<?xml version="1.0"?>
<sonnet type="Shakespearean">
<author>
<last-name>Shakespeare</last-name>
<first-name>William</first-name>
<nationality>British</nationality>
<year-of-birth>1564</year-of-birth>
<year-of-death>1616</year-of-death>
</author>
<title>Sonnet130</title>
<lines>
<line>Mymistress?eyesare...
处理DOM树
现在解析已经完成,我们将遍历DOM树。注意这段代码是递归的。对每个节点,我们处理其本身,然后我们对每个节点的子女递归地调用printDOMTree方法。递归调用如左所示。
要记住当有些XML文档非常大时,它们反而不会有太多层标记。以一个上海市的电话簿为例,可能有几百万条记录,但其标记可能不会超过几层。考虑到这个原因,递归算法的栈溢出不是一个问题。
public void printDOMTree(Nodenode)
{
intnodeType=Node.getNodeType();
switch(nodeType)
{
caseDOCUMENT_NODE:
printDOMTree(((Document)node).
GetDocumentElement());
...
caseELEMENT_NODE:
...
NodeListchildren= node.getChildNodes();
if(children!=null)
{
for(inti=0; i< children.getLength(); i++)
printDOMTree(children.item(i));
如果您查看 sonnet.xml,有二十四个节点。您可能认为这意味着二十四个节点。然而,这不正确。在 sonnet.xml 中一共有 69 个节点;一个文档节点(document node), 23 个元素节点(element node)以及 45 个文本节点(text node)。我们运行 java domCounter sonnet.xml 就获得了下边所示的结果。
统计 sonnet.xml 的数据:
====================================
Document Nodes: 1
Element Nodes: 23
Entity Reference Nodes: 0
CDATA Sections: 0
Text Nodes: 45
Processing Instructions: 0
----------
Total: 69 Nodes
节点列表示例:
对于下边的片断,
<sonnet type="Shakespearean">
<author>
<last-name>Shakespeare</last-name>
下列是从解析器返回的节点:
Document节点
Element节点对应于<sonnet>标记
一个Text节点对应于<sonnet>节点后的回车符以及<author>标记前的两个空格符
Element节点对应于<author>标记
一个Text节点对应于<author>节点后的回车符以及<last-name>标记前的四个空格符
Element节点对应于<last-name>标记
所有那些文本节点
如果您查看由解析器返回的所有节点列表,您将发现它们大多数是没用的。在每行开始的空格符组成其中包含可忽略的Text节点。注意如果您将所有的节点放在一行上我们就不会得到这些无用的节点了。我们通过添加分行符和空格符来提高文档的可读性。当您构建一个XML文档时不需要考虑可读性,就可省略分行符和空格符。这可使得您的文档更小,处理您的文档时也不需要构建那些无用的节点。
<sonnet type="Shakespearean">
<author>
<last-name>Shakespeare</last-name>
<first-name>William</first-name>
<nationality>British</nationality>
<year-of-birth>1564</year-of-birth>
<year-of-death>1616</year-of-death>
</author>
<title>Sonnet130</title>
<lines>
<line>Mymistress'eyesarenothinglikethesun,</line>
一个Text节点对应于"Shakespeare"字符
如果您看到标记间所有的空格符,您可发现为何我们有那么多超出您想像的节点。
了解您的Node
我们最后对处理在DOM树的Node要指出的是,我们在处理其之前要检查每个Node的类型。一些方法,例如getAttributes,对一些特定的节点类型返回null值。如果您不检查节点类型,您将得到不正确的结果(最佳情况)和异常(最差情况)。
在此所介绍的switch语句常出现在使用DOM解析器的代码。
switch(nodeType)
{
caseNode.DOCUMENT_NODE:
...
caseNode.ELEMENT_NODE:
...
caseNode.TEXT_NODE:
...
}
总结
不管您信不信,这就是我们使用DOM对象所要了解的所有内容。我们的domOne代码完成了下列工作:
创建一个Parser对象
将一个XML文档传递给Parser来解析
获得来自于Parser的Document对象然后加以检查。
在本教程最后一章,我们将讨论如何不需要XML原文件来构建一棵DOM树,并展示如何对一个XML文档中的元素排序。而那些都是基于我们这里所讨论的概念之上。
<sonnet type="Shakespearean">
<author>
<last-name>Shakespeare</last-name>
<first-name>William</first-name>
<nationality>British</nationality>
<year-of-birth>1564</year-of-birth>
<year-of-death>1616</year-of-death>
</author>
<title>Sonnet130</title>
<lines>
<line>Mymistress?eyesare...
处理DOM树
现在解析已经完成,我们将遍历DOM树。注意这段代码是递归的。对每个节点,我们处理其本身,然后我们对每个节点的子女递归地调用printDOMTree方法。递归调用如左所示。
要记住当有些XML文档非常大时,它们反而不会有太多层标记。以一个上海市的电话簿为例,可能有几百万条记录,但其标记可能不会超过几层。考虑到这个原因,递归算法的栈溢出不是一个问题。
public void printDOMTree(Nodenode)
{
intnodeType=Node.getNodeType();
switch(nodeType)
{
caseDOCUMENT_NODE:
printDOMTree(((Document)node).
GetDocumentElement());
...
caseELEMENT_NODE:
...
NodeListchildren= node.getChildNodes();
if(children!=null)
{
for(inti=0; i< children.getLength(); i++)
printDOMTree(children.item(i));
}
domCounter.java
这段代码解析一个 XML 文档,然后遍历 DOM 树来采集有关该文档的数据。当数据采集后将其输出到标准输出。
如果您查看 sonnet.xml,有二十四个节点。您可能认为这意味着二十四个节点。然而,这不正确。在 sonnet.xml 中一共有 69 个节点;一个文档节点(document node), 23 个元素节点(element node)以及 45 个文本节点(text node)。我们运行 java domCounter sonnet.xml 就获得了下边所示的结果。
统计 sonnet.xml 的数据:
====================================
Document Nodes: 1
Element Nodes: 23
Entity Reference Nodes: 0
CDATA Sections: 0
Text Nodes: 45
Processing Instructions: 0
----------
Total: 69 Nodes
节点列表示例:
对于下边的片断,
<sonnet type="Shakespearean">
<author>
<last-name>Shakespeare</last-name>
下列是从解析器返回的节点:
Document节点
Element节点对应于<sonnet>标记
一个Text节点对应于<sonnet>节点后的回车符以及<author>标记前的两个空格符
Element节点对应于<author>标记
一个Text节点对应于<author>节点后的回车符以及<last-name>标记前的四个空格符
Element节点对应于<last-name>标记
所有那些文本节点
如果您查看由解析器返回的所有节点列表,您将发现它们大多数是没用的。在每行开始的空格符组成其中包含可忽略的Text节点。注意如果您将所有的节点放在一行上我们就不会得到这些无用的节点了。我们通过添加分行符和空格符来提高文档的可读性。当您构建一个XML文档时不需要考虑可读性,就可省略分行符和空格符。这可使得您的文档更小,处理您的文档时也不需要构建那些无用的节点。
<sonnet type="Shakespearean">
<author>
<last-name>Shakespeare</last-name>
<first-name>William</first-name>
<nationality>British</nationality>
<year-of-birth>1564</year-of-birth>
<year-of-death>1616</year-of-death>
</author>
<title>Sonnet130</title>
<lines>
<line>Mymistress'eyesarenothinglikethesun,</line>
一个Text节点对应于"Shakespeare"字符
如果您看到标记间所有的空格符,您可发现为何我们有那么多超出您想像的节点。
了解您的Node
我们最后对处理在DOM树的Node要指出的是,我们在处理其之前要检查每个Node的类型。一些方法,例如getAttributes,对一些特定的节点类型返回null值。如果您不检查节点类型,您将得到不正确的结果(最佳情况)和异常(最差情况)。
在此所介绍的switch语句常出现在使用DOM解析器的代码。
switch(nodeType)
{
caseNode.DOCUMENT_NODE:
...
caseNode.ELEMENT_NODE:
...
caseNode.TEXT_NODE:
...
}
总结
不管您信不信,这就是我们使用DOM对象所要了解的所有内容。我们的domOne代码完成了下列工作:
创建一个Parser对象
将一个XML文档传递给Parser来解析
获得来自于Parser的Document对象然后加以检查。
在本教程最后一章,我们将讨论如何不需要XML原文件来构建一棵DOM树,并展示如何对一个XML文档中的元素排序。而那些都是基于我们这里所讨论的概念之上。