当前位置: 首页 > 面试题库 >

展平JSON字符串以使包含每个级别键值的键映射到Map 使用Gson或Jackson

胡鸿羲
2023-03-14
问题内容

我有一个有关使用Gson或Jackson拼写将JSON字符串展平到Map的增强问题。

我的场景包括重复键,因此上述问题中的解决方案将导致某些重复键被覆盖。因此,我正在考虑通过将每个级别的键组合在一起来构造键。

那么如何实现呢?

例如:

{
    "id" : "123",
    "name" : "Tom",
    "class" : {
        "subject" : "Math",
        "teacher" : "Jack"
    }
}

我想获取地图:

"id" : "123",
"name" : "Tom",
"class.subject" : "Math",
"class.teacher" : "Jack"

***更新解决方案*** ***

基于@Manos Nikolaidis的答案,我可以通过考虑ArrayNode来实现以下解决方案。

public void processJsonString(String jsonString) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    ArrayNode arrayNode = (ArrayNode) mapper.readTree(jsonString);
    processArrayNode(arrayNode);
}

private void processObjectNode(JsonNode jsonNode) {
    Map<String, String> result = new HashMap<>();
    Iterator<Map.Entry<String, JsonNode>> iterator = jsonNode.fields();
    iterator.forEachRemaining(node -> mapAppender(result, node, new ArrayList<String>()));
}

private void processArrayNode(ArrayNode arrayNode) {
    for (JsonNode jsonNode : arrayNode) {
        processObjectNode(jsonNode);
    }
}


private void mapAppender(Map<String, String> result, Map.Entry<String, JsonNode> node, List<String> names) {
    names.add(node.getKey());
    if (node.getValue().isTextual()) {
        String name = names.stream().collect(Collectors.joining("."));
        result.put(name, node.getValue().asText());
    } else if (node.getValue().isArray()) {
        processArrayNode((ArrayNode) node.getValue());
    } else if (node.getValue().isNull()) {
        String name = names.stream().collect(Collectors.joining("."));
        result.put(name, null);
    } else {
        node.getValue().fields()
                        .forEachRemaining(nested -> mapAppender(result, nested, new ArrayList<>(names)));
    }
}

问题答案:

您可以获取JSON,JsonNode并递归遍历所有字段,然后将键和值字段添加到Map。当值是对象而不是字符串时,您可以将字段名称添加到List中,以最终遇到字符串时使用句点进行连接。首先创建(为了提高可读性)将Json字段添加到的单独方法Map

void mapAppender(Map<String, String> result, Entry<String, JsonNode> node, List<String> names) {
    names.add(node.getKey());
    if (node.getValue().isTextual()) {
        String name = names.stream().collect(joining("."));
        result.put(name, node.getValue().asText());
    } else {
        node.getValue().fields()
            .forEachRemaining(nested -> mapAppender(result, nested, new ArrayList<>(names)));
    }
}

并像这样使用它:

ObjectMapper mapper = new ObjectMapper();
Map<String, String> result = new HashMap<>();
mapper.readTree(json).fields()
    .forEachRemaining(node -> mapAppender(result, node, new ArrayList<String>()));

fields()返回Iterator。谨防StackOverflowErrors深度嵌套的JSON可能会降低性能。



 类似资料:
  • 在我的Android应用程序中,我从web服务得到了一个响应。web服务将响应返回为 也就是说,对于“ResponseData”,值要么是string要么是JSONObject。 我在用Gson进行解析。 我编写了用于解析的POJO类 注意:decodeString()方法给出了上面指定的json对象。

  • 问题内容: 我想将a转换为,所以我想可以解决这个问题,但是它说不支持type失败。但是,如果我使用带键字符串,它可以正常工作。 http://play.golang.org/p/qhlS9Nt8qQ 稍后在检查编组代码时,将进行显式检查,以查看键是否不是字符串并返回… 为什么什至不能使用基元作为键?如果json标准不允许非字符串键,是否不应该将原语转换为字符串并将其用作键? 问题答案: 这不是因为

  • 问题内容: 我有以下JSON表示盐请求的服务器响应: 我尝试使用以下POJO映射它: 现在每次我这样做: 该为空。如何使用Gson将JSON映射到POJO?我的变量顺序对Gson映射重要吗? 问题答案: 我的变量顺序对Gson映射重要吗? 不,不是这样。 如何使用Gson将JSON映射到POJO? 它是 区分大小写 和JSON字符串键应该是相同的POJO类使用的变量名。 您可以使用@Seriali

  • 我有以下JSON来表示salt请求的服务器响应: 我尝试用以下POJO映射它: 每次我这样做: 为空。如何使用GSON将JSON映射到POJO?变量的顺序对Gson映射重要吗?

  • 我想解析一些JSON,但一个键要么是字符串,要么是对象。 这是我当前的结构:https://github.com/PhillippOhlandt/pmtoapib/blob/master/CollectionItemRequest.go#L10 在这里,“Url”属性不仅可以是字符串,还可以是对象。 我开始为它创建一个自己的结构,覆盖对象案例。 但是这样字符串版本就不行了。有没有一种方法既能处理这