如何将 JSON 文件加载到在 Java 中运行的 Saxon 中的 DOM? [英] How do I load a JSON file into the DOM in Saxon running in Java?

查看:34
本文介绍了如何将 JSON 文件加载到在 Java 中运行的 Saxon 中的 DOM?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的 Java 代码中,我试图创建一个 Saxon 文档 (DOM),它是 JSON 文件的内容.这应该有可能,但我的代码失败了.

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.

完整代码位于 SaxonQuestions.zip、TestLoadJson.java 也列在下面.在这段代码中,evaluate() 失败了.

The full code for this is at SaxonQuestions.zip, TestLoadJson.java and is also listed below. In this code the evaluate() fails.

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);
    }
}

推荐答案

如果你有一个带有 JSON 的 Java String 将它作为变量传递给 XPath 并调用 parse-json:

If you have a Java String with JSON pass it in as a variable to XPath and call parse-json on the variable:

    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/#func-json-doc) 在变量:

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:

    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 计算.

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.

所以让我们假设你有 employees.json 包含

So lets assume you have employees.json containing

{ 
    "employees": [ 
        { 
          "name": "mike",
          "department": "accounting",
          "age": 34 
        },
        { 
          "name": "sally",
          "department": "sales",
          "age": 24
        }
      ]
}

然后您可以使用第二个样本将其解析为 XdmValue 值,并将其进一步用作表达式的上下文项,例如

then 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

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 每个数组项的值:

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 the Students 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 the Grade value of each array item:

avg(?Students?*!(?Grade, 70)[1])

但附加要求为那些没有 Grade 的对象/地图选择默认值 70.示例 JSON 是

but with the additional requirement to select a default of 70 for those objects/maps that don't have a Grade. The sample JSON is

{
  "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 项,作为进一步评估的上下文项.

The 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.

为了给出一些针对 JSON 的更复杂的 XPath 3.1 表达式的示例,我从 https://github.com/json-path/JsonPath 作为 parse-json 的 JSON 输入(如果您有字符串)或 json-doc 如果您有文件的 URI 甚至 HTTP(S) 位置并将其用作某些路径的上下文项(在小提琴中评估为 XQuery 3.1 但 XPath 3.1 是一个子集,我想我已经限制了示例到 XPath 3.1:

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) or json-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:

样品位于:

  • https://xqueryfiddle.liberty-development.net/gWmuPs6/0 : ?store?book?*?author : "the authors of all books"
  • https://xqueryfiddle.liberty-development.net/gWmuPs6/1 : ?store?* : "all things in the store, both books and bicycles"
  • https://xqueryfiddle.liberty-development.net/gWmuPs6/2 : ?store?book?3 : "the third book"
  • https://xqueryfiddle.liberty-development.net/gWmuPs6/3 : ?store?book?(1,2) : "the first two books"
  • https://xqueryfiddle.liberty-development.net/gWmuPs6/4 : ?store?book?*[?isbn] : "all books with an isbn number"
  • https://xqueryfiddle.liberty-development.net/gWmuPs6/5 : ?store?book?*[?price < 10] : "all books with a price less than 10"
  • https://xqueryfiddle.liberty-development.net/gWmuPs6/6 : let $context := . return ?store?book?*[?price <= $context?expensive] : "all books with a price less than expensive"
  • https://xqueryfiddle.liberty-development.net/gWmuPs6/7 : count(?store?book?*) : "the number of books"

文件是

{
    "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
}

这篇关于如何将 JSON 文件加载到在 Java 中运行的 Saxon 中的 DOM?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