You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Jackson将大JsonNode转为指定数组格式的XML?

解决方案:Jackson动态JsonNode转XML(数组用包裹)

针对你遇到的动态结构大JSON转XML的需求,以下是两种可行方案,分别适用于树结构处理和流式大文件场景:

方案1:自定义JsonNode XML序列化器(树结构处理)

通过自定义XmlSerializer覆盖Jackson默认的数组序列化逻辑,强制将数组元素用<Item>标签包裹在父节点下。

步骤1:实现自定义序列化器

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ValueNode;
import com.fasterxml.jackson.dataformat.xml.ser.XmlSerializer;
import com.fasterxml.jackson.dataformat.xml.ser.XmlSerializerProvider;

import java.io.IOException;

public class CustomJsonNodeXmlSerializer extends XmlSerializer<JsonNode> {

    @Override
    public void serialize(JsonNode value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        XmlSerializerProvider xmlProvider = (XmlSerializerProvider) provider;
        processNode(value, gen, xmlProvider);
    }

    private void processNode(JsonNode node, JsonGenerator gen, XmlSerializerProvider provider) throws IOException {
        if (node.isArray()) {
            // 遍历数组元素,每个元素用<Item>包裹
            ArrayNode arrayNode = (ArrayNode) node;
            for (JsonNode item : arrayNode) {
                gen.writeStartObject();
                gen.writeFieldName("Item");
                processNode(item, gen, provider);
                gen.writeEndObject();
            }
        } else if (node.isObject()) {
            // 递归处理对象节点的所有字段
            ObjectNode objectNode = (ObjectNode) node;
            gen.writeStartObject();
            for (String fieldName : objectNode.fieldNames()) {
                JsonNode child = objectNode.get(fieldName);
                gen.writeFieldName(fieldName);
                processNode(child, gen, provider);
            }
            gen.writeEndObject();
        } else if (node.isValueNode()) {
            // 直接写入值类型节点的内容
            ValueNode valueNode = (ValueNode) node;
            gen.writeObject(valueNode.asText());
        }
    }
}

步骤2:注册序列化器并转换

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

import java.io.File;
import java.io.IOException;

public class JsonNodeToXmlDemo {
    public static void main(String[] args) throws IOException {
        // 初始化XmlMapper并注册自定义序列化器
        XmlMapper xmlMapper = new XmlMapper();
        SimpleModule customModule = new SimpleModule();
        customModule.addSerializer(JsonNode.class, new CustomJsonNodeXmlSerializer());
        xmlMapper.registerModule(customModule);

        // 读取JSON文件为JsonNode(适合中等大小文件)
        JsonNode jsonNode = xmlMapper.readTree(new File("input.json"));

        // 转换并写入XML文件
        xmlMapper.writeValue(new File("output.xml"), jsonNode);
    }
}

输出示例:
输入JSON:

{
  "data": [
    "item1",
    {"name": "item2", "tags": ["tagA", "tagB"]}
  ]
}

转换后XML:

<root>
  <data>
    <Item>item1</Item>
    <Item>
      <name>item2</name>
      <tags>
        <Item>tagA</Item>
        <Item>tagB</Item>
      </tags>
    </Item>
  </data>
</root>

方案2:流式处理(适合10-200MB大文件)

对于超大JSON,直接加载为JsonNode会导致内存溢出,建议使用Jackson的流式API,一边读取JSON Token一边生成XML,全程低内存占用。

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.dataformat.xml.XmlFactory;
import com.fasterxml.jackson.dataformat.xml.XmlGenerator;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class StreamingJsonToXml {
    public static void main(String[] args) throws IOException {
        try (JsonParser jsonParser = new com.fasterxml.jackson.databind.ObjectMapper().getFactory()
                .createParser(new FileInputStream("large_input.json"));
             XmlGenerator xmlGenerator = new XmlFactory().createGenerator(new FileOutputStream("large_output.xml"))) {

            xmlGenerator.writeStartDocument();
            xmlGenerator.writeStartObject(); // 自定义根节点,可修改名称

            while (!jsonParser.isClosed()) {
                JsonToken token = jsonParser.nextToken();
                if (token == null) break;

                switch (token) {
                    case START_OBJECT:
                        xmlGenerator.writeStartObject();
                        break;
                    case END_OBJECT:
                        xmlGenerator.writeEndObject();
                        break;
                    case START_ARRAY:
                        // 数组开始时不额外生成标签,后续元素用<Item>包裹
                        break;
                    case END_ARRAY:
                        break;
                    case FIELD_NAME:
                        String fieldName = jsonParser.getCurrentName();
                        xmlGenerator.writeFieldName(fieldName);
                        break;
                    default:
                        // 值类型节点:如果处于数组中,用<Item>包裹
                        if (jsonParser.getParsingContext().inArray()) {
                            xmlGenerator.writeStartObject();
                            xmlGenerator.writeFieldName("Item");
                            xmlGenerator.writeObject(jsonParser.getValueAsString());
                            xmlGenerator.writeEndObject();
                        } else {
                            xmlGenerator.writeObject(jsonParser.getValueAsString());
                        }
                        break;
                }
            }

            xmlGenerator.writeEndObject();
            xmlGenerator.writeEndDocument();
        }
    }
}

关键说明

  • 方案1适合中等大小的JSON,代码更简洁,支持嵌套数组的处理
  • 方案2针对超大文件,流式处理避免内存溢出,性能更优
  • 两种方案都严格遵循你要求的数组格式:所有数组元素被<Item>标签包裹,直接嵌套在对应父节点下

内容的提问来源于stack exchange,提问作者JustJavaDeveloper_987

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 01:01:51