使用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

相关依赖

xml 复制代码
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
        </dependency>

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

jackson工具类

java 复制代码
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数据

xml 复制代码
<root>
    <id>1001</id>
    <name>test</name>
    <node>
        <test1>test1</test1>
        <test2>test2</test2>
    </node>
</root>

实体类

java 复制代码
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;
}
java 复制代码
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转为对象

java 复制代码
    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);
    }

输出

txt 复制代码
XmlDataBo(id=1001, name=test, testBo=XmlDataTestBo(Test1=test1, Test2=test2))

对象转为xml

java 复制代码
        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);
txt 复制代码
<root><id>1001</id><name>test</name><node><test2>test2</test2><test1>test1</test1></node></root>

xml和List相互转换

xml数据

java 复制代码
<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 >

java 复制代码
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 >

java 复制代码
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 >

java 复制代码
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

java 复制代码
        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);

输出

java 复制代码
<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

java 复制代码
        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);

输出

txt 复制代码
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实体类

java 复制代码
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;

}

测试

java 复制代码
    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);
    }

输出

txt 复制代码
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 时,表示列表或数组被包裹在一个额外的元素中。例如以上代码中:
xml 复制代码
<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标签中。

所以在取值时代码:

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

所以在取值时代码:

java 复制代码
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "info")
    private List<XmlDataInfoBo> infoBos;

总结

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

列表或数组没有被包裹在额外的元素中时,选择useWrapping = false。


相关推荐
Monly21几秒前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
Ttang233 分钟前
Tomcat原理(6)——tomcat完整实现
java·tomcat
goTsHgo4 分钟前
在 Spring Boot 的 MVC 框架中 路径匹配的实现 详解
spring boot·后端·mvc
钱多多_qdd14 分钟前
spring cache源码解析(四)——从@EnableCaching开始来阅读源码
java·spring boot·spring
waicsdn_haha16 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
飞的肖24 分钟前
前端使用 Element Plus架构vue3.0实现图片拖拉拽,后等比压缩,上传到Spring Boot后端
前端·spring boot·架构
Q_192849990626 分钟前
基于Spring Boot的摄影器材租赁回收系统
java·spring boot·后端
Code_流苏28 分钟前
VSCode搭建Java开发环境 2024保姆级安装教程(Java环境搭建+VSCode安装+运行测试+背景图设置)
java·ide·vscode·搭建·java开发环境
良许Linux30 分钟前
0.96寸OLED显示屏详解
linux·服务器·后端·互联网
求知若饥43 分钟前
NestJS 项目实战-权限管理系统开发(六)
后端·node.js·nestjs