简体   繁体   English

使用用于JSON的Jackson流式API,如何在对象之间循环?

[英]Using the Jackson streaming api for JSON, how do I while loop through an object?

    ObjectMapper map = new ObjectMapper(); //for later inner object data binding
    JsonParser p = map.getFactory().createParser(new File("test.json"));
    //start the tokenizing of object
    p.nextToken();
    //loop until the end object is found, simultaneously incrementing loop
    while (p.nextToken() != JsonToken.END_OBJECT) {
        //...
    }
    p.close(); 

(note, there is probably a better way to do what I am trying to do here and I welcome any advice on how to do this better, but please also tell me if my current technique is possible) (请注意,这里可能有更好的方法来做我想做的事情,欢迎您提出任何有关如何做得更好的建议,但也请告诉我我目前的技术是否可行)

This is the code I currently have and have not gone any further because I realized a flaw. 这是我当前拥有的代码,因为我意识到了一个缺陷,所以没有做得更进一步。 This code was taken from a Jackson streaming API tutorial and I am trying to adapt it to my project. 该代码取自Jackson的流API教程,我正在尝试使其适应我的项目。

What I am trying to do is loop through the tokens of an object in a json file from the start of the object to its end. 我想做的是从对象的开始到结束遍历json文件中的对象标记。 However, this json file contains many inner objects, and the loop may end prematurely at the END_OBJECT of an inner object. 但是,此json文件包含许多内部对象,循环可能在内部对象的END_OBJECT处过早结束。

What I thought then was, maybe I could try to make the while loop end more specifically: only when it encounters the corresponding END_OBJECT of its START_OBJECT. 我当时的想法是,也许我可以尝试使while循环更具体地结束:仅当它遇到其START_OBJECT的相应END_OBJECT时。 I have looked in the Jackson docs (at JsonParser and JsonToken) but I cannot figure out how I would do this programmatically. 我已经查看了Jackson的文档(位于JsonParser和JsonToken),但无法弄清楚如何以编程方式进行此操作。

My question then is, how do I write a while loop that loops through one object only? 我的问题是,如何编写仅循环一个对象的while循环? How do I uniquely define the end of the object? 如何唯一定义对象的末端? I thought about storing the initial start object JsonToken in memory but I am not sure how I could compare it to the end object token to see if the two are related at all. 我考虑过将初始的起始对象JsonToken存储在内存中,但是我不确定如何将其与结束对象令牌进行比较,以查看两者是否完全相关。 The Jackson docs aren't too descriptive on this or maybe I am too wishful and naive. 杰克逊(Jackson)的文档对此没有太多描述,或者也许我太过如意和天真。

I am using a mapper because I will be doing a mix of data binding and streaming in this method. 我正在使用映射器,因为我将在这种方法中混合使用数据绑定和流式传输。 I only need to data bind the inner objects. 我只需要数据绑定内部对象。

The first object contains an array, "decks" 第一个对象包含一个数组“ decks”

The inner object contains a deck's cards (also an array). 内部对象包含卡片组的卡片(也是一个数组)。

I will be data binding single cards (as I have looked extensively but have not found an easier way to data bind inner objects (cards) while retaining some information of the "deck" they came from). 我将使用数据绑定单卡(因为我已经进行了广泛的研究,但是还没有找到一种更简单的方法来绑定内部对象(卡)的数据,同时保留它们所来自“甲板”的某些信息)。

Specifically regarding the way you do it, the simplest general solution would be counting the START_OBJECT encountered vs the END_OBJECT (same exercise in CS classes of knowing if an expression contains the correct number of opening and closing parenthesis). 具体来说,最简单的通用解决方案是对遇到的START_OBJECT与END_OBJECT进行计数(CS类中的相同练习,即知道表达式是否包含正确数量的开括号和闭括号)。 So your code would look like: 因此您的代码如下所示:

ObjectMapper map = new ObjectMapper(); //for later inner object data binding
JsonParser p = map.getFactory().createParser(new File("test.json"));
//start the tokenizing of object
p.nextToken();
// Assuming the first token you encounter is the START_OBJECT, otherwise start from 0.
int startEndCounter = 1;
//loop until the end object is found, simultaneously incrementing loop
while (startEndCounter != 0) {
    //...
    if (p.nextToken() == JsonToken.STAR_OBJECT) {
        startEndCounter++;    
    } else if (p.nextToken() == JsonToken.END_OBJECT) {
        startEndCounter--;    
    }
}
p.close();

And the Jackson way to read an object using the parser: 以及使用解析器读取对象的Jackson方法:

Card card = mapper.readValue(jp, Card.class);

Here's a variation of an example from the fasterxml wiki , which will read a Card object on each iteration: 这是fasterxml Wiki的一个示例变体,它将在每次迭代中读取Card对象:

JsonParser jp = map.getFactory().createParser(new File("test.json"));
// advance stream to START_ARRAY first:
jp.nextToken();
// and then each time, advance to opening START_OBJECT
while (jp.nextToken() == JsonToken.START_OBJECT)) {
Card card = mapper.readValue(jp, Card.class);
   // process
   // after binding, stream points to closing END_OBJECT
}

If you reach the end of the stream, call to parser.nextToken() will return null. 如果到达流的末尾,则对parser.nextToken()的调用将返回null。 You can iterate until null is returned like so and build your desired object: 您可以像这样迭代直到返回null,然后构建所需的对象:

            Object myObject; 
            List<Object> myObjects = new ArrayList()
            JsonToken nextToken = parser.nextToken()
            while (nextToken != null) {
                nextToken = parser.nextToken()
                if (nextToken == JsonToken.START_OBJECT) {myObject = new Object()}
                else if (nextToken == JsonToken.END_OBJECT){myObjects.add(myObject)}
                else {
                       if(parser.currentName == "myProperty"){
                           parser.nextToken()
                           myObject.property = parser.getValue()
                        }
                     }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM