如何使用saxon将输入外部绑定到xquery?

时间:2015-05-15 09:24:26

标签: java xquery saxon

我必须使用saxon HE在xquery中调用外部java方法。我可以使用以下代码调用方法。但问题是我想在外部绑定我的输入。

final Configuration config = new Configuration();
config.registerExtensionFunction(new ShiftLeft());
final StaticQueryContext sqc = new StaticQueryContext(config);
final XQueryExpression exp = sqc.compileQuery(new FileReader(
"input/names.xq"));

final DynamicQueryContext dynamicContext = new DynamicQueryContext(config);

 String xml = "<student_list><student><name>George Washington</name><major>Politics</major><phone>312-123-4567</phone><email>gw@example.edu</email></student><student><name>Janet Jones</name><major>Undeclared</major><phone>311-122-2233</phone><email>janetj@example.edu</email></student><student><name>Joe Taylor</name><major>Engineering</major><phone>211-111-2333</phone><email>joe@example.edu</email></student></student_list>";
DocumentBuilderFactory newInstance = DocumentBuilderFactory.newInstance();
newInstance.setNamespaceAware(true);
Document parse = newInstance.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
DocumentWrapper sequence = new DocumentWrapper(parse, "", config);
StructuredQName qname = new StructuredQName("", "", "student_list");
dynamicContext.setParameter(qname, sequence);

Properties props = new Properties();
final SequenceIterator iter = exp.iterator(dynamicContext);
props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
props.setProperty(OutputKeys.INDENT, "yes");

StringWriter writer = new StringWriter();
QueryResult.serializeSequence(iter, config, writer, props);
System.out.println("Result is " + writer);

names.xq

declare namespace eg="http://example.com/saxon-extension";
declare namespace xs = "http://www.w3.org/2001/XMLSchema";
declare variable $student_list as element(*) external;

<Students>  
<value> {
let $n := eg:shift-left(2, 2)
return $n
}</value>
<student_names>
{ $student_list//student_list/student/name }
</student_names>
</Students>

但是得到以下错误

Error at procedure student_list on line 3 of students.xml:
XPTY0004: Required item type of value of variable $student_list is element(); supplied
value has item type document-node(element(Q{}student_list))
net.sf.saxon.trans.XPathException: Required item type of value of variable $student_list is element(); supplied value has item type document-     node(element(Q{}student_list))
at      net.sf.saxon.expr.ItemTypeCheckingFunction.testConformance(ItemTypeCheckingFunction.java:69)
at net.sf.saxon.expr.ItemTypeCheckingFunction.mapItem(ItemTypeCheckingFunction.java:50)
at net.sf.saxon.expr.ItemMappingIterator.next(ItemMappingIterator.java:95)
at net.sf.saxon.expr.CardinalityCheckingIterator.<init>(CardinalityCheckingIterator.java:52)
at net.sf.saxon.type.TypeHierarchy.applyFunctionConversionRules(TypeHierarchy.java:230)
at net.sf.saxon.expr.instruct.GlobalParameterSet.convertParameterValue(GlobalParameterSet.java:105)
at net.sf.saxon.expr.instruct.Bindery.useGlobalParameter(Bindery.java:136)
at net.sf.saxon.expr.instruct.GlobalParam.evaluateVariable(GlobalParam.java:62)
at net.sf.saxon.expr.GlobalVariableReference.evaluateVariable(GlobalVariableReference.java:105)
at net.sf.saxon.expr.VariableReference.evaluateItem(VariableReference.java:460)
at net.sf.saxon.expr.Atomizer.evaluateItem(Atomizer.java:313)
at net.sf.saxon.expr.Atomizer.evaluateItem(Atomizer.java:35)
at net.sf.saxon.expr.AtomicSequenceConverter.evaluateItem(AtomicSequenceConverter.java:275)
at net.sf.saxon.expr.AtomicSequenceConverter.evaluateItem(AtomicSequenceConverter.java:30)
at net.sf.saxon.functions.Doc.doc(Doc.java:235)
at net.sf.saxon.functions.Doc.evaluateItem(Doc.java:190)
at net.sf.saxon.functions.Doc.evaluateItem(Doc.java:28)
at net.sf.saxon.expr.SimpleStepExpression.iterate(SimpleStepExpression.java:85)
at net.sf.saxon.expr.SlashExpression.iterate(SlashExpression.java:842)
at net.sf.saxon.expr.sort.DocumentSorter.iterate(DocumentSorter.java:168)
at net.sf.saxon.expr.SlashExpression.iterate(SlashExpression.java:842)
at net.sf.saxon.expr.sort.DocumentSorter.iterate(DocumentSorter.java:168)
at net.sf.saxon.expr.Expression.process(Expression.java:552)
at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:450)
at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:389)
at net.sf.saxon.expr.instruct.Block.processLeavingTail(Block.java:669)
at net.sf.saxon.expr.instruct.Instruction.process(Instruction.java:144)
at net.sf.saxon.expr.instruct.ElementCreator.constructElement(ElementCreator.java:539)
at net.sf.saxon.expr.instruct.ElementCreator.evaluateItem(ElementCreator.java:476)
at net.sf.saxon.expr.instruct.Instruction.iterate(Instruction.java:363)
at net.sf.saxon.query.XQueryExpression.iterator(XQueryExpression.java:332)
at com.example.saxon.ExternalMethodCaller.main(ExternalMethodCaller.java:77)

