当前位置: 首页 > 知识库问答 >
问题:

带有空元素键的Jackson JsonNode

田博超
2023-03-14

我使用jackson-dataformat-xml(2.9)将XML解析为JSONode,然后将其解析为JSON(XML是非常动态的,所以我使用JSONode而不是绑定到POJO。例如,“元素名”和“id”的名称可能不同)。

在JSON解析阶段,其中一个元素键是空字符串(“”)。

XML:

<elementName>
      <id type="pid">abcdef123</id>
</elementName>
public Parser() {
        ObjectMapper jsonMapper = new ObjectMapper();
        XmlMapper xmlMapper = new XmlMapper(new XmlFactory(new WstxInputFactory()));
}

public InputStream parseXmlResponse(InputStream xmlStream) {
        InputStream stream = null;

        try {
            JsonNode node = xmlMapper.readTree(xmlStream);
            stream = new ByteArrayInputStream(jsonMapper.writer().writeValueAsBytes(node));
        } catch (IOException e) {
            e.printStackTrace();
        }

        return stream;
    }

JSON:

结果:

{
   "elementName": {
     "id": {
        "type": "pid",
        "": "abcdef123"
     }
   },
}

预期:

{
   "elementName": {
     "id": {
        "type": "pid",
        "value": "abcdef123"
     }
   },
}

我的想法是无论何时找到空密钥“”,并用“值”替换它。无论是在XML反序列化还是在JSON序列化期间。我尝试使用默认的序列化程序,筛选器,但没有使它以一种良好和简洁的方式工作。

非常感谢提出建议。

基于@Shoek的建议,我决定编写一个自定义序列化程序,以避免在过程中创建中间对象(ObjectNode)。

public class CustomNode {
    private JsonNode jsonNode;

    public CustomNode(JsonNode jsonNode) {
        this.jsonNode = jsonNode;
    }

    public JsonNode getJsonNode() {
        return jsonNode;
    }
}

public class CustomObjectsResponseSerializer extends StdSerializer<CustomNode> {

    protected CustomObjectsResponseSerializer() {
        super(CustomNode.class);
    }

    @Override
    public void serialize(CustomNode node, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        convertObjectNode(node.getJsonNode(), jgen, provider);
    }

    private void convertObjectNode(JsonNode node, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        jgen.writeStartObject();
        for (Iterator<String> it = node.fieldNames(); it.hasNext(); ) {
            String childName = it.next();
            JsonNode childNode = node.get(childName);
            // XML parser returns an empty string as value name. Replacing it with "value"
            if (Objects.equals("", childName)) {
                childName = "value";
            }

            if (childNode instanceof ArrayNode) {
                jgen.writeFieldName(childName);
                convertArrayNode(childNode, jgen, provider);
            } else if (childNode instanceof ObjectNode) {
                jgen.writeFieldName(childName);
                convertObjectNode(childNode, jgen, provider);
            } else {
                provider.defaultSerializeField(childName, childNode, jgen);
            }
        }
        jgen.writeEndObject();

    }

    private void convertArrayNode(JsonNode node, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        jgen.writeStartArray();
        for (Iterator<JsonNode> it = node.elements(); it.hasNext(); ) {
            JsonNode childNode = it.next();

            if (childNode instanceof ArrayNode) {
                convertArrayNode(childNode, jgen, provider);
            } else if (childNode instanceof ObjectNode) {
                convertObjectNode(childNode, jgen, provider);
            } else {
                provider.defaultSerializeValue(childNode, jgen);
            }
        }
        jgen.writeEndArray();
    }
}

共有1个答案

都超英
2023-03-14

您还可以简单地对JSON DOM进行后处理,遍历所有对象,并将空字符串的键重命名为“value”。

争用条件:这样的密钥可能已经存在,并且不能覆盖
(例如 abcdef123 )。

用法:
(注意:您不应该静默地禁止异常并返回null,而是允许它传播,以便调用方可以决定在需要时捕获并应用故障转移逻辑)

