在 Saxon 中使用外部变量
Use external variables in Saxon
我有一个将 Json 转换为 Json 的 XQuery。
我制作了一个可在命令行上运行的演示版本,我想在 java.
中使用它
问题是我不知道如何在 XQuery 中设置参数。
我的源文件“1.json”:
{
"FirstName": "Fred",
"Surname": "Smith",
"Age": 28,
"Phone": [{
"type": "home",
"number": "0203 544 1234"
}, {
"type": "office",
"number": "01962 001234"
}, {
"type": "office",
"number": "01962 001235"
}, {
"type": "mobile",
"number": "077 7700 1234"
}
]
}
我要使用的 XQuery "XQuery.xq":
xquery version "3.1";
declare namespace array = "http://www.w3.org/2005/xpath-functions/array";
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "json";
let $j := json-doc( 'src/test/resources/1.json' )
where ("Fred" = $j?FirstName or 30 != $j?Age) (:predicate on the highest level:)
return array {
for $i in (1 to $j?Phone => array:size()) (:predicate on the next level:)
let $e := $j?Phone($i)
where ($e?type = "home" or fn:matches($e?type, "^mob.*$")) (:implementing like using regular expressions % => .*, ? => . , ^/$ Start/End of line :)
return map {
"Name (First)": data($j?FirstName),
"Name (Last)": data($j?Surname),
"age": data($j?Age),
"Phone": data($e?number),
"ConstantValue": "TEST"
}
}
命令行:
java -cp saxon9he.jar net.sf.saxon.Query -t -q:test\Query.xq >test\Test.json
在 Java 中,我写了以下内容(不起作用!=> 我收到 SXXP0003:XML 解析器报告错误:序言中不允许内容。):
@Test
public void test_XQuery() throws Exception {
runXQuery("/1.json", "/XQuery.xq", "/1_Output.json");
}
private void runXQuery(String datafile, String xQueryFile, String expectedOutput) throws Exception {
InputStream dataStream = getClass().getResourceAsStream(datafile);
InputStream xQueryStream = getClass().getResourceAsStream(xQueryFile);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
run(dataStream, xQueryStream, outputStream);
String json = outputStream.toString();
String expected = StreamUtils.copyToString(getClass().getResourceAsStream(expectedOutput), Charset.defaultCharset());
assertEquals(expected, json);
}
private static void run(InputStream input, InputStream query, OutputStream output) throws SaxonApiException {
Configuration config = Configuration.newConfiguration();
Processor processor = new Processor(config);
XQueryCompiler compiler = processor.newXQueryCompiler();
XQueryExecutable executor = compiler.compile(query);
XQueryEvaluator evaluator = executor.load();
Source sourceInput = new SAXSource(new InputSource(input));
DocumentBuilder builder = processor.newDocumentBuilder();
XdmNode doc = builder.build(sourceInput);
evaluator.setContextItem(doc);
// QName qName = new QName("input");
// evaluator.setExternalVariable(qName, doc);
Serializer out = processor.newSerializer(output);
out.setOutputProperty(Serializer.Property.METHOD, "json");
evaluator.run(out);
}
我的问题:我应该如何更改我的 "XQuery.xq" 和我的 Java 代码以便我可以使用多个输入文件。例如"2.json",...
首先,这个查询中没有任何外部变量,这使得问题标题相当混乱。外部变量将像这样声明:
declare variable $param as xs:string external;
您收到的错误是因为您提供了一个 JSON 文件作为 SAXSource 的输入。 SAX 用于读取 XML 个文件,XML 解析器 (SXXP0003) 的错误是因为 XML 个解析器无法读取 JSON 个文件。
如果您想使用要读取的 JSON 文件的文件名来参数化查询,我会这样做:
declare variable $jsonFile as xs:string external;
let $j := json-doc($jsonFile)...
然后使用
提供文件名
QName qName = new QName("jsonFile");
evaluator.setExternalVariable(qName, "src/test/resources/1.json");
剩下的唯一问题是关于相对文件名的解析。我在这里完成的方式,文件名 "src/test/resources..." 将被解释为相对于查询的位置(静态基本 URI),在您的情况下这是未知的,因为您将查询作为匿名 InputStream
。您可以使用 XQueryCompiler.setBaseURI() 为查询设置一个基本 URI,或者您可以解析 Java 代码中的文件名并为 JSON 输入提供一个绝对 URI。
我有一个将 Json 转换为 Json 的 XQuery。 我制作了一个可在命令行上运行的演示版本,我想在 java.
中使用它问题是我不知道如何在 XQuery 中设置参数。
我的源文件“1.json”:
{
"FirstName": "Fred",
"Surname": "Smith",
"Age": 28,
"Phone": [{
"type": "home",
"number": "0203 544 1234"
}, {
"type": "office",
"number": "01962 001234"
}, {
"type": "office",
"number": "01962 001235"
}, {
"type": "mobile",
"number": "077 7700 1234"
}
]
}
我要使用的 XQuery "XQuery.xq":
xquery version "3.1";
declare namespace array = "http://www.w3.org/2005/xpath-functions/array";
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "json";
let $j := json-doc( 'src/test/resources/1.json' )
where ("Fred" = $j?FirstName or 30 != $j?Age) (:predicate on the highest level:)
return array {
for $i in (1 to $j?Phone => array:size()) (:predicate on the next level:)
let $e := $j?Phone($i)
where ($e?type = "home" or fn:matches($e?type, "^mob.*$")) (:implementing like using regular expressions % => .*, ? => . , ^/$ Start/End of line :)
return map {
"Name (First)": data($j?FirstName),
"Name (Last)": data($j?Surname),
"age": data($j?Age),
"Phone": data($e?number),
"ConstantValue": "TEST"
}
}
命令行:
java -cp saxon9he.jar net.sf.saxon.Query -t -q:test\Query.xq >test\Test.json
在 Java 中,我写了以下内容(不起作用!=> 我收到 SXXP0003:XML 解析器报告错误:序言中不允许内容。):
@Test
public void test_XQuery() throws Exception {
runXQuery("/1.json", "/XQuery.xq", "/1_Output.json");
}
private void runXQuery(String datafile, String xQueryFile, String expectedOutput) throws Exception {
InputStream dataStream = getClass().getResourceAsStream(datafile);
InputStream xQueryStream = getClass().getResourceAsStream(xQueryFile);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
run(dataStream, xQueryStream, outputStream);
String json = outputStream.toString();
String expected = StreamUtils.copyToString(getClass().getResourceAsStream(expectedOutput), Charset.defaultCharset());
assertEquals(expected, json);
}
private static void run(InputStream input, InputStream query, OutputStream output) throws SaxonApiException {
Configuration config = Configuration.newConfiguration();
Processor processor = new Processor(config);
XQueryCompiler compiler = processor.newXQueryCompiler();
XQueryExecutable executor = compiler.compile(query);
XQueryEvaluator evaluator = executor.load();
Source sourceInput = new SAXSource(new InputSource(input));
DocumentBuilder builder = processor.newDocumentBuilder();
XdmNode doc = builder.build(sourceInput);
evaluator.setContextItem(doc);
// QName qName = new QName("input");
// evaluator.setExternalVariable(qName, doc);
Serializer out = processor.newSerializer(output);
out.setOutputProperty(Serializer.Property.METHOD, "json");
evaluator.run(out);
}
我的问题:我应该如何更改我的 "XQuery.xq" 和我的 Java 代码以便我可以使用多个输入文件。例如"2.json",...
首先,这个查询中没有任何外部变量,这使得问题标题相当混乱。外部变量将像这样声明:
declare variable $param as xs:string external;
您收到的错误是因为您提供了一个 JSON 文件作为 SAXSource 的输入。 SAX 用于读取 XML 个文件,XML 解析器 (SXXP0003) 的错误是因为 XML 个解析器无法读取 JSON 个文件。
如果您想使用要读取的 JSON 文件的文件名来参数化查询,我会这样做:
declare variable $jsonFile as xs:string external;
let $j := json-doc($jsonFile)...
然后使用
提供文件名QName qName = new QName("jsonFile");
evaluator.setExternalVariable(qName, "src/test/resources/1.json");
剩下的唯一问题是关于相对文件名的解析。我在这里完成的方式,文件名 "src/test/resources..." 将被解释为相对于查询的位置(静态基本 URI),在您的情况下这是未知的,因为您将查询作为匿名 InputStream
。您可以使用 XQueryCompiler.setBaseURI() 为查询设置一个基本 URI,或者您可以解析 Java 代码中的文件名并为 JSON 输入提供一个绝对 URI。