在实际项目开发过程中,尤其是web项目的开发,我们或多或少会使用XML格式的数据进行数据交换;即使自己的项目用不到,但和第三方接口对接时,也是会经常遇到用XML格式数据的第三方接口,因为XML是标准通用标记语言 (SGML) 的子集,非常适合 Web 传输。所以对XML数据的处理是必须要掌握的。
下面就手把手拿一个真实的接口对接案例来教你们如何处理这类数据,耐心看下去。
就拿项目中遇到的一个第三方对接需求来说,这个第三方接口使用的就是XML格式的数据,而且字段多,结构复杂,把这个搞定再遇到类似情况都能从容应对了。
首先我们先看这个接口第三方给我们的文件
可以看到这是一个非常标准化的接口文件,有接口文档,有各个接口的数据规范及统一的结果返回规范。
我们随便打开一个接口的文件夹
可以看到里面是有三个文件:(1).接口数据表格 (2).XML文件 (3).XSD文件
xml文件就是该接口数据的xml格式,xsd简单来说就是用来描述文档结构的,用来验证xml格式是否符合该接口规范,这个后续也会讲到。
再来看接口文档
接口文档里也明确表示当我们请求第三方接口时,发送的xml数据必须符合这个XSD的规范,所以我们在写完数据处理代码后必须用XSD验证我们的xml格式是否正确
下面开始介绍如何处理XML数据。我们对XML数据的处理无非就是XML转JSON、JSON转XML,在转换过程中需要用到一些注解,下面以XML转对象为例,结合在项目中创建接口数据对象时如何与XML相关数据一 一对应来介绍这些注解
小技巧: 为了更方便的理解对应关系,在拿到XML数据后先将该xml数据在线简单转json然后对照着来找对应关系,打开一个JSON在线解析网站JSON在线解析,将xml完整复制上去解析成json格式,右边就是我们熟悉的JSON格式,这个xml数据格式我们就大概看出来了
@JacksonXmlRootElement(localName = "字段名")
@JacksonXmlProperty(localName = "字段名")
@JacksonXmlElementWrapper(useWrapping = false)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@TableField(exist = false)
这些注解大部分属于Jackson常用注解,所以要用到这些注解需要引入Jackson以及其他一些相关依赖。
<!-- 序列化-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-bom.version}</version>
</dependency>
<!-- xml转换-->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
<version>5.1.0</version>
</dependency>
这个注解是用在指定XML根元素节点标签的名称,根元素就是XML最外层的那个元素,如下图
这个注解是指定XML命名空间的名称,可以简单理解为数据字段或对象要加的注解,如下图,不管是对象或者字段,都可以用这个注解来对应
这个注解是集合元素的映射,可以将列表数据转为XML节点,可以理解为列表字段需要额外加的一个注解,如下(前面的@JacksonXmlProperty注解依然要带上,别忘了)
这个注解比较特殊,是用于排除某个属性,这样该属性就不会被Jackson序列化和反序列化。比如你在把xml数据转换为java对象之后,你要把这些数据存到数据库里,然后你要加上id、create_time等字段,这些字段在xml数据里没有,那你就要加上这个注解,不然字段对应不上在转换的时候会报错
这个注解本来不想加上的,因为这是mybatis-plus需要用到的注解,但既然写的详细一点就加上吧,这个注解申明此字段不在数据库存在,但代码中需要用到它,通知Mybatis-plus在做写库操作时忽略它。比如 id、crete_time、update_time这些字段本地数据库里有,但是接口的数据交互中不需要,那就得加上这个注解,这样在xml转换过程中就可以忽略这些字段
通过前面对注解的使用,我们已经在本地服务创建好对应xml结构的对象了,那么接下来是如何进行转换。首先xml数据可以用String类型来接收,拿到xml数据之后就可以转换了
/**
* xml转对象方法(报错时打印日志)
* @param po
* @return
*/
public static 本地对象 xmlToObject(Object po, String xml) throws JsonProcessingException {
ObjectMapper mapper = new XmlMapper();
po = mapper.readValue(xml, 本地对象.class);
本地对象 = Convert.convert(本地对象.class,po);
return 本地对象;
}
这样就将xml数据转换成对应对象格式数据了,就进入你熟悉的领域了
//ObjectMapper:writeValueAsString 方法可将传入的对象序列化为JSON字符串
ObjectMapper mapper = new XmlMapper();
//一定要加上xml版本和编码信息,组成完整的xml数据
String xml = "" + mapper.writeValueAsString(本地对象);
这里需要注意一点,转换结果是不含xml版本和编码信息的,一定要像我这样加上,不然是不完整的xml信息,如果不知道加什么,可以直接复制接口的xml版本和编码信息
1.在xml转对象过程中,你本地建的数据结构和xml中有对不上的地方控制台一般都会输出报错位置和原因,这个能解决大部分问题
2.有时候你接收到的xml数据是没有填满的数据(有很多字段是空的),这就导致有的字段或者结构在你本地没有创建的情况下,你依然转换成功了,所以我们本地新建完结构后要再对照着接口文件里的字段表格看看有没有遗漏的,
3.在上述问题都验证完后,还可以通过XSD来验证xml完整性
/**
* 利用XSD测试xml格式是否正确
* 如果不用文件类型来测试的话,可以加上 xml、xsd转文件格式来写
*/
public class demo {
public static void main(String[] args) {
boolean a = false;
try {
//第一个参数放入你的xsd文件,第二个你的xml文件,就会调用方法去验证
//如何不符合规范,就会报错,符合就会输出true成功
a = Validatexml("XSD文件在你电脑上的地址", "XML文件在你电脑上的地址");
} catch (SAXException e) {
a = false;
System.out.println("sax错误,验证不通过");
e.printStackTrace();
} catch (IOException e) {
a = false;
System.out.println("io错误,验证不通过");
e.printStackTrace();
}
System.out.println(a);
}
public static boolean Validatexml(String xsdpath, String xmlpath) throws SAXException, IOException {
//建立schema工厂
SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
//建立验证文档文件对象,利用此文件对象所封装的文件进行schema验证
File schemaFile = new File(xsdpath);
//利用schema工厂,接收验证文档文件对象生成Schema对象
Schema schema = schemaFactory.newSchema(schemaFile);
//通过Schema产生针对于此Schema的验证器,利用schenaFile进行验证
Validator validator = schema.newValidator();
//得到验证的数据源
Source source = new StreamSource(xmlpath);
//开始验证,成功输出success!!!,失败输出fail
validator.validate(source);
return true;
}