现在的软件项目都不是独立的一个项目,都是多系统协调工作。这样的话就涉及到系统间的通讯,通讯就会跟报文传输挂上关系。系统间使用怎样的报文格式进行通讯呢?有的使用固定长度格式报文;有的使用变长格式报文;有的使用 XML 格式报告。本分享主要和大家分享一下 XML 格式报文的解析。
Java 是一个开源的语言,本文将给大家介绍一下常用的 XML 解析框架及特点。
XML 的简介及一些常见概念
Java 内置解析 XML API: DOM、SAX
XML 解析框架 JDOM
XML 解析框架 DOM4J
XML 解析框架 XStream
总结
XML 的简介及一些常见概念
XML 的概念
XML 是 Extensible Markup Language 简称,中文翻译为可扩展标记语言。XML 是一种通用的数据交换格式,它的平台无关性、语言无关性、系统无关性,给数据集成与交互带来了极大的方便。XML 在不同的语言环境中解析方式都是一样的,只不过实现的语法不同而已。
XML 可用来描述数据、存储数据、传输数据/交换数据。
XML 文档节点的类型主要有:
document:文档,代表整个文档(DOM 树的根节点);
element:元素,表示一个元素;
PCDATA(Parsed Character Data):文本;
comment:注释,代表一个注释;
DOCTYPE:主要验证文档内容的正确性;
ENTITIES:实体;
CDATA(Character Data):代表文档中的 CDATA 区段,文本不会被解析器解析。
XML 的基本语法
在使用过程中,请记住以下几个基本语法。
声明格式,如下:
<?xml version="1.0" encoding="UTF-8"?>
根节点:必须有一个根节点。
属性:必须使用引号引起值。
空格会被保留。
命名规则:命名必须见名知意。
名字可包含字母、数字以及其他的字符。
名字不能以数字或者标点符号开始。
名字不能以字符“xml”(或者 XML、Xml)开始。
名字不能包含空格。
不应在 XML 元素名称中使用“:” ,这是由于它用于命名空间(NameSpaces)的保留字。
XML 命名空间可提供避免元素命名冲突的方法。
CDATA:字符数据,<![CDATA[字符数据]]>,字符数据不进行转义。
实体:使用方式为“&实体;”,XML 中有5个预定义的实体,如下表所示。
XML 约束注释:在 XML 中,只有字符 "<" 和 "&" 确实是非法的。大于号是合法的,但是用实体引用来代替它是一个好习惯。
1.XML DTD 约束
DTD 是 DocType Definition 的简称,中文翻译为文档类型定义,DTD 的作用是定义 XML 文档的合法构建模块。它使用一系列的合法元素来定义文档结构,用于约定 XML 的格式。规定了文档中所使用的元素、实体、元素的属性、元素与实体之间的关系。
DTD主要作用有:
使用 DTD 可以提供一种统一的格式。
XML 的可扩展性为文档的作者提供了很高的灵活性,可有时候需要的是统一,要求某一类文档具有相同的结构。
使用 DTD 可以保证数据交流和共享的顺利进行。
DTD 使用户能够不依赖具体的数据就知道文档的逻辑结构。
在没有 XML 文档的时候,也可以根据 DTD 为 XML 文档编写样式单,编写处理程序,这样可以有效地提高工作效率。
使用 DTD 可以验证数据的有效性。
DTD 对文档的逻辑结构进行了约束,这种约束可以比较宽松,也可以十分严格。可以根据 DTD 检查数据,以验证其是否符合规定和要求,这可以保证数据的正确和有效。
DTD 主要定义方式:
<!DOCTYPE 根元素 [元素声明]>
请看下面的例子,book.xml:
"UTF-8" ?> <!DOCTYPE bookstore [ <!ELEMENT bookstore (book+)> <!ELEMENT book (bookname,author,price)> <!ATTLIST book id CDATA #required> <!ELEMENT bookname (#PCDATA)> <!ELEMENT author (#PCDATA)> <!ELEMENT price (#PCDATA)> ]> <bookstore> <book> <bookname>带你飞培训教程</bookname> <author>huangjinjin</author> <price>1.00元</price> </book> <book> <bookname>降龙十八讲秘籍</bookname> <author>洪七公</author> <price>0.01元</price> </book> </bookstore>
(2)外部定义,请看下面这个例子。
bookstore.dtd:
?>
<!DOCTYPE bookstore [ <!ELEMENT bookstore (book+)> <!ELEMENT book (bookname,price)> <!ATTLIST book id CDATA #required> <!ELEMENT bookname (#PCDATA)> <!ELEMENT author (#PCDATA)> <!ELEMENT price (#PCDATA)> ]>
book.xml:
<!DOCTYPE bookstore SYSTEM "bookstore.dtd"> <bookstore> <book> <bookname>带你飞培训教程</bookname> <author>huangjinjin</author> <price>1.00元</price> </book> <book> <bookname>降龙十八讲秘籍</bookname> <author>洪七公</author> <price>0.01元</price> </book> </bookstore>
2.XML Schema 约束
XML Schema 是基于 XML DTD 的替代者,XML Schema 描述 XML 文档的结构。XML Schema 语言也称作 XML Schema 定义(XML Schema Definition 简称 XSD)。DTD 不是通过 XML 语法定义文档结构,不能定义数据类型和限制;Schema 通过 XML 语法定义文档结构,可以定义数据类型和限制。
XML Schema 对 XML 文件的主要约定有:
定义可出现在 XML 文档中的元素;
定义可出现在 XML 文档中的属性;
定义哪个元素是子元素;
定义子元素的次序;
定义子元素的数目;
定义元素是否为空,或者是否可包含文本;
定义元素和属性的数据类型;
定义元素和属性的默认值以及固定值。
为何使用 Schema,原因有几下几点:
XML Schema 可针对未来的需求进行扩展;
XML Schema 更完善,功能更强大;
XML Schema 基于 XML 编写;
XML Schema 支持数据类型和限制;
XML Schema 支持命名空间。
我们看下面这个例子。
book.xsd 文件:
?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.mybook.org/BookSchema" xmlns:tns="http://www.mybook.org/BookSchema" elementFormDefault="qualified"> <!-- 定义一个标签 --> <element name="bookstore"> <!-- 复合类型 就是该标签含有子标签 --> <complexType> <!-- 含有不限定个数的子标签 --> <sequence maxOccurs="unbounded"> <!-- 定义一个子标签 --> <element name="book"> <complexType> <sequence> <!-- 定义一个文本子标签 --> <element name="bookname" type="string" /> <element name="author" type="price" type="string" /> </sequence> <attribute name="id" type="string"></attribute> </complexType> </element> </sequence> </complexType> </element> </schema>
book.xml
?> <bookstore xmlns="http://www.w3.org/2001/XMLSchema-instance" xmlns:nsbook="http://www.mybook.org/BookSchema" nsbook:schemaLocation="http://www.mybook.org/BookSchema book.xsd"> <book id="1"> <bookname>带你飞培训教程</bookname> <author>huangjinjin</author> <price>1.00元</price> </book> <book id="2"> <bookname>降龙十八讲秘籍</bookname> <author>洪七公</author> <price>0.01元</price> </book> </bookstore>
Java 内置解析 XML API: DOM、SAX
DOM
DOM的全称是 Document Object Model,即文档对象模型,W3C 组织推荐处理 XML 的一种方式。在应用程序中,基于 DOM 的 XML 分析器将一个 XML 文档转换成一个对象模型的集合(通常称 DOM 树),应用程序正是通过对这个对象模型的操作,来实现对 XML 文档数据的操作。通过 DOM 接口,应用程序可以在任何时候访问 XML 文档中的任何一部分数据,因此这种利用 DOM 接口的机制也被称作随机访问机制。
DOM 接口提供了一种通过分层对象模型来访问 XML 文档信息的方式,这些分层对象模型依据 XML 的文档结构形成了一棵节点树。无论 XML 文档中所描述的是什么类型的信息,即便是制表数据、项目列表或一个文档,利用 DOM 所生成的模型都是节点树的形式。也就是说 DOM 强制使用树模型来访问 XML 文档中的信息。由于 XML 本质上就是一种分层结构,所以这种描述方法是相当有效的。
DOM 树所提供的随机访问方式给应用程序的开发带来了很大的灵活性,它可以任意地控制整个 XML 文档中的内容。然而,由于 DOM 分析器把整个 XML 文档转化成 DOM 树放在了内存中,因此当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且对于结构复杂的树的遍历也是一项耗时的操作。所以 DOM 分析器对机器性能的要求比较高,实现效率不十分理想。
不过,由于 DOM 分析器所采用的树结构的思想与 XML 文档的结构相吻合,同时鉴于随机访问所带来的方便,因此 DOM 分析器还是有很广泛的使用价值的。
其优点主要有:
其缺点主要有:
DOM 操作 XML 例子,请见下面代码:
// 创建一个DocumentBuilderFactory的对象 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); // 创建一个DocumentBuilder的对象 try { // 创建DocumentBuilder对象 DocumentBuilder db = dbf.newDocumentBuilder(); // 通过DocumentBuilder对象的parser方法加载books.xml文件到当前项目下 Document document = db.parse("C:\\Users\\Administrator\\Desktop\\xmlchat\\xml-chat\\src\\test\\resources\\3.xml"); // 获取所有book节点的集合 NodeList bookList = document.getElementsByTagName("book"); // 通过nodelist的getLength()方法可以获取bookList的长度 System.out.println("一共有" + bookList.getLength() + "本书"); // 遍历每一个book节点 for (int i = 0; i < bookList.getLength(); i++) { System.out.println("=================下面开始遍历第" + (i + 1) + "本书的内容================="); // 通过 item(i)方法 获取一个book节点,nodelist的索引值从0开始 Node book = bookList.item(i); // 获取book节点的所有属性集合 NamedNodeMap attrs = book.getAttributes(); System.out.println("第 " + (i + "本书共有" + attrs.getLength() + "个属性"); // 遍历book的属性 for (int j = 0; j < attrs.getLength(); j++) { // 通过item(index)方法获取book节点的某一个属性 Node attr = attrs.item(j); // 获取属性名 值 System.out.print("属性名:" + attr.getNodeName()+",属性值" + attr.getNodeValue()); } // 解析book节点的子节点 NodeList childNodes = book.getChildNodes(); // 遍历childNodes获取每个节点的节点名和节点值 System.out.println("第" + (i + "本书共有" + childNodes.getLength() + "个子节点"); for (int k = 0; k < childNodes.getLength(); k++) { // 区分出text类型的node以及element类型的node if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) { // 获取了element类型节点的节点名 System.out.print("第" + (k + "个节点的节点名:" + childNodes.item(k).getNodeName()); // 获取了element类型节点的节点值 System.out.println("--节点值是:" + childNodes.item(k).getFirstChild().getNodeValue()); } } System.out.println("======================结束遍历第" + (i + "本书的内容================="); } } catch (Exception e) { e.printStackTrace(); }