使用 Jackson 将 XML 属性添加到手动构建的节点树

Posted

技术标签:

【中文标题】使用 Jackson 将 XML 属性添加到手动构建的节点树【英文标题】:Using Jackson to add XML attributes to manually-built node-tree 【发布时间】:2019-11-25 09:34:33 【问题描述】:

我正在尝试设置代码以使用Jackson 创建一个节点树,然后可以使用它来编写JSONXML。我已经像这样手动创建了节点树:

XmlMapper nodeMapper = new XmlMapper();

ObjectNode rootNode = nodeMapper.createObjectNode();
ObjectNode currentNode = rootNode.putObject("Examples");
currentNode.put("Puppy", TRUE)
           .put("Apple", 2)
           .put("Jet", "Li");
currentNode = rootNode.putObject("Single");
currentNode.put("One", 1);

String writePath = "C:/users/itsameamario/Documents/basicXMLtest.xml";
nodeMapper.writeValue(new File(writePath), rootNode);

我的 XML 输出是:

<?xml version="1.0"?>
<ObjectNode>
    <Examples>
        <Puppy>true</Puppy>
        <Apple>2</Apple>
        <Jet>Li</Jet>
    </Examples>
    <Single>
        <One>1</One>
    </Single>
</ObjectNode>

但是对于 XML 的某些部分,我想向其中一个节点添加一个属性,如下所示:

<Examples overlyComplicated="yes">
<!--...-->
</Examples>

我发现的所有包含属性的示例都应用于预先存在的类。我一直无法找到将属性添加到上述手动构建的节点树的方法。使用Jackson是否可行?

【问题讨论】:

【参考方案1】:

无法将给定属性标记为attribute,因为ObjectNode 对序列化一无所知。您可以对 POJO 类执行此操作,并且仅当 @JacksonXmlProperty(isAttribute = true) 注释用于给定属性时,com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator 才会处理它。我建议为需要属性的元素创建POJO 并使用Jackson XML 注释或实现JsonSerializable 接口。它可能如下所示:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializable;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

public class XmlMapperApp 

    public static void main(String[] args) throws Exception 
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("Puppy", Boolean.TRUE);
        map.put("Apple", 2);
        map.put("Jet", "Li");
        Examples examples = new Examples();
        examples.setOverlyComplicated("yes");
        examples.setMap(map);

        XmlMapper mapper = new XmlMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);

        ObjectNode rootNode = mapper.createObjectNode();
        rootNode.putPOJO("Examples", examples);
        ObjectNode currentNode = rootNode.putObject("Single");
        currentNode.put("One", 1);

        mapper.writeValue(System.out, rootNode);
    


class Examples implements JsonSerializable 

    @Override
    public void serialize(JsonGenerator gen, SerializerProvider serializers) throws IOException 
        ToXmlGenerator toXmlGenerator = (ToXmlGenerator) gen;
        toXmlGenerator.writeStartObject();

        writeAttributes(toXmlGenerator);
        writeMap(toXmlGenerator);

        toXmlGenerator.writeEndObject();
    

    private void writeAttributes(ToXmlGenerator gen) throws IOException 
        if (overlyComplicated != null) 
            gen.setNextIsAttribute(true);
            gen.writeFieldName("overlyComplicated");
            gen.writeString(overlyComplicated);
            gen.setNextIsAttribute(false);
        
    

    private void writeMap(ToXmlGenerator toXmlGenerator) throws IOException 
        for (Map.Entry<String, Object> entry : map.entrySet()) 
            toXmlGenerator.writeObjectField(entry.getKey(), entry.getValue());
        
    

    @Override
    public void serializeWithType(JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException 
        serialize(gen, serializers);
    

    private String overlyComplicated;
    private Map<String, Object> map;

    // getters, setters, toString

上面的代码打印:

<ObjectNode>
  <Examples overlyComplicated="yes">
    <Puppy>true</Puppy>
    <Apple>2</Apple>
    <Jet>Li</Jet>
  </Examples>
  <Single>
    <One>1</One>
  </Single>
</ObjectNode>

如果您想使用相同的Example POJO 进行JSON 序列化,您需要在serialize 方法中处理它,或者创建另一个ObjectNode 而不是Examlples 对象。

【讨论】:

以上是关于使用 Jackson 将 XML 属性添加到手动构建的节点树的主要内容,如果未能解决你的问题,请参考以下文章

SpringMVC 中使用 @ResponseBody 返回Json时,需要手动添加jackson依赖

使用jackson转换xml格式数据进行响应

Jackson中的JSON属性文件不区分大小写[重复]

使用 jackson-dataformat-xml 库将 XML 中的空标签转换为 java 属性

等效于@JsonIgnore,但仅适用于使用 Jackson 的 xml 字段/属性转换

Jackson XML Annotations:具有属性的字符串元素