Прочитайте часть строки JSON, используя Jackson
Строка JSON выглядит следующим образом
{
"rank":"-text_relevance",
"match-expr":"(label 'star wars')",
"hits":{
"found":7,
"start":0,
"hit":[
{"id":"tt1185834",
"data":{
"actor":["Abercrombie, Ian","Baker, Dee","Burton, Corey"],
"title":["Star Wars: The Clone Wars"]
}
},
.
.
.
{"id":"tt0121766",
"data":{
"actor":["Bai, Ling","Bryant, Gene","Castle-Hughes, Keisha"],
"title":["Star Wars: Episode III - Revenge of the Sith"]
}
}
]
},
"info":{
"rid":"b7c167f6c2da6d93531b9a7b314ad030b3a74803b4b7797edb905ba5a6a08",
"time-ms":2,
"cpu-time-ms":0
}
}
В нем много полей, но мне просто нужно поле данных. Это не сработает:
mapper.readvalue(jsonString,Data.class);
Как заставить Джексона читать только поле "Данные"?
Ответы
Ответ 1
У Jackson 2.3 теперь есть класс JsonPointer, который вы можете использовать. В этом выпуске представлен простой пример в кратком обзоре.
Использование прост: для JSON как
{
"address" : { "street" : "2940 5th Ave", "zip" : 980021 },
"dimensions" : [ 10.0, 20.0, 15.0 ]
}
вы можете использовать выражения типа:
JsonNode root = mapper.readTree(src);
int zip =root.at("/address/zip").asIntValue();
double height = root.add("/dimensions/1").asDoubleValue();// assuming it the second number in there
Ответ 2
Я думаю, что самый простой способ сделать это - использовать Jackson TreeModel: пусть Джексон проанализирует вход JSON в JsonNode
, который вы затем запрашиваете, предполагая некоторое знание структуры данных. Таким образом, вы можете игнорировать большинство данных, идя вниз по JsonNodes
к тем данным, которые вы хотите.
// String input = The JSON data from your question
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readValue(input.getBytes(), JsonNode.class);
// can also use ArrayNode here, but JsonNode allows us to get(index) line an array:
JsonNode hits = rootNode.get("hits");
// can also use ObjectNodes here:
JsonNode oneHit = null;
JsonNode dataObj = null;
int idx = 0;
Data data = null;
if (hits != null)
{
hits = hits.get("hit");
if (hits != null)
{
while ((oneHit = hits.get(idx)) != null)
{
dataObj = oneHit.get("data");
System.out.println("Data[" + idx + "]: " + dataObj);
idx++;
}
}
}
Вывод:
Data[0]: {"id":"tt1185834","data":{"actor":["Abercrombie, Ian","Baker, Dee","Burton, Corey"],"title":["Star Wars: The Clone Wars"]}}
Data[1]: {"id":"tt0121766","data":{"actor":["Bai, Ling","Bryant, Gene","Castle-Hughes, Keisha"],"title":["Star Wars: Episode III - Revenge of the Sith"]}}
Вы по-прежнему можете использовать реализацию класса Data
, но я считаю, что для этого потребуется String
, представляющий каждый Data
, как указано выше, используя toString
или используя JsonNode.getText()
- и повторно разглаживая его используя ObjectMapper
:
mapper.readValue(dataArray, Data.class));
Альтернативой является использование модели потоковой передачи Jackson и перехват узлов самостоятельно, пока вы не увидите часть входа, которая отмечает начало каждого элемента Data
, затем потребляет строку и вызывает objectMapper.readValue
в содержимом, для каждой строки.
Ответ 3
Json-path может быть очень хорошей альтернативой для такого требования - если вы в порядке с решением, отличным от Jackson, то есть: http://code.google.com/p/json-path/