Reputation: 1735
I have an XQuery that converts Json to Json. I made a demo version that works on the command line and I want to use it in java.
The issue is that I don't know how to set parameters in the XQuery.
My source file "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"
}
]
}
The XQuery that I want to use "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"
}
}
Command line:
java -cp saxon9he.jar net.sf.saxon.Query -t -q:test\Query.xq >test\Test.json
In Java, I wrote the following (not working! => I get a SXXP0003: Error reported by XML parser: Content is not allowed in prolog.):
@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);
}
My Question: How should I change my "XQuery.xq" and my Java code so I can use multiple input files. e.g. "2.json",...
Upvotes: 2
Views: 1005
Reputation: 163625
Well firstly, there aren't any external variables in this query, which makes the question title rather confusing. An external variable would be declared like this:
declare variable $param as xs:string external;
The error you are getting is because you are supplying a JSON file as the input to a SAXSource. SAX is for reading XML files, and the error from the XML parser (SXXP0003) is because XML parsers can't read JSON files.
If you want to parameterize the query with the filename of the JSON file to be read, I would do:
declare variable $jsonFile as xs:string external;
let $j := json-doc($jsonFile)...
and then supply the filename using
QName qName = new QName("jsonFile");
evaluator.setExternalVariable(qName, "src/test/resources/1.json");
The only remaining question is about resolution of relative file names. The way I have done it here, the file name "src/test/resources..." will be interpreted as relative to the location (static base URI) of the query, which in your case is unknown, because you are supplying the query as an anonymous InputStream
. You can set a base URI for the query using XQueryCompiler.setBaseURI(), or you could resolve the filename in your Java code and supply an absolute URI for the JSON input.
Upvotes: 3