Как загрузить файл JSON в DOM в Saxon, работающем на Java?
В моем коде Java я пытаюсь создать саксонский документ (DOM), который является содержимым файла JSON. Это должно быть возможно, но код, который у меня есть, не работает.
Полный код для этого находится в SaxonQuestions.zip, TestLoadJson.java и также указан ниже. В этом коде оценка () не выполняется.
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);
}
}
1 ответ
Если у вас есть Java String
с JSON передайте его как переменную в XPath и вызовите parse-json
по переменной:
Processor processor = new Processor(true);
String[] jsonExamples = { "1", "true", "null", "\"string\"", "[1,2,3]", "{ \"prop\" : \"value\" }" };
XPathCompiler compiler = processor.newXPathCompiler();
compiler.declareVariable(new QName("json"));
XPathExecutable executable = compiler.compile("parse-json($json)");
XPathSelector selector = executable.load();
for (String json : jsonExamples) {
selector.setVariable(new QName("json"), new XdmAtomicValue(json));
XdmValue value = selector.evaluate();
System.out.println(value);
}
Если у вас есть файл с JSON, передайте его имя файла или вообще URI в качестве переменной в XPath и вызовите json-doc
( https://www.w3.org/TR/xpath-functions/) для переменной:
compiler = processor.newXPathCompiler();
compiler.declareVariable(new QName("json-uri"));
executable = compiler.compile("json-doc($json-uri)");
selector = executable.load();
selector.setVariable(new QName("json-uri"), new XdmAtomicValue("example1.json")); // pass in a relative (e.g. 'example.json' or 'subdir/example.json') or an absolute URI (e.g. 'file:///C:/dir/subdir/example.json' or 'http://example.com/example.json') here, not an OS specific file path
XdmValue value = selector.evaluate();
System.out.println(value);
Конечно, вы можете разделить шаги и проанализировать строку в XdmValue или файл в XdmValue, а затем передать его позже как переменную в другую оценку XPath.
Итак, допустим, у вас есть employees.json
содержащий
{
"employees": [
{
"name": "mike",
"department": "accounting",
"age": 34
},
{
"name": "sally",
"department": "sales",
"age": 24
}
]
}
затем вы можете проанализировать его со вторым образцом в значение XdmValue и использовать его в дальнейшем как элемент контекста для выражения, например
avg(?employees?*?age)
вычислил бы средний возраст:
Processor processor = new Processor(true);
XPathCompiler compiler = processor.newXPathCompiler();
compiler.declareVariable(new QName("json-uri"));
XPathExecutable executable = compiler.compile("json-doc($json-uri)");
XPathSelector selector = executable.load();
selector.setVariable(new QName("json-uri"), new XdmAtomicValue("employees.json"));
XdmValue value = selector.evaluate();
System.out.println(value);
executable = compiler.compile("avg(?employees?*?age)");
selector = executable.load();
selector.setContextItem((XdmItem) value);
XdmItem result = selector.evaluateSingle();
System.out.println(result);
На https://xqueryfiddle.liberty-development.net/94hwphZ меня есть другой пример обработки JSON, он также вычисляет среднее значение с выражением с использованием оператора поиска?
, сначала с ?Students
выбрать Students
элемент контекстной карты, затем со звездочкой ?*
в возвращенном массиве, чтобы получить последовательность всех элементов массива, наконец, с ?Grade
выбрать Grade
значение каждого элемента массива:
avg(?Students?*!(?Grade, 70)[1])
но с дополнительным требованием выбрать значение по умолчанию 70
для тех объектов / карт, у которых нет Grade
. Пример JSON
{
"Class Name": "Science",
"Teacher\u0027s Name": "Jane",
"Semester": "2019-01-01",
"Students": [
{
"Name": "John",
"Grade": 94.3
},
{
"Name": "James",
"Grade": 81.0
},
{
"Name": "Julia",
"Grade": 91.9
},
{
"Name": "Jessica",
"Grade": 72.4
},
{
"Name": "Johnathan"
}
],
"Final": true
}
Скрипка поддерживает XQuery 3.1, но, как и для XPath 3.1, JSON передается как переменная, а затем анализируется с помощью parse-json
в элемент XDM, чтобы служить элементом контекста для дальнейшей оценки.
Чтобы привести несколько примеров более сложных выражений XPath 3.1 для JSON, я взял образец JSON из примеров путей в https://github.com/json-path/JsonPath в качестве входных данных JSON дляparse-json
(если у вас есть строка) или json-doc
если у вас есть URI для файла или даже для местоположения HTTP(S) и вы использовали его в качестве элемента контекста для некоторых путей (оценивается в скрипте как XQuery 3.1, но XPath 3.1 является подмножеством, и я думаю, что ограничил образцы XPath 3.1:
Образцы находятся по адресу:
- https://xqueryfiddle.liberty-development.net/gWmuPs6/0:
?store?book?*?author
: "авторы всех книг" - https://xqueryfiddle.liberty-development.net/gWmuPs6/1:
?store?*
: "все, что есть в магазине, и книги, и велосипеды" - https://xqueryfiddle.liberty-development.net/gWmuPs6/2:
?store?book?3
: "третья книга" - https://xqueryfiddle.liberty-development.net/gWmuPs6/3:
?store?book?(1,2)
: "первые две книги" - https://xqueryfiddle.liberty-development.net/gWmuPs6/4:
?store?book?*[?isbn]
: "все книги с номером isbn" - https://xqueryfiddle.liberty-development.net/gWmuPs6/5:
?store?book?*[?price < 10]
: "все книги по цене менее 10" - https://xqueryfiddle.liberty-development.net/gWmuPs6/6:
let $context := . return ?store?book?*[?price <= $context?expensive]
: "все книги по цене ниже дорогой" - https://xqueryfiddle.liberty-development.net/gWmuPs6/7:
count(?store?book?*)
: "количество книг"
Файл
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}