XML解析
XML 文档的应用范围主要有存储数据、系统配置和数据交换。也就是说,我们需要编写程序读取 XML 文档中的数据,或将数据写入 XML 文档。目前最常用的 XML 解析技术有 DOM 和 SAX。JDK 提供了 JAXP 来使用 DOM 和 SAX,其中 org.w3c.dom
是 W3C 推荐的用于使用 DOM 解析 XML 文档的接口,org.xml.sax
是使用 SAX 解析 XML 文档的接口,javax.xml.parsers
提供处理 XML 文档的类,支持 DOM 和 SAX。
DOM解析
DOM(Document Object Model)是 XML 文档的应用程序接口,它定义了对 XML 文档进行随机访问与操作的方法。DOM 是一个与语言无关、与平台无关的标准接口规范。利用 DOM,可以动态地创建 XML 文档,遍历文档结构,添加、修改、删除文档内容,改变文档的显示方式等。可以这样说,文档代表的是数据,而 DOM 则代表了如何去处理这些数据。
DOM 把一个 XML 文档映射成一个分层对象模型,而这个层次的结构,是一棵根据 XML 文档生成的节点树。DOM 在对 XML 文档进行分析之后,不管这个文档有多简单或多复杂,其中的信息都会被转化成一棵对象节点树。在这棵节点树中,有一个根节点,其他所有的节点都是根节点的子节点。节点树生成之后,就可以通过 DOM 接口访问、修改、添加、删除树中的节点或内容了。
使用 DOM 解析 XML,需要经过以下几个步骤:
- 创建解析器工厂,即
DocumentBuilderFactory
对象。- 通过解析器工厂获得 DOM 解析器,即
DocumentBuilder
对象。- 解析指定 XML 文档,得到 DOM 节点树。
- 对 DOM 节点树进行操作,完成对 XML 文档的增、删、改、查。
Node接口
Node 接口在整个 DOM 树中具有举足轻重的地位,DOM 接口中有很大一部分接口是从 Node 接口继承过来的,例如 Document(根节点)、Element(元素)、Attr(属性)、Comment(注释)、Text(元素或属性的文本内容)等接口都是从 Node 继承过来的。在 DOM 树中,Node 接口代表了树中的一个节点。Node 接口的常用方法如下。
NodeList getChildNodes()
:返回此节点的所有子节点的NodeList
。Node getFirstChild()
:返回此节点的第一个子节点。Node getLastChild()
:返回此节点的最后一个子节点。Node getNextSibling()
:返回此节点之后的节点。Node getPreviousSibling()
:返回此节点之前的节点。Document getOwnerDocument()
:返回与此节点相关的Document
对象。Node getParentNode()
:返回此节点的父节点。short getNodeType()
:返回此节点的类型。String getNodeName()
:根据此节点类型,返回节点名称。String getNodeValue()
:根据此节点类型,返回节点值。
前面已经提到,DOM 中很多接口都是从 Node 接口继承的,所以 Node 接口拥有的方法这些接口都可以使用。
但是这些从 Node 接口继承下来的接口又都各有特性,所以 Node 接口拥有的方法在各个子接口上的返回值含义不尽相同。
例如,Element(元素接口)的 getNodeType()
的返回值为 Node.ELEMENT_NODE
常量,getNodeName()
的返回值为标签名称,getNodeValue()
的返回值为 null。
下表列出了 nodeName
、 nodeValue
和 attributes
的值将根据接口类型的不同而不同。
Interface | nodeName | nodeValue | attributes |
---|---|---|---|
Attr | 与 Attr.name 相同 | 与 Attr.value 相同 | null |
CDATASection | “#cdata-section” | 与 CharacterData.data 相同:CDATA 节的内容 | null |
Comment | “#comment” | 与 CharacterData.data 相同: 该注释的内容 | null |
Document | “#document” | null | null |
DocumentFragment | “#document-fragment” | null | null |
DocumentType | 与 DocumentType.name 相同 | null | null |
Element | 与 Element.tagName 相同 | null | NamedNodeMap |
Entity | entity name | null | null |
EntityReference | 引用的实体名称 | null | null |
Notation | notation name | null | null |
ProcessingInstruction | 与 ProcessingInstruction.target 相同 | 与 ProcessingInstruction.data 相同 | null |
Text | “#text” | 与 CharacterData.data 相同: 该文本节点的内容 | null |
String getTextContent()
:返回此节点的文本内容。void setNodeValue(String nodeValue)
:根据此节点类型,设置节点值。void setTextContent(String textContent)
:设置此节点的文本内容。Node appendChild(Node newChild)
:将节点 newChild 添加到此节点的子节点列表的末尾。Node insertBefore(Node newChild,Node refChild)
:在现有子节点 refChild 之前插入节点 newChild。Node removeChild(Node oldChild)
:从子节点列表中移除 oldChild 所指示的子节点,并将其返回。Node replaceChild(Node newChild, oldChild)
:将子节点列表中的子节点 oldChild 替换为 newChild,并返回 oldChild 节点。
Document接口
Document
接口表示 DOM 树中的根节点,即对 XML 文档进行操作的入口节点。通过 Document
节点,可以访问到文档中的其他节点。
Document
接口的常用方法如下:
-
Element getDocumentElement()
:返回代表这个 DOM 树根节点的Element
对象。 -
NodeList getElementsByTagName(String tagname)
:按文档顺序返回包含在文档中且具有给定标记名称的所有Element
的NodeList
。NodeList 接口
NodeList 接口提供了对节点集合的抽象定义,包含了一个或多个节点(Node)的有序集合。NodeList 接口的常用方法如下。
int getLength()
:返回有序集合中的节点数。Node item(int index)
:返回有序集合中的第 index 个项。
SAX解析
相比于 DOM,SAX(Simple API for XML)是一种速度更快、更有效的解析 XML 文档的方法。它不需要一次性建立一个完整的 DOM 树,而是读取文档时激活事件进行处理。
DOM 是 W3C 标准,提供的是标准的解析方式,但其解析效率一直不尽如人意。这是因为 DOM 解析 XML 文档时,把所有内容一次性装载入内存,并构建一个驻留在内存中的节点树。如果需要解析的 XML 文档过大,或者只对该文档中的一部分内容感兴趣,这种做法就会引起性能问题。
SAX 既是一个接口,也是一个软件包。SAX 在解析 XML 时是事件驱动型的,它的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档开始与结束、元素开始与结束等地方时通知事件处理程序,由事件处理程序做相应动作,然后继续同样的扫描,直至文档结束。SAX 的缺点也很明显,要用 SAX 对 XML 文档进行解析时,就要实现多个事件处理程序,用来处理可能触发的事件,对程序员而言操作起来相对复杂。