XML和JSON是两种经常在网络使用的数据表示格式
XML简介
XML有几个特点:一是纯文本,默认使用UTF-8编码,二是可嵌套,适合表示结构化数据。
XML的结构
XML有固定的结构,首行必定是<?xml version="1.0"?>,可以加上可选的编码。紧接着,如果以类似声明的是文档定义类型(DTD:Document Type Definition),DTD是可选的。接下来是XML的文档内容,一个XML文档有且仅有一个根元素,根元素可以包含任意个子元素,元素可以包含属性,例如,1234567包含一个属性lang=“CN”,且元素必须正确嵌套。如果是空元素,可以用表示。
由于使用了<、>以及引号等标识符,如果内容出现了特殊符号,需要使用&???;表示转义。
小结
XML使用嵌套结构的数据表示方式,支持格式验证;
XML常用于配置文件、网络消息传输等。
使用DOM
XML是一种树形结构的文档,它有两种标准的解析API:
- DOM:一次性读取XML,并在内存中表示为树形结构;(树形结构处理XML结构)
- SAX:以流的形式读取XML,使用事件回调。
对于DOM API解析出来的结构,我们从根节点Document出发,可以遍历所有子节点,获取所有元素、属性、文本数据,还可以包括注释,这些节点被统称为Node,每个Node都有自己的Type,根据Type来区分一个Node到底是元素,还是属性,还是文本,等等。
使用DOM API时,如果要读取某个元素的文本,需要访问它的Text类型的子节点,所以使用起来还是比较繁琐的。
使用SAX
SAX——基于流的解析方式,边读取XML边解析(占用数据小),以事件回调的方式让调用者获取数据
使用SAX API解析XML,Java代码如下
InputStream input = Main.class.getResourceAsStream("/book.xml");
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();
saxParser.parse(input, new MyHandler());
关键代码SAXParser.parse()除了需要传入一个InputStream外,还需要传入一个回调对象,这个对象要继承自DefaultHandler:
class MyHandler extends DefaultHandler {
public void startDocument() throws SAXException {
print("start document");
}
public void endDocument() throws SAXException {
print("end document");
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
print("start element:", localName, qName);
}
public void endElement(String uri, String localName, String qName) throws SAXException {
print("end element:", localName, qName);
}
public void characters(char[] ch, int start, int length) throws SAXException {
print("characters:", new String(ch, start, length));
}
public void error(SAXParseException e) throws SAXException {
print("error:", e);
}
void print(Object... objs) {
for (Object obj : objs) {
System.out.print(obj);
System.out.print(" ");
}
System.out.println();
}
}
使用Jackson
XML解析成一个JavaBean:使用Jackson这个开源第三方库
使用Jackson,先添加两个Maven的依赖:
- com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.10.1
- org.codehaus.woodstox:woodstox-core-asl:4.4.1
然后,定义好JavaBean,就可以用下面几行代码解析:
InputStream input = Main.class.getResourceAsStream("/book.xml");
JacksonXmlModule module = new JacksonXmlModule();
XmlMapper mapper = new XmlMapper(module);//XmlMapper就是核心对象
Book book = mapper.readValue(input, Book.class);//用readValue(InputStream, Class)直接读取XML并返回一个JavaBean
System.out.println(book.id);
System.out.println(book.name);
System.out.println(book.author);
System.out.println(book.isbn);
System.out.println(book.tags);
System.out.println(book.pubDate);
使用JSON
XML这种数据结构的特点是功能全面,但标签繁琐,格式复杂。在Web上使用XML现在越来越少,取而代之的是JSON这种数据结构。一个典型的JSON如下:
JSON作为数据传输的格式,有几个显著特点:
- JSON只允许使用UTF-8编码,不存在编码问题;
- JSON只允许使用双引号作为key,特殊字符用\转义,格式简单;
- 浏览器内置JSON支持,如果把数据用JSON发送给浏览器,可以用JavaScript直接处理。
JSON适合表示层次结构,因为它格式简单,仅支持以下几种数据类型:
键值对:{“key”: value}
数组:[1, 2, 3]
字符串:“abc”
数值(整数和浮点数):12.34
布尔值:true或false
空值:null
浏览器直接支持使用JavaScript对JSON进行读写:
// JSON string to JavaScript object:
jsObj = JSON.parse(jsonStr);
// JavaScript object to JSON string:
jsonStr = JSON.stringify(jsObj);
开发Web应用的时候,使用JSON作为数据传输,在浏览器端非常方便。
常用的用于解析JSON的第三方库有:Jackson、Gson、Fastjson等
Jackson也可以解析JSON!只需要引入以下Maven依赖:
com.fasterxml.jackson.core:jackson-databind:2.10.0
就可以使用下面的代码解析一个JSON文件:
InputStream input = Main.class.getResourceAsStream("/book.json");
ObjectMapper mapper = new ObjectMapper();//核心代码是创建一个ObjectMapper对象
// 反序列化时忽略不存在的JavaBean属性:
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);//解析时如果JavaBean不存在该属性时解析不会报错
Book book = mapper.readValue(input, Book.class);
把JSON解析为JavaBean的过程称为反序列化。如果把JavaBean变为JSON,那就是序列化。要实现JavaBean到JSON的序列化,只需要一行代码:
String json = mapper.writeValueAsString(book);
要把JSON的某些值解析为特定的Java对象,例如LocalDate,也是完全可以的。例如:
{
“name”: “Java核心技术”,
“pubDate”: “2016-09-01”
}
要解析为:
public class Book {
public String name;
public LocalDate pubDate;
}
只需要引入标准的JSR 310关于JavaTime的数据格式定义至Maven:
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.0
然后,在创建ObjectMapper时,注册一个新的JavaTimeModule:
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
有些时候,内置的解析规则和扩展的解析规则如果都不满足我们的需求,还可以自定义解析。