使用jackson将xml和对象、List相互转换


Jackson Xml

Jackson 是一个广泛使用的 JSON 处理库,但在处理 XML 数据时,Jackson 也提供了相应的支持。虽然 Jackson 的主要用途是处理 JSON 数据,但通过在pom.xml中引入jackson-dataformat-xml 模块,可以很方便地将 Java 对象序列化为 XML 文档或将 XML 文档反序列化为 Java 对象。

常用注解

  • @JacksonXmlRootElement:定义Xml根元素,默认使用类的SimpleName
  • @JacksonXmlProperty:指定属性名称,以及属性是否被写成一个XML元素或属性
  • @JacksonXmlElementWrapper:允许指定用于包装List和Map属性的XML元素。类似JAXB的@XmlElementWrapper
  • @JacksonXmlCData:允许指定一个属性的值被序列化在一个CData标签中

常用的配置属性

  • SerializationFeature.INDENT_OUTPUT:是否格式化输出,默认false
  • SerializationFeature.WRITE_DATES_AS_TIMESTAMPS:日期写为时间戳,默认true
  • MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES:反序列化忽略大小写,默认false
  • DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES:反序列化时,未知字段是否直接失败,默认true

相关依赖

        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

jackson工具类

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

import java.io.IOException;

/**
 * @author qf
 * @since 2024/09/11 19:04
 */
public class JacksonXmlUtil {
    private static class SingletonHolder {
        private static XmlMapper xmlMapper = new XmlMapper();
        static {
            // 在构造器中进行配置
            //反序列化的时候如果多了其他属性,不抛出异常
            xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        }
    }

    public static XmlMapper getXmlSingleton() {
        XmlMapper mapper = SingletonHolder.xmlMapper;
        return mapper;
    }

    /**
     * 对象转xml
     *
     * @param obj
     * @return
     * @throws JsonProcessingException
     */
    public static String toXml(Object obj) throws JsonProcessingException {
        ObjectMapper mapper = getXmlSingleton();
        return mapper.writeValueAsString(obj);
    }


    /**
     * xml转为对象
     *
     * @param xml
     * @param clazz
     * @param <T>
     * @return
     * @throws IOException
     */
    public static <T> T toXmlObject(String xml, Class<T> clazz) throws IOException {
        XmlMapper mapper = getXmlSingleton();
        return mapper.readValue(xml, clazz);
    }
}

xml和对象相互转换

xml数据

<root>
    <id>1001</id>
    <name>test</name>
    <node>
        <test1>test1</test1>
        <test2>test2</test2>
    </node>
</root>

实体类

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;

import java.util.List;

/**
 * @author qf
 * @since 2024/09/11 19:06
 */
@Data
@JacksonXmlRootElement(localName = "root")
public class XmlDataBo {

    @JacksonXmlProperty(localName = "id")
    private Long id;

    @JacksonXmlProperty(localName = "name")
    private String name;

    @JacksonXmlProperty(localName = "node")
    private XmlDataTestBo testBo;
}
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;

/**
 * @author qf
 * @since 2024/09/10 19:42
 */
@Data
@JacksonXmlRootElement(localName = "node")
public class XmlDataTestBo {
    @JacksonXmlProperty(localName = "test1")
    private String Test1;
    @JacksonXmlProperty(localName = "test2")
    private String Test2;
}

xml转为对象

    public static void main(String[] args) throws IOException {
        String xmlStr = "<root><id>1001</id><name>test</name><node><test1>test1</test1><test2>test2</test2></node></root>";
//        XmlDataBo xmlBo = JacksonXmlUtil.toXmlObject(xmlStr, XmlDataBo.class);
        XmlMapper xmlMapper = new XmlMapper();
        xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        XmlDataBo xmlBo = xmlMapper.readValue(xmlStr, XmlDataBo.class);
    }

输出

XmlDataBo(id=1001, name=test, testBo=XmlDataTestBo(Test1=test1, Test2=test2))

对象转为xml

        XmlDataTestBo testBo = new XmlDataTestBo();
        testBo.setTest1("test1");
        testBo.setTest2("test2");
        XmlDataBo xmlDataBo = new XmlDataBo();
        xmlDataBo.setId(1001L);
        xmlDataBo.setName("test");
        xmlDataBo.setTestBo(testBo);
        String xml = JacksonXmlUtil.toXml(xmlDataBo);
        System.out.println(xml);
<root><id>1001</id><name>test</name><node><test2>test2</test2><test1>test1</test1></node></root>

xml和List相互转换

xml数据

<root>
    <id>1001</id>
    <name>test</name>
    <node>
        <info>
            <name>zs</name>
            <age>18</age>
            <sex></sex>
         </info>
         <info>
            <name>ls</name>
            <age>19</age>
            <sex></sex>
         </info>
    </node>
</root>

实体类

根标签 < root >

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;

/**
 * @author qbh
 * @since 2024/09/10 19:25
 */
@Data
@JacksonXmlRootElement(localName = "root")
public class XmlDataBo {

    @JacksonXmlProperty(localName = "id")
    private Long id;

    @JacksonXmlProperty(localName = "name")
    private String name;

    @JacksonXmlProperty(localName = "node")
    private XmlDataTestBo testBo;

}

node标签< node >

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;

import java.util.List;

/**
 * @author qf
 * @since 2024/09/10 18:42
 */
