Jackson 是一个广泛使用的 JSON 处理库,但在处理 XML 数据时,Jackson 也提供了相应的支持。虽然 Jackson 的主要用途是处理 JSON 数据,但通过在pom.xml中引入jackson-dataformat-xml 模块,可以很方便地将 Java 对象序列化为 XML 文档或将 XML 文档反序列化为 Java 对象。
<dependency>
<groupId>com.fasterxml.jackson.dataformatgroupId>
<artifactId>jackson-dataformat-xmlartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
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
* @return
* @throws IOException
*/
public static <T> T toXmlObject(String xml, Class<T> clazz) throws IOException {
XmlMapper mapper = getXmlSingleton();
return mapper.readValue(xml, clazz);
}
}
<root>
<id>1001id>
<name>testname>
<node>
<test1>test1test1>
<test2>test2test2>
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;
}
public static void main(String[] args) throws IOException {
String xmlStr = "1001 test test1 test2 ";
// 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))
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);
1001 test test2 test1
<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;
}
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>
String xmlStr = "1001 test zs 18 男 ls 19 女 ";
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=女)]))
也可以直接从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 = "1001 test zs 18 男 ls 19 女 ";
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 注解用于指定列表或数组属性在 XML 中的包装元素。useWrapping 参数控制是否使用额外的包装元素来包裹列表或数组。
<root>
<node>
<info>
<name>zsname>
<age>18age>
<sex>男sex>
info>
<info>
<name>lsname>
<age>19age>
<sex>女sex>
info>
node>
root>
在这个例子中,info标签被包裹在node标签中。
所以在取值时代码:
@JacksonXmlElementWrapper(useWrapping = true )
@JacksonXmlProperty(localName = "node")
private List<XmlDataInfoBo> infoBos;
<root>
<info>
<name>zsname>
<age>18age>
<sex>男sex>
info>
<info>
<name>lsname>
<age>19age>
<sex>女sex>
info>
root>
所以在取值时代码:
@JacksonXmlElementWrapper(useWrapping = false)
@JacksonXmlProperty(localName = "info")
private List<XmlDataInfoBo> infoBos;
当列表或数组会被包裹在一个额外的元素中或想直接从父标签拿子标签列表时,选择useWrapping = true。
列表或数组没有被包裹在额外的元素中时,选择useWrapping = false。