使用JSONObject在Java中为以下结构创建嵌套JSON对象

时间:2014-09-09 03:30:59

标签: java json

父键集:------- [2002,2003,2000,2001,2004,2005,999]

我有一个Map,它有很多键/值对,如下所述。 2002年的关键是[201,1004,200]。 现在,201中的值再次被用作此映射中具有一定价值的键。所以这种结构还在继续。

如何使用Java代码构建JSON嵌套JSON结构?

中断条件: - 当值不存在为关键时。它被视为没有任何子节点的叶节点,我们可以关闭那个节点的JSON结构。

{2002=[201, 1004, 200],
 2003=[1002, 311, 902, 312], 
 2001=[305, 304, 322, 900, 317, 301, 319, 302, 318, 303], 
 201=[203, 202], 
 203=[204], 
 2004=[310, 109], 
 202=[121], 
 2005=[1000, 1003, 116, 504, 115, 505, 114, 1010, 502, 108, 503, 107]}

2 个答案:

答案 0 :(得分:1)

my other answer相同的先决条件适用(我创建了相同的地图)

为了非递归地解决这个问题,我使用了一个堆栈。为此,我需要一个类来保存有关堆栈元素的所有信息:

public class StackElement{
    int value; //the value
    StackElement parent; //the object which corresponds to the key in the map
    boolean touched = false; //have my children been added to the stack?
    JSONArray jArr = new JSONArray(); //my children's JSON

    public StackElement(int value, StackElement parent){
        this.value = value;
        this.parent = parent;
    }

    public void addToParent(){
        if(jArr.length() == 0){
            //I have no children, so I only put my value
            parent.jArr.put(value);
        }
        else{
            parent.jArr.put(new JSONObject().put(Integer.toString(value), jArr));
        }
    }
}

为方便起见,我为2002和999这样的顶级键创建了另一个类,这样我就不必以不同的方式处理它们了

public class TopLevelStackElement extends StackElement{
    //corresponds to the top-level keys like 2002 and 999

    JSONObject jObj;
    public TopLevelStackElement(int value, JSONObject jObj) {
        super(value, null);
        this.jObj = jObj;
    }

    @Override
    public void addToParent(){
        //add the accumulated JSON of the children to the JSONObject 
        //I want to have as result
        jObj.put(Integer.toString(value), jArr);
    }

}

要创建我使用以下算法的JSONObject:

JSONObject jObj = new JSONObject(); //the result
Stack<StackElement> stack = new Stack<>(); //stack to store the pending nodes
//add all the top-level keys
for(int i: new int[]{2002, 2003, 2000, 2001, 2004, 2005, 999}){
    stack.push(new TopLevelStackElement(i, jObj));
}

//process all the nodes
while(!stack.isEmpty()){
    StackElement item = stack.peek();

    if(item.touched || !map.containsKey(item.value)){
        //either item is a leaf, which means that the map does not contain it 
        //as a key
        //or its children had already been added to the stack and processed
        item.addToParent();
        stack.pop();
    }
    else{
        //the item is not a leaf, but has not been processed before, which means
        // that I have to put its children on the stack to be processed 
        //(see below for explanation)
        item.touched = true; //tells me that my children have been added
        Integer[] values = map.get(item.value);
        for(int i = 0; i < values.length; i++){
            //add all the children to the stack
            stack.push(new StackElement(values[i], item)); 
        }
    }
}

这个想法是这样的:

                                         121
         200                     202(f)  202(t)  202(t)
        1004    1004             203(f)  203(f)  203(f)  203(f)
         201(f)  201(f)  201(f)  201(t)  201(t)  201(t)  201(t)
2002(f) 2002(t) 2002(t) 2002(t) 2002(t) 2002(t) 2002(t) 2002(t)
   1.     2.      3.      4.      5.      6.      7.      8.

在步骤5中,将202的子节点添加到堆栈中(仅121),如步骤6中所示。在步骤7中,已经处理了202的所有子节点,因此我可以从堆栈中移除202。

如果我只有202个元素而没有其他信息,我怎么知道呢?

简单:我在202元素中添加了一个标志,当我添加它的子元素时,我将其设置为true。当我在地图中包含有值的元素,但是将此标志设置为true时,我知道子节点已经处理过,我可以安全地从堆栈中删除该项目。

所以括号中的字母代表这个标志的当前状态。

答案 1 :(得分:0)

根据您的问题,我有一张这样的地图:

HashMap<Integer, Integer[]> map = new HashMap<>();
map.put(2002, new Integer[]{201, 1004, 200});
map.put(2003, new Integer[]{1002, 311, 902, 312});
map.put(2001, new Integer[]{305, 304, 322, 900, 317, 301, 319, 302, 318, 303}); 
map.put(201, new Integer[]{203, 202}); 
map.put(203, new Integer[]{204}); 
map.put(2004, new Integer[]{310, 109}); 
map.put(202, new Integer[]{121}); 
map.put(2005, new Integer[]{1000, 1003, 116, 504, 115, 505, 114, 1010, 502, 108, 503, 107});

要创建嵌套结构,我将使用递归方法:

对于给定的keyValue,我检索所有值并查看它们是否是地图中的键。如果它们是,我再次使用值作为keyValue调用相同的方法,否则我将只返回值,因为它是一个叶子。

private JSONArray createJSONArray(HashMap<Integer, Integer[]> map, int keyValue) {
    Integer[] values = map.get(keyValue);
    JSONArray arr = new JSONArray();
    if(values != null){
        for(int val: values){
            if(map.containsKey(val)){
                JSONObject jObj = new JSONObject();
                jObj.put(Integer.toString(val), createJSONArray(map, val));
                arr.put(jObj);
            }
            else{
                arr.put(val);
            }
        }
    }
    return arr;
}

要使用顶级键创建一个完整的JSONObject,我在一个循环中运行上面的方法,其顶级值为keyValue:

JSONObject jObj = new JSONObject();
for(int key: new int[]{2002, 2003, 2000, 2001, 2004, 2005, 999}){
    jObj.put(Integer.toString(key), createJSONArray(map, key));
}

这将产生以下结果,希望是您想要的格式:

{
    "2004": [ 310, 109 ],
    "2005": [ 1000, 1003, 116, 504, 115, 505, 114, 1010, 502, 108, 503, 107 ],
    "2002": [ {"201": [ {"203": [204] }, {"202": [121] } ] }, 1004, 200 ],
    "2003": [ 1002, 311, 902, 312 ],
    "2001": [ 305, 304, 322, 900, 317, 301, 319, 302, 318, 303 ],
    "999": [],
    "2000": []
}