我之前从未尝试过解析JSON。我有一些像这样的JSON格式的书:
df_new = df.groupby('video_id').agg({"ios_id": np.count_nonzero,
"ios_id": pd.Series.nunique,
"feed_position": np.average,
"time_watched": np.sum,
"video_length": np.sum}).sort('ios_id', ascending=False)
我想要的是解析它们并最终得到一个已填充的Book对象列表。我和杰克逊以及谷歌的GSON一起玩过。我终于开始工作,但我并不满意。这只是有效的代码,我希望我的解决方案是将来再次使用JSON时的良好代码 - 我认为这是低效的,因为我首先将其转换为树然后解析它。有人可以建议改进吗?
{
"Search": {
"Books": [
{
"isbn": "1849830347",
"title": "American Assassin",
"author": "Vince Flynn",
"price": 7.99
},
{
"isbn": "0857208683",
"title": Kill Shot",
"author": "Vince Flynn",
"price": 5.99
},
...
}
}
我拥有setCodec行的唯一原因是因为没有它,我得到一个带有消息的IllegalStateException:没有为解析器定义的ObjectCodec,不能将JSON反序列化为JsonNode树。
从Jackson API开始,我尝试使用Streaming API方法。但我不得不调用jp.nextToken()大约10次才能获得第一个isbn值,它看起来非常混乱。虽然API确实说它的速度提高了20%/ 30%。
感谢对此的任何反馈。
答案 0 :(得分:2)
您可以在Gson中编写自己的反序列化程序: https://sites.google.com/site/gson/gson-user-guide#TOC-Writing-a-Deserializer
或者您可以使用所需的setter创建一个Object并让Gson完成工作: http://java.dzone.com/articles/deserializing-json-java-object
答案 1 :(得分:0)
一些可用的JSON库或多或少都很麻烦。在我看来,遍历树是使用外部库时不应该关心的事情之一。在这种情况下,您甚至可以自己编写。
但是我前面找到了一个很好的库,它可以帮助你完成所有这些工作,名为json-io。 这个库的缺点是它不能很好地与Android一起使用。 (我在Android上获得了OutOfMemory异常。)
答案 2 :(得分:0)
杰克逊提供三个级别"解析:流API是基础层,并且在此基础上提供了将JSON解析为树节点或您自己的类。虽然直接使用流式传输API可能效率最高,但正如您所发现的那样,需要大量人力。
事实上,你需要的大部分内容似乎都在1-minute tutorial中,无需向前跳!
Jackson可以直接创建/填充您自己的Book对象,而不是解析为JsonNode。由于你已经拥有了bean风格的setter,所以这应该是一个简单的插件。
(BTW的典型用法是最初创建一个ObjectMapper--通常作为单例 - 并从中创建JsonFactory,ObjectReader等而不是相反的方式)
所以你可以这样阅读一个Book对象:
Book book = mapper.readValue("{\"isbn\":\"1849830347\"}", Book.class);
您可以创建某种包装器对象来表示"搜索"键:
/*static*/ class SearchResult {
@JsonProperty("Books")
public List<Book> books;
}
SearchResult result = mapper.readValue("{\"Books\":[{\"isbn\":\"...\"}]}", SearchResult.class);
List<Book> books = result.books;
(@JsonProperty需要指定一个大写的&#34; Books&#34;字段名称,而不是默认值。为了简洁起见,显示为公共字段,带有getter和setter的私有字段也可以工作)< / p>
然后你可以添加另一层对象来表示整个消息,或添加一个@JsonRootName注释来告诉Jackson在SearchResult是&#34; root&#34;时进行额外的解包。类型:
@JsonRootName(value="Search")
class SearchResult { ... }
很多时候你可以避免直接使用JsonNode,JsonFactory等杰克逊。如果你只注释属性名称等的类,那么你只需要对称地使用这些类来解析和格式。
答案 3 :(得分:0)
我在很多项目中都使用过Jackson,并且将来会毫不犹豫地再次使用它。
在大多数情况下,我喜欢开发用于为JSON消息建模的Java POJO。因此,在您的情况下,您需要一个Book POJO来模拟JSON的内部部分
{
"isbn": "1849830347",
"title": "American Assassin",
"author": "Vince Flynn",
"price": 7.99
}
匹配的POJO就是这个
public class BookVO {
private final String isbn;
private final String title;
private final String author;
private final double price;
@JsonCreator
public BookVO(@JsonProperty("isbn") final String isbn, @JsonProperty("title") final String title, @JsonProperty("author") final String author, @JsonProperty("price") final double price) {
super();
this.isbn = isbn;
this.title = title;
this.author = author;
this.price = price;
}
public String getIsbn() {
return isbn;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
public double getPrice() {
return price;
}
}
上面这本书的父POJO就是这个
public class BookSearchVO {
private final BookVO[] books;
@JsonCreator
public BookSearchVO(@JsonProperty("Books") final BookVO[] books) {
super();
this.books = books;
}
public BookVO[] getBooks() {
return books;
}
}
Grand Parent POJO就是这个
public class SearchVO {
private final BookSearchVO search;
@JsonCreator
public SearchVO(@JsonProperty("Search") final BookSearchVO search) {
super();
this.search = search;
}
public BookSearchVO getSearch() {
return search;
}
}
将JSON转换为Java对象只需执行此操作
final ObjectMapper mapperBook = new ObjectMapper();
final SearchVO results = mapperBook.readValue(new File("books.json"), SearchVO.class);
books.json的内容是
{
"Search":{
"Books":[
{
"isbn":"1849830347",
"title":"American Assassin",
"author":"Vince Flynn",
"price":7.99
},
{
"isbn":"0857208683",
"title":"Kill Shot",
"author":"Vince Flynn",
"price":5.99
}
]
}
}