XML是可扩展标记语言(eXtensible Markup Language)的缩写,它是是一种数据表示格式,可以描述非常复杂的数据结构,常用于传输和存储数据。
例如,一个描述书籍的XML文档可能如下:
XML有几个特点:
一是纯文本,默认使用UTF-8编码,
二是可嵌套,适合表示结构化数据。
XML有固定的结构,
首行必定是 <?xml version="1.0"?> ,可以加上可选的编码。
接下来是XML的文档内容,一个XML文档有且仅有一个根元素,根元素可以包含任意个子元素,元素可以包含属性,例如, <isbn lang="CN">1234567</isbn>包含一个属性lang="CN",且元素必须正确嵌套。如果是空元素,可以用 <tag/> 表示。
由于使用了<、>以及引号等标识符,如果内容出现了特殊符号,需要使用&???;表示转义。例如,Java<tm>必须写成:
常见的特殊字符如下:
格式正确的XML(Well Formed)是指XML的格式是正确的,可以被解析器正常读取。
合法的XML是指,不但XML格式正确,而且它的数据结构可以被DTD或者XSD验证。(结构正确、数据有效)
XML是一种树形结构的文档,它有两种标准的解析API:
如何使用DOM来读取XML:
DOM是Document Object Model的缩写,DOM模型就是把XML结构作为一个树形结构处理,从根节点开始,每个节点都可以包含任意个子节点。
最顶层的document代表XML文档,它是真正的“根”
<book>是根元素,但它是document的一个子节点
Java提供了DOM API来解析XML,它使用下面的对象来表示XML的内容:
使用DOM API解析一个XML文档的代码如下:
解析结构如下:
对于DOM API解析出来的结构,我们从根节点Document出发,可以遍历所有子节点,获取所有元素、属性、文本数据,还可以包括注释,
这些节点被统称为Node,每个Node都有自己的Type,根据Type来区分一个Node到底是元素,还是属性,还是文本,等等。
使用DOM API时,如果要读取某个元素的文本,需要访问它的Text类型的子节点,所以使用起来还是比较繁琐的。
DOM解析XML的优点是用起来省事,但主要缺点是内存占用太大。
另一种解析XML的方式是SAX。SAX是Simple API for XML的缩写,它是一种基于流的解析方式,边读取XML边解析,并以事件回调的方式让调用者获取数据。因为是一边读一边解析,所以无论XML有多大,占用的内存都很小。
SAX解析会触发一系列事件:
如果我们用SAX API解析XML,Java代码如下:
运行SAX解析代码,可以打印出下面的结果:
如果要读取 <name> 节点的文本,我们就必须在解析过程中根据startElement()和endElement()定位当前正在读取的节点,可以使用栈结构保存,每遇到一个startElement()入栈,每遇到一个endElement()出栈,这样,读到characters()时我们才知道当前读取的文本是哪个节点的。可见,使用SAX API仍然比较麻烦。
XML文档的结构:
我们发现,它完全可以对应到一个定义好的JavaBean中:
如果能直接从XML文档解析成一个JavaBean,那比DOM或者SAX不知道容易到哪里去了。
幸运的是,一个名叫Jackson的开源的第三方库可以轻松做到XML到JavaBean的转换。我们要使用Jackson,先添加两个Maven的依赖:
然后,定义好JavaBean,就可以用下面几行代码解析:
注意到XmlMapper就是我们需要创建的核心对象,可以用readValue(InputStream, Class)直接读取XML并返回一个JavaBean。运行上述代码,就可以直接从Book对象中拿到数据:
JSON是JavaScript Object Notation的缩写,它去除了所有JavaScript执行代码,只保留JavaScript的对象格式。一个典型的JSON如下:
JSON作为数据传输的格式,有几个显著的优点:
因此,JSON适合表示层次结构,因为它格式简单,仅支持以下几种数据类型:
浏览器直接支持使用JavaScript对JSON进行读写:
所以,开发Web应用的时候,使用JSON作为数据传输,在浏览器端非常方便。因为JSON天生适合JavaScript处理,所以,绝大多数REST API都选择JSON作为数据传输格式。
常用的用于解析JSON的第三方库有:
入以下Maven依赖:
就可以使用下面的代码解析一个JSON文件:
要实现JavaBean到JSON的序列化,只需要一行代码:
假设Book类的isbn是一个BigInteger:
但JSON数据并不是标准的整形格式:
直接解析,肯定报错。这时,我们需要自定义一个IsbnDeserializer,用于解析含有非数字的字符串:
然后,在Book类中使用注解标注:
类似的,自定义序列化时我们需要自定义一个IsbnSerializer,然后在Book类中标注@JsonSerialize(using = ...)即可。