如何在 Saxon 的 XQuery 中动态引用 XML 文件
Posted
技术标签:
【中文标题】如何在 Saxon 的 XQuery 中动态引用 XML 文件【英文标题】:Howto refer dynamically to an XML file in XQuery in Saxon 【发布时间】:2015-08-05 13:45:51 【问题描述】:我正在使用 XQuery 处理器 Saxon。 现在我们将 XQuery 写入一个“.xqy”文件中,我们将在其中引用我们将在其上执行 XQuery 的 XML 文件。 请看下面的例子:
for $x in doc("books.xml")/books/book
where $x/price>30
return $x/title
现在我想使用未存储在某些路径中的动态生成的 XML。比如说,我想在下面引用可作为字符串使用的 XML。
如何做到这一点?
String book=
<books>
<book category="JAVA">
<title lang="en">Learn Java in 24 Hours</title>
<author>Robert</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="DOTNET">
<title lang="en">Learn .Net in 24 hours</title>
<author>Peter</author>
<year>2011</year>
<price>40.50</price>
</book>
<book category="XML">
<title lang="en">Learn XQuery in 24 hours</title>
<author>Robert</author>
<author>Peter</author>
<year>2013</year>
<price>50.00</price>
</book>
<book category="XML">
<title lang="en">Learn XPath in 24 hours</title>
<author>Jay Ban</author>
<year>2010</year>
<price>16.50</price>
</book>
</books>
Java 代码:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import javax.xml.xquery.XQConnection;
import javax.xml.xquery.XQDataSource;
import javax.xml.xquery.XQException;
import javax.xml.xquery.XQPreparedExpression;
import javax.xml.xquery.XQResultSequence;
import com.saxonica.xqj.SaxonXQDataSource;
public class XQueryTester
public static void main(String[] args)
try
execute();
catch (FileNotFoundException e)
e.printStackTrace();
catch (XQException e)
e.printStackTrace();
private static void execute() throws FileNotFoundException, XQException
InputStream inputStream = new FileInputStream(new File("books.xqy"));
XQDataSource ds = new SaxonXQDataSource();
XQConnection conn = ds.getConnection();
XQPreparedExpression exp = conn.prepareExpression(inputStream);
XQResultSequence result = exp.executeQuery();
while (result.next())
System.out.println(result.getItemAsString(null));
【问题讨论】:
您可以将字符串作为参数传递并在XQuery 代码中使用parse-xml($param)
对其进行解析,或者您可以在Java 中解析XML 并将其作为参数传递给您的XQuery 代码。您能向我们展示您使用 Saxon 的 Java 代码吗?您使用 Saxon 的哪些 API?
@MartinHonnen 感谢您的评论。我已添加 java 代码,请参见上文。
【参考方案1】:
如果您正在寻找一种使用 Java 绑定查询的输入(上下文项)的方法,我建议使用 Saxon 的 S9API(Java 中用于 XSLT、XPath 和 XQuery 处理的最直观的 API )。
下面是如何实例化 Saxon、编译查询、解析输入并使用绑定的输入文档作为其上下文项来评估查询:
// the Saxon processor object
Processor saxon = new Processor(false);
// compile the query
XQueryCompiler compiler = saxon.newXQueryCompiler();
XQueryExecutable exec = compiler.compile(new File("yours.xqy"));
// parse the string as a document node
DocumentBuilder builder = saxon.newDocumentBuilder();
String input = "<xml>...</xml>";
Source src = new StreamSource(new StringReader(input));
XdmNode doc = builder.build(src);
// instantiate the query, bind the input and evaluate
XQueryEvaluator query = exec.load();
query.setContextItem(doc);
XdmValue result = query.evaluate();
请注意,如果 Java 代码正在生成 XML 文档,我强烈建议您使用 S9API 直接在内存中构建树,而不是将 XML 文档生成为字符串,然后对其进行解析。如果可能的话。
【讨论】:
XQuery 带有命名空间 [使用 s9api 进行 XQuery] (saxonica.com/documentation9.5/index.html#!using-xquery/…)compiler.declareNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");compiler.compile("for $x in /soap:Envelope return $x/soap:Body");
[Saxon-HE-*.jar](mvnrepository.com/artifact/net.sf.saxon/Saxon-HE)
在内存中构建树是什么意思?
XML 是一棵节点树(元素、属性、文本...) 将一些 XML 解析为字符串就是在内存中构建相应的树。但是您也可以使用 S9API 直接在内存中构建树,而无需通过生成字符串然后解析它的步骤(通过使用“创建元素”、“添加文本”、“创建属性”等函数代替) 【参考方案2】:
这是我按照上述用户的建议实现的方式-
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.xquery.XQConnection;
import javax.xml.xquery.XQDataSource;
import javax.xml.xquery.XQException;
import javax.xml.xquery.XQPreparedExpression;
import javax.xml.xquery.XQResultSequence;
import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XQueryCompiler;
import net.sf.saxon.s9api.XQueryEvaluator;
import net.sf.saxon.s9api.XQueryExecutable;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XdmValue;
import com.saxonica.xqj.SaxonXQDataSource;
public class Xml public static void main(String[] args)
try
process();
catch (FileNotFoundException e)
e.printStackTrace();
catch (Exception e)
e.printStackTrace();
public static void process() throws SaxonApiException, IOException
// the Saxon processor object
Processor saxon = new Processor(false);
// compile the query
XQueryCompiler compiler = saxon.newXQueryCompiler();
XQueryExecutable exec;
exec = compiler.compile(new File("E:\\abc.xqy"));
// parse the string as a document node
DocumentBuilder builder = saxon.newDocumentBuilder();
String input = "<data><employee id=\"1\"><name>A</name>"
+ "<title>Manager</title></employee>+<employee id=\"2\"><name>B</name>"
+ "<title>Manager</title></employee>+</data>";
Source src = new StreamSource(new StringReader(input));
XdmNode doc = builder.build(src);
// instantiate the query, bind the input and evaluate
XQueryEvaluator query = exec.load();
query.setContextItem(doc);
XdmValue result = query.evaluate();
System.out.println(result.itemAt(0));
【讨论】:
我不确定你是如何真正创建input
,但我建议你看看DocumentBuilder.newBuildingStreamWriter,以了解一种直接以编程方式构造树的方法,而不是生成一个字符串已解析。
@FlorentGeorges 但为什么我需要锁定?我从 web 服务获取这个 xml 数据,然后我从中读取一些特定元素。在这种情况下我需要锁定吗?
嗯,不知道你所说的“lock”是什么意思。如果您将文档作为字符串检索,那么是的,您必须解析它。但这从您的问题中并不清楚,如果您自己构建字符串(例如使用 concats 和其他东西),那么通常这是一个坏主意。
@FlorentGeorges 你在上面的评论中建议我看看 DocumentBuilder.newBuildingStreamWriter,我在说同样的事情。在这种情况下我需要吗,这里我从 web 服务获取 xml。以上是关于如何在 Saxon 的 XQuery 中动态引用 XML 文件的主要内容,如果未能解决你的问题,请参考以下文章
如何编写可以测试正在使用的 XQuery 版本的 XQuery?
从 Saxon 9.4he 中的嵌入式资源加载 xml 和 xslt