In my Java code I am trying to create a Saxon document (DOM) that is the contents of a JSON file. This should be possible but the code I have fails.
The full code for this is at SaxonQuestions.zip, TestLoadJson.java and is also listed below. In this code the evaluate() fails.
TestLoadJson.java
import net.sf.saxon.Configuration;
import net.sf.saxon.s9api.*;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import javax.xml.transform.sax.SAXSource;
import java.io.*;
import java.nio.charset.Charset;
public class TestLoadJson {
public static void main(String[] args) throws Exception {
// get the file
File jsonFile = new File("files", "SouthWind.json");
Charset inputCharset = Charset.forName("UTF-8");
FileInputStream fis = new FileInputStream(jsonFile);
InputStreamReader isr = new InputStreamReader(fis, inputCharset);
BufferedReader br = new BufferedReader(isr);
String str;
StringBuilder buf = new StringBuilder();
while ((str = br.readLine()) != null)
buf.append(str).append('\n');
br.close();
isr.close();
fis.close();
// set up the compiler
Configuration config = XmlDatasource.createEnterpriseConfiguration();
Processor processor = new Processor(config);
XPathCompiler xPathCompiler = processor.newXPathCompiler();
// need an XML document
DocumentBuilder doc_builder = processor.newDocumentBuilder();
XMLReader reader = XmlDatasource.createXMLReader();
InputSource xmlSource = new InputSource(new ByteArrayInputStream("<root/>".getBytes()));
SAXSource saxSource = new SAXSource(reader, xmlSource);
XdmNode xmlRootNode = doc_builder.build(saxSource);
// give it the JSON
buf.insert(0, "parse-json(");
buf.append(")");
Object json = xPathCompiler.evaluate(buf.toString(), xmlRootNode);
System.out.println("JSON read in!!! json = " + json);
}
}
If you have a Java
String
with JSON pass it in as a variable to XPath and callparse-json
on the variable:If you have a file with JSON pass its file name or in general URI as a variable to XPath and call
json-doc
(https://www.w3.org/TR/xpath-functions/#func-json-doc) on the variable:Of course you can separate the steps and parse a string to an XdmValue or a file to an XdmValue and then pass it in later as a variable to another XPath evaluation.
So lets assume you have
employees.json
containingthen you can parse it with the second sample into an XdmValue value and use that further as a context item for an expression e.g
would compute the average age:
At https://xqueryfiddle.liberty-development.net/94hwphZ I have another sample processing JSON, it also computes the average of a value with an expression using the lookup operator
?
, first with?Students
to select theStudents
item of the context map, then with an asterisk?*
on the returned array to get a sequence of all array items, finally with?Grade
to select theGrade
value of each array item:but with the additional requirement to select a default of
70
for those objects/maps that don't have aGrade
. The sample JSON isThe fiddle supports XQuery 3.1 but like for XPath 3.1 the JSON is passed in as a variable and then parsed with
parse-json
into an XDM item to serve as the context item for further evaluation.To give some examples of more complex XPath 3.1 expressions against JSON I have taken the JSON sample from the path examples in https://github.com/json-path/JsonPath as the JSON input to
parse-json
(if you have a string) orjson-doc
if you have a URI to a file or even a HTTP(S) location and used it as the context item for some paths (evaluated in the fiddle as XQuery 3.1 but XPath 3.1 is a subset and I think I have restricted the samples to XPath 3.1:The samples are at:
?store?book?*?author
: "the authors of all books"?store?*
: "all things in the store, both books and bicycles"?store?book?3
: "the third book"?store?book?(1,2)
: "the first two books"?store?book?*[?isbn]
: "all books with an isbn number"?store?book?*[?price < 10]
: "all books with a price less than 10"let $context := . return ?store?book?*[?price <= $context?expensive]
: "all books with a price less than expensive"count(?store?book?*)
: "the number of books"The file is