控制 JsonPath 的 read() 方法返回的数据类型

Controlling the type of data returned by JsonPath's read() method

我希望 JsonPath 始终 return 将其解析为字符串的数据。然而,JsonPath的read()方法的return类型根据被解析数据的类型不同而不同,因为JsonPath总是猜测数据类型是什么以及return的结果那种。

问题是我无法知道哪种数据将被 returned,因为我只能访问一组我需要输入到 read() 函数中的路径.这意味着我必须将 returned JsonPath 数据存储在对象数组中,并使用包含 instanceof 关键字的非常丑陋的 if/else-if 语句集合来确定数据是什么(然后将其转换为适当的类型)。

有谁知道强制 JsonPath return 字符串的方法吗?或者其他人可以想到更好的解决方法吗?

这是我现在正在做的事情(Java):

ArrayList<Object> realData = JsonPath.read(dataDumpFile, current.getPath());

我想做什么:

ArrayList<String> realData = JsonPath.read(dataDumpFile, current.getPath());

docs 我发现了这个:

When using JsonPath in java its important to know what type you expect in your result. JsonPath will automatically try to cast the result to the type expected by the invoker.

//Will throw an java.lang.ClassCastException    
List<String> list = JsonPath.parse(json).read("$.store.book[0].author")

//Works fine
String author = JsonPath.parse(json).read("$.store.book[0].author")

"the type expected by the invoker" 是什么意思?

在 JsonPath 的典型用例中,库假定 we know what to expect from a path:

  • 路径是否确定?路径是:

    • 确定是否只能有一个结果,例如$..book[0] 第一本书。
    • 不确定是否可能有多个结果,例如$..book[?(@.isbn)] 具有特定属性的所有书籍; return 类型可以是列表。
  • 结果应该是什么具体类型?例如,您可以期望 return 类型 DateList<Date> 而不是 ObjectList<Object>

在你的情况下,以上所有都不重要,因为你事先不知道类型,你只需要 JSON 字符串的结果。

JsonPath 中的默认解析器太聪明了,会将所有内容转换为漂亮的 LinkedHashMap 对象;但是如果您使用 JacksonJsonNodeJsonProvider, you'll get results as JsonNode 个对象,并且您距离 JSON 个字符串结果仅 toString() 个调用。

更好的是,您可以使用 JsonPath option ALWAYS_RETURN_LIST,这意味着您无需担心您的路径是确定的还是不确定的(无论您的结果是单个对象还是一个列表)。

// Example from https://github.com/jayway/JsonPath#path-examples
final String json = "{\"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}";

Configuration conf = Configuration.builder().jsonProvider(new JacksonJsonNodeJsonProvider())
        .options(Option.ALWAYS_RETURN_LIST, Option.SUPPRESS_EXCEPTIONS).build();

ArrayNode node = JsonPath.using(conf).parse(json).read("$.store.book[*]"); // indefinite
for (Object o : node) {
    System.out.println(o.toString());
}
// {"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}

node = JsonPath.using(conf).parse(json).read("$.store.book[0].author"); // definite
for (Object o : node) {
    System.out.println(o.toString());
}
// "Nigel Rees"

假设这是您的 JSON:

{
    "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,然后您可以轻松地遍历它们并获得您想要的内容:

Configuration conf = Configuration.builder()
     .options(Option.AS_PATH_LIST).build();

List<String> authorPathList = using(conf).parse(json).read("$..author");

这将 return 作者路径列表:

["$['store']['book'][0]['author']",
"$['store']['book'][1]['author']",
"$['store']['book'][2]['author']",
"$['store']['book'][3]['author']"]

现在您可以遍历它们并获取您的值:

for (string authorPath : authorPathList) {
    String author = JsonPath.parse(json).read(authorPath);
}