【问题标题】:How to iterate all subnodes of a json object?如何迭代一个json对象的所有子节点?
【发布时间】:2018-07-16 11:35:03
【问题描述】:

我想遍历一个json对象的所有节点,写出一个普通的key-value map,如下:

{
    "name": [
        {
            "first": "John",
            "last": "Doe",
        "items": [
            {
                "name": "firstitem",
                "stock": 12
            },
            {
                "name": "2nditem",
                "stock:" 23
            }               
        ]
        }],
    "company": "John Company"
}

应该导致:

name-first-1=John
name-last-1=Doe
name-items-name-1-1=firstitem (meaning the list index is always appended at the end of the name)
name-items-name-1-2=2nditem
company=John Company

这是获取json字符串作为json对象的方法:

ObjectMapper mapper = new ObjectMapper(); //using jackson
JsonNode root = mapper.readTree(json);
//TODO how loop all nodes and subnodes, and always get their key + value?

但是我现在如何遍历所有节点并提取它们的密钥和内容?

【问题讨论】:

标签: java json jackson


【解决方案1】:

这对你有用:

ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(json);
Map<String, String> map = new HashMap<>();
addKeys("", root, map, new ArrayList<>());

map.entrySet()
     .forEach(System.out::println);

private void addKeys(String currentPath, JsonNode jsonNode, Map<String, String> map, List<Integer> suffix) {
    if (jsonNode.isObject()) {
        ObjectNode objectNode = (ObjectNode) jsonNode;
        Iterator<Map.Entry<String, JsonNode>> iter = objectNode.fields();
        String pathPrefix = currentPath.isEmpty() ? "" : currentPath + "-";

        while (iter.hasNext()) {
            Map.Entry<String, JsonNode> entry = iter.next();
            addKeys(pathPrefix + entry.getKey(), entry.getValue(), map, suffix);
        }
    } else if (jsonNode.isArray()) {
        ArrayNode arrayNode = (ArrayNode) jsonNode;

        for (int i = 0; i < arrayNode.size(); i++) {
            suffix.add(i + 1);
            addKeys(currentPath, arrayNode.get(i), map, suffix);

            if (i + 1 <arrayNode.size()){
                suffix.remove(arrayNode.size() - 1);
            }
        }

    } else if (jsonNode.isValueNode()) {
        if (currentPath.contains("-")) {
            for (int i = 0; i < suffix.size(); i++) {
                currentPath += "-" + suffix.get(i);
            }

            suffix = new ArrayList<>();
        }

        ValueNode valueNode = (ValueNode) jsonNode;
        map.put(currentPath, valueNode.asText());
    }
}

对于您给出的json,输出将是:

name-items-name-1-2=2nditem
name-items-name-1-1=firstitem
name-items-stock-1-1=12
name-first-1=John
name-items-stock-1-2=23
company=John Company
name-last-1=Doe

【讨论】:

    【解决方案2】:

    elements() 为您提供子节点的迭代器,fields() 为您提供属性。

    这样,您可以编写遍历所有节点的递归函数。

    【讨论】:

    • ...您只需要将遍历器编码为递归。
    • elements()iterator() 有什么区别?
    • @eigenfield: iterator() 听起来很相似。也许更适合。我没试过。
    【解决方案3】:

    这是工作示例,输入是字符串

    public static void main(String[] args) throws IOException {
        JsonNode node = om.readTree(input);
        LOG.info(node.toString());
        process("", node);
    }
    
    private static void process(String prefix, JsonNode currentNode) {
        if (currentNode.isArray()) {
            ArrayNode arrayNode = (ArrayNode) currentNode;
            Iterator<JsonNode> node = arrayNode.elements();
            int index = 1;
            while (node.hasNext()) {
                process(!prefix.isEmpty() ? prefix + "-" + index : String.valueOf(index), node.next());
                index += 1;
            }
        }
        else if (currentNode.isObject()) {
            currentNode.fields().forEachRemaining(entry -> process(!prefix.isEmpty() ? prefix + "-" + entry.getKey() : entry.getKey(), entry.getValue()));
        }
        else {
            LOG.info(prefix + ": " + currentNode.toString());
        }
    }
    

    【讨论】:

    • 只是递归 json 迭代
    • 不错。但是对于嵌套列表,这不会将所有列表的索引放在键的末尾吗? (请参阅我的示例,名称 + 项目是两个嵌套列表,两个索引都应出现在末尾)。
    • 好吧,这段代码只是展示了如何递归迭代 json 节点的示例。您可以更改前缀形成算法。
    【解决方案4】:

    您可以将 JSON 对象转换为 HashMap,以便获得键值对

    这里我使用 GSON 库

    代码sn-p

    Gson gson = new Gson();
    Type type = new TypeToken<Map<String, String>>(){}.getType();
    Map<String,String> map = gson.fromJson(json, type);
    

    因此您可以根据自己的目的迭代此地图。

    【讨论】:

    • 好吧,如果结果是Map&lt;String, String&gt;,那么嵌套映射如何处理?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-26
    • 1970-01-01
    相关资源
    最近更新 更多