如何用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
相关产品推荐
相关产品推荐

