2016-11-22 37 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