@Data
@JacksonXmlRootElement(localName = "node")
public class XmlDataTestBo {
//    @JacksonXmlProperty(localName = "test1")
//    private String Test1;
//    @JacksonXmlProperty(localName = "test2")
//    private String Test2;

    /**
     * JacksonXmlElementWrapper注解用于指定列表或数组属性在XML中的包装元素,以提供更好的结构化层次和语义意义。
     *  当useWrapping = true:列表或数组会被包裹在一个额外的元素中。
     *  当useWrapping = false:列表或数组不会被包裹在额外的元素中。
     */
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "info")
    private List<XmlDataInfoBo> infoBos;
}

info标签 < info >

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.lang.ref.PhantomReference;

/**
 * @author qf
 * @since 2024/09/10 19:27
 */
@NoArgsConstructor
@AllArgsConstructor
@Data
@JacksonXmlRootElement(localName = "info")
public class XmlDataInfoBo {

    @JacksonXmlProperty(localName = "name")
    private String name;

    @JacksonXmlProperty(localName = "age")
    private Integer age;

    @JacksonXmlProperty(localName = "sex")
    private String sex;
}

List转xml

        XmlDataBo xmlDataBo = new XmlDataBo();
        xmlDataBo.setId(1001L);
        xmlDataBo.setName("test");
        List<XmlDataInfoBo> infoBos = new ArrayList<>();
        infoBos.add(new XmlDataInfoBo("zs", 18, "男"));
        infoBos.add(new XmlDataInfoBo("ls", 19, "女"));
        XmlDataTestBo testBo = new XmlDataTestBo();
        testBo.setInfoBos(infoBos);
        xmlDataBo.setTestBo(testBo);
        String xml = JacksonXmlUtil.toXml(xmlDataBo);
        System.out.println(xml);

输出

<root><id>1001</id><name>test</name><node><info><name>zs</name><age>18</age><sex></sex></info><info><name>ls</name><age>19</age><sex></sex></info></node></root>

xml转List

方法1

        String xmlStr = "<root><id>1001</id><name>test</name><node><info><name>zs</name><age>18</age><sex>男</sex></info><info><name>ls</name><age>19</age><sex>女</sex></info></node></root>";
        XmlDataBo xmlDataBo = JacksonXmlUtil.toXmlObject(xmlStr, XmlDataBo.class);
        System.out.println(xmlDataBo);

输出

XmlDataBo(id=1001, name=test, testBo=XmlDataTestBo(infoBos=[XmlDataInfoBo(name=zs, age=18, sex=男), XmlDataInfoBo(name=ls, age=19, sex=女)]))

方法2

也可以直接从node标签中拿取列表(跳过node标签直接拿列表info)
修改root实体类

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;

import java.util.List;

/**
 * @author qbh
 * @since 2024/09/10 17:25
 */
@Data
@JacksonXmlRootElement(localName = "root")
public class XmlDataBo {

    @JacksonXmlProperty(localName = "id")
    private Long id;

    @JacksonXmlProperty(localName = "name")
    private String name;

//    @JacksonXmlProperty(localName = "node")
//    private XmlDataTestBo testBo;

    @JacksonXmlElementWrapper(useWrapping = true )
    @JacksonXmlProperty(localName = "node")
    private List<XmlDataInfoBo> infoBos;

}

测试

    public static void main(String[] args) throws IOException {
        String xmlStr = "<root><id>1001</id><name>test</name><node><info><name>zs</name><age>18</age><sex>男</sex></info><info><name>ls</name><age>19</age><sex>女</sex></info></node></root>";
        XmlDataBo xmlDataBo = JacksonXmlUtil.toXmlObject(xmlStr, XmlDataBo.class);
        System.out.println(xmlDataBo);
    }

输出

XmlDataBo(id=1001, name=test, infoBos=[XmlDataInfoBo(name=zs, age=18, sex=男), XmlDataInfoBo(name=ls, age=19, sex=女)])

@JacksonXmlElementWrapper 的 useWrapping 参数区别

@JacksonXmlElementWrapper 注解用于指定列表或数组属性在 XML 中的包装元素。useWrapping 参数控制是否使用额外的包装元素来包裹列表或数组。

  1. useWrapping = true (默认)
    当 useWrapping = true 时,表示列表或数组被包裹在一个额外的元素中。例如以上代码中:
<root>
    <node>
        <info>
            <name>zs</name>
            <age>18</age>
            <sex></sex>
         </info>
         <info>
            <name>ls</name>
            <age>19</age>
            <sex></sex>
         </info>
    </node>
</root>

在这个例子中,info标签被包裹在node标签中。
所以在取值时代码:

    @JacksonXmlElementWrapper(useWrapping = true )
    @JacksonXmlProperty(localName = "node")
    private List<XmlDataInfoBo> infoBos;
  1. useWrapping = false
    当 useWrapping = false 时,表示列表或数组没有被包裹在额外的元素中。例如以上代码中:
<root>
     <info>
         <name>zs</name>
         <age>18</age>
         <sex></sex>
      </info>
      <info>
         <name>ls</name>
         <age>19</age>
         <sex></sex>
      </info>
</root>

所以在取值时代码:

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "info")
    private List<XmlDataInfoBo> infoBos;

总结

当列表或数组会被包裹在一个额外的元素中或想直接从父标签拿子标签列表时,选择useWrapping = true。
列表或数组没有被包裹在额外的元素中时,选择useWrapping = false。


  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值