Как загрузить файл 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:

Образцы находятся по адресу:

Файл

{
    "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
}
Другие вопросы по тегам