背景
现在大多数应用都是使用 JSON 作为数据传输的方式。但是也有其他形式的数据存在,比如 XML。本文就是我遇到的需求:把老系统返回的 XML 封装为实体类返给前台。
思考步骤
- JSON 操作类库很多,但是选用哪一个?
- 如何将 XML 转为 JSON 串?
- 如何将 JSON 串转为实体类
XML 转 JSON 串
jackson
为什么先介绍 jackson:这是创建 SpringBoot 项目,里面就会自带的 json 解析库。
刚开始的返参很简单,没有包含 List 之类,所以 jackson 类库就完全足够
public class JacksonTest {
public static void main(String[] args) throws IOException {
String xmlStr = "<ROOT><ErrorMessage>14</ErrorMessage><student><name>Ncharming</name><age>23</age></student></ROOT>";
ObjectMapper objectMapper = new ObjectMapper();
ObjectMapper xmlMapper = new XmlMapper();
// 将 xml 串转为 JsonNode
JsonNode jsonStr = xmlMapper.readTree(xmlStr);
//获取 json String 串转为对应的实体类
Student student = objectMapper.readValue(jsonStr.get("student").toString(), Student.class);
System.out.println(objectMapper.writeValueAsString(student));
}
}
相同的节点会被最后一个节点覆盖。
String xmlStr = "<ROOT><ListStudent><student><name>Ncharming</name><age>23</age></student><student><name>charming</name><age>24</age></student></ListStudent></ROOT>";
ObjectMapper objectMapper = new ObjectMapper();
ObjectMapper xmlMapper = new XmlMapper();
JsonNode jsonStr = xmlMapper.readTree(xmlStr);
System.out.println(jsonStr);
//outPut:{"ListStudent":{"student":{"name":"charming","age":"24"}}}
所以,不用 jackson 类库来实现。
org.json
会完整的把 XML 转为 JSON 串,但是过于完整
public class OrgJsonTest {
public static void main(String[] args) {
String xmlStr = "<ROOT><student><name>Ncharming</name><age>23</age></student><student><name>charming</name><age>24</age></student></ROOT>";
String jsonStr = XML.toJSONObject(xmlStr).toString();
System.out.println(jsonStr);
}
}
// outPut:{"ROOT":{"student":[{"name":"Ncharming","age":23},{"name":"charming","age":24}]}}
为什么说过于完整:
String complexStr = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><student><name>Ncharming</name><age>23</age></student></soap:Envelope>";
//outPut:{"soap:Envelope":{"student":{"name":"Ncharming","age":23},"xmlns:soap":"http://schemas.xmlsoap.org/soap/envelope/"}}
当想把 XML 串转为 json 串的时候,可以用 org.json 类库实现:
- 速度快
- 会把相同的节点转换为 一个Array 而不会覆盖
json-lib
网上说需要自己加入很多库,但是经过我自己测试,直接在maven库找到最新的 pom ,加入到你的项目即可。
<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
</dependency>
不过只是上面的还不能,必须加上:
<classifier>jdk15</classifier>
long s = System.currentTimeMillis();
XMLSerializer xmlSerializer = new XMLSerializer();
JSON jsonStr = xmlSerializer.read(complexXmlStr);
System.out.println(System.currentTimeMillis() - s + "," + jsonStr.toString());
测试数据可以完整转换,但是时间相对很慢,所以舍弃。
自己实现
参考链接
速度比起 org.json 大概慢了 3-4 倍,这只是我随便找的一段 XML 进行的测试
JSON 串转实体类
fastjson
fastjson WIKI
首先 fastjson 不支持 XML 转 JSON ,因为专注于 JSON 操作;
其次,宣称是 Java 实现的 JSON 类库中,性能NO.1。
我们在引用类库的时候或者一个新技术的时候,应该从全局判定,而不是某一个方面。在这里 fastjson 完全满足我的需求,并且不会因为他的一些缺点而带来困扰,所以我在项目中使用 fastjson。
public class FastjsonTest {
public static void main(String[] args) {
String jsonStr = "{\"student\":{\"name\":\"Ncharming\",\"age\":23}}";
JSONObject jsonObject = JSONObject.parseObject(jsonStr);
String stuStr = jsonObject.getJSONObject("student").toString();
Student student = JSON.parseObject(stuStr, Student.class);
System.out.println(student);
// 如果 stuStr 串是一个 array 类型,那么使用如下的语句
// List<Student> jsonArray = JSONObject.parseArray(stuStr,Student.class);
}
}
问题 :
我们返回的数据,可能是一个 array,也可能就是一个 Object,此时怎么办?
public class FastjsonTest {
public static void main(String[] args) {
String jsonStr = "{\"student\":{\"name\":\"Ncharming\",\"age\":23}}";
JSONObject jsonObject = JSONObject.parseObject(jsonStr);
Object stuObject = jsonObject.get("student");
//当我们不知道 student 节点返回的是 array 还是 object
if (stuObject instanceof JSONArray) {
List<Student> infoList = JSONObject.parseArray(stuObject.toString(), Student.class);
//返给前台 Resp.setInfoList()
} else {
Student infoList = JSON.parseObject(stuObject.toString(), Student.class);
//返给前台 Resp.setInfo()
}
/**
* 如上所见,我们对 student 节点类型进行了判断,分两种操作,这样可以解决 array 还是 object 的问题。
* 但是引入了新问题:我们在 Resp.set 的时候,会返回到两个字段下面
* 一旦返回到前端,当时一条数据的时候,Info 下面有值;多条数据的时候 InfoList 下面有值
* 我们整合到一起,不管几条数据,都返回到一个字段下面去。
*/
//解决方案,把 object 先添加到 array 中即可
if (stuObject instanceof JSONArray) {
List<Student> infoList = JSONObject.parseArray(stuObject.toString(), Student.class);
//返给前台 Resp.setInfoList()
} else {
JSONArray jsonArray = new JSONArray();
jsonArray.add(stuObject);
List<Student> infoList = JSONObject.parseArray(jsonArray.toString(), Student.class);
//返给前台 Resp.setInfoList()
}
}
}
总结
JSON类库 | 本身 | XML转 JSON | JSON 转实体类 |
---|---|---|---|
jackson | spring-boot-starter-web包中自带的 JSON 库 | XmlMapper#readTree()相同节点会被覆盖,只会保留最后一个节点的内容 | XmlMapper#readValue() 可以转换 |
org.json | 本身方法很少,也不是特别常用 | 1.速度快 2.转换过于完整 | 类库中没有方法支持 |
fastjson | 阿里开源的一个类库 | 不支持,只专注于 JSON 操作 | parseObject()、parseArray () 两个方法转为实体类要灵活运用 |
1.当然市面上还有其他很多的 JSON 类库,我这里不多介绍,比如 Gson 等。
2.本文引用了别人自己写的将 XML 转 JSON 的方法,但是效率没有类库来的高,而且也比较麻烦。
3.所有的类库包都可以通过 Maven仓库下载