2016-11-22 1255 views
2

我希望JsonPath始终以字符串的形式返回它解析的数据。但是,JsonPath的read()方法的返回类型因要解析的数据类型而异,因为JsonPath总是猜测数据类型是什么,并返回该类型的结果。控制JsonPath的read()方法返回的数据类型

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

有谁知道强制JsonPath返回字符串的方法?还是可以想一想更好的解决方法?

下面是我在做什么,现在(在Java中):

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

我想做什么:

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

docs我发现这一点:

在java中使用JsonPath时,重要的是要知道结果中期望的类型。 JsonPath将自动尝试将结果转换为调用者期望的类型。

//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") 

什么是 “被调用者期望的类型” 是什么意思?

+0

如果你获得了字符串(大概JSON字符串)的列表,你会尝试将其解析为对象呢? – approxiblue

+0

我会把它们解析成字符串。我输出到一个文本文件,所以字符串将是最容易处理。 – Adam

回答

2

在JsonPath的典型使用情况下,库假定we know what to expect from a path

  • 是路径明确?路径是:

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

就你而言,以上所有内容都没有关系,因为事先不知道类型,只需要结果作为JSON字符串。

JsonPath中的默认解析器太聪明了,会将所有东西都转换成好的LinkedHashMap对象;但如果使用JacksonJsonNodeJsonProvider,则会得到结果为JsonNode对象,并且您将从一个toString()调用JSON字符串结果。

更好的是,您可以使用JsonPath optionALWAYS_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" 
+0

使用不同解析器的好主意。完美的作品,谢谢! – Adam

+0

我可以确定任何'toString()'方法总能正常工作吗?我知道'Object'implements'toString()',但'Object'实现在这里不适用于我。 – Adam

+1

我认为应该没问题。看起来'ArrayNode'存储'JsonNode's,它实现'toString()'(https://fasterxml.github.io/jackson-databind/javadoc/2.0.0/com/fasterxml/jackson/databind/node/ ArrayNode.html#toString()),所以我想我会没事的。 – Adam

0

让我们假设这是您的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"); 

这将返回的作家路径列表:

["$['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); 
} 
+0

问题是我不知道'author'的类型是什么。即使我要求一个'清单',它可能会让我回到完全不同的地方。 “作者”可能是我知道的所有人的名单。 – Adam

+0

正弦不是所有的对象都可以转换为字符串,我不建议强制除非我确定它是安全的(例如string/int/decimal) – Yaser

+0

我可以通过instanceof key work和if/elseif块来确保安全就像我在问题中所描述的那样。这并不理想,这就是为什么我要求替代品。 – Adam