提前致谢..

1 个答案:

答案 0 :(得分:1)

除非你有充分的理由不这样做,否则我的建议是使用Snappi(Saxon 9 API或s9api):

Processor saxon = new Processor(false);
saxon.registerExtensionFunction(new MyExtension());

XQueryCompiler compiler = saxon.newXQueryCompiler();
XQueryExecutable exec = compiler.compile(new File("input/names.xq"));
XQueryEvaluator query = exec.load();

DocumentBuilder builder = saxon.newDocumentBuilder();
String students = "<xml>...</xml>";
Source src = new StreamSource(new StringReader(students));
XdmNode doc = builder.build(src);
query.setExternalVariable(new QName("student_list"), doc);

XdmValue result = query.evaluate();

MyExtension看起来如下所示:

public class MyExtension
        implements ExtensionFunction
{
    @Override
    public QName getName()
    {
        return new QName("http://example.org/my-project", "my-fun");
    }

    @Override
    public SequenceType getResultType()
    {
        return SequenceType.makeSequenceType(
                ItemType.INTEGER, OccurrenceIndicator.ONE);
    }

    @Override
    public SequenceType[] getArgumentTypes()
    {
        return new SequenceType[] {
            SequenceType.makeSequenceType(
                    ItemType.INTEGER, OccurrenceIndicator.ONE),
            SequenceType.makeSequenceType(
                    ItemType.INTEGER, OccurrenceIndicator.ONE)
        };
    }

    @Override
    public XdmValue call(XdmValue[] args) throws SaxonApiException
    {
        long first  = ((XdmAtomicValue)args[0].itemAt(0)).getLongValue();
        long second = ((XdmAtomicValue)args[0].itemAt(0)).getLongValue();
        long result = ...;
        return new XdmAtomicValue(result);
    }
}

有关详细信息,请参阅http://www.saxonica.com/documentation9.5/extensibility/integratedfunctions/ext-simple-J.html上的文档。

EXPath还有一个名为tools-saxon的项目,其中包含几个在Java中使用Saxon的工具。包括扩展功能。它介绍了函数库的概念,如果你有几个扩展函数,它很方便。它还引入了一个函数定义构建器,允许用尽可能少的样板代码构建函数定义(并为类型序列提供方便的快捷方式)。在上面的代码中,将函数注册(前2行)替换为:

Processor saxon = new Processor(false);
Library lib = new MyLibrary();
lib.register(saxon.getUnderlyingConfiguration());

并将扩展类替换为以下2个类(库和函数,分别为:)

public class MyLibrary
        extends Library
{
    public MyLibrary()
    {
        super("http://example.org/my-project", "my");
    }

    @Override
    protected Function[] functions()
    {
        return new Function[] {
            new MyFunction(this)
        };
    }

}

public class MyFunction
        extends Function
{
    public MyFunction(Library lib)
    {
        super(lib);
    }

    @Override
    protected Definition makeDefinition()
    {
        return library()
                .function(this, "my-fun")
                .returns(Types.SINGLE_INTEGER)
                .param(Types.SINGLE_INTEGER, "first")
                .param(Types.SINGLE_INTEGER, "second")
                .make();
    }

    @Override
    public Sequence call(XPathContext ctxt, Sequence[] args)
            throws XPathException
    {
        Parameters params = checkParams(args);
        long first  = params.asLong(0, true);
        long second = params.asLong(1, true);
        long result = 0;
        return Return.value(result);
    }
}

https://github.com/expath/tools-saxon上查看Github上项目主页的所有信息。

注意:未经测试。