public InputStream parseXmlResponse(InputStream xmlStream) throws IOException {
    JsonNode node = xmlMapper.readTree(xmlStream);
    postprocess(node);
    return new ByteArrayInputStream(jsonMapper.writer().writeValueAsBytes(node));
}
private void postprocess(JsonNode jsonNode) {

    if (jsonNode.isArray()) {
        ArrayNode array = (ArrayNode) jsonNode;
        Iterable<JsonNode> elements = () -> array.elements();

        // recursive post-processing
        for (JsonNode element : elements) {
            postprocess(element);
        }
    }
    if (jsonNode.isObject()) {
        ObjectNode object = (ObjectNode) jsonNode;
        Iterable<String> fieldNames = () -> object.fieldNames();

        // recursive post-processing
        for (String fieldName : fieldNames) {
            postprocess(object.get(fieldName));
        }
        // check if an attribute with empty string key exists, and rename it to 'value',
        // unless there already exists another non-null attribute named 'value' which
        // would be overwritten.
        JsonNode emptyKeyValue = object.get("");
        JsonNode existing = object.get("value");
        if (emptyKeyValue != null) {
            if (existing == null || existing.isNull()) {
                object.set("value", emptyKeyValue);
                object.remove("");
            } else {
                System.err.println("Skipping empty key value as a key named 'value' already exists.");
            }
        }
    }
}

输出:正如预期的那样。

{
   "elementName": {
     "id": {
        "type": "pid",
        "value": "abcdef123"
     }
   },
}

编辑:关于性能的注意事项:

我使用一个大型XML文件(enwikiquote-20200520-pages-articles-multistream.XML,en.wikiquote XML dump,498.4 MB)进行了100轮测试,测试时间如下(使用deltas与system.nanotime()):

  • 平均读取时间(文件,SSD):2870.96ms
    (jsonnode=xmlmapper.readtree(xmlStream);)
  • 平均后处理时间:0.04ms
    (后处理(节点);)
  • 平均写入时间(内存):0.31ms
    (new ByteArrayInputStream(jsonMapper.writer().writeValueasBytes(node));)

对于从一个大约500 MB的文件构建对象树来说,这只是一毫秒的几分之一--因此性能非常出色,无需担心。

 类似资料:
  • 我有以下,每个都有几个元素: 我打算让变量包含、或类型的元素。我尝试将类型的元素添加到中,如下所示: 但是IDE不允许我这样做,它说: 我是否使用了?我如何解决这个问题?

  • 问题内容: 我正在使用Java,我创建了一个枚举,如下所示: 上面的示例在以元素名称(即北美)使用空格时给出了错误。有什么建议可以解决上述问题吗? 问题答案: 您不能在标识符中间放置空格。 这样做结束了标识符,并且解析器假定接下来要执行的操作是该语句上下文中的有效令牌。很少(如果有)合法的地方。 常规的Java值名称为: 一个可以具有相关属性,如人类可读的名称,例如, 我对用于提供表示层表示形式有

  • 我想根据元素的数据集过滤元素。我创建了一个小提琴来显示我所处的位置:这里,但如你所见,当我选择“红色”时,它只是隐藏了“红色”项,而不是其他项。就像“黄色”一样,它不会做任何事情。 下面是脚本: 多谢!

  • 本文向大家介绍什么是空元素?常用的空元素有哪些?相关面试题,主要包含被问及什么是空元素?常用的空元素有哪些?时的应答技巧和注意事项,需要的朋友参考一下 没有闭合标签的元素是空元素

  • 问题内容: 在命令提示符下运行项目时,出现以下错误 我收到以下错误 来源:com / javavids / jaxb / sitemap / UPM / Test.java 来源:com / javavids / jaxb / sitemap / UPM / ObjectFactory.java 来源:com / javavids / jaxb / sitemap / main / Main.ja

  • 我有一个问题与我的震动转换,但不知道如何解决它。我在生成的数组中获得“null”元素: 我的结果: