分享
 
 
 

DOM心得

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

DOM心得

绯雨闲丸

本文介绍了DOM(文档对象模型)的结构和常规使用方法。通过本文,读者可以学会用DOM来对XML文档进行常见的处理。本文不讨论DOM的设计和实现技巧。

关键词:

XML DOM

概述

DOM(文档对象模型)是对XML数据的描述体系,它用树型结构的文档来保存XML数据。此外,DOM也包括了解析、处理XML数据的API。

在开始使用DOM之前,首先来了解一下它的结构。DOM整体上的结构是一个Composite模式。所有的XML单元,无论是文档、元素还是属性、文本,在DOM中都是一个Node(节点)。按照Composite模式的定义,每个Node都可以包容其他的Node,于是很轻松地就构成了一个树型结构。举一个简单的例子,下面的XML文档

<Book>

<Title>Effective C++</Title>

<Author>

<Name>Scott Meyers</Name>

<Gender>Male</Gender>

<Nationality>USA</Nationality>

</Author>

<Publisher>Addison-Wesley</Publisher>

</Book>

在DOM中的存储形式就会是这样:

既然已经了解了DOM文档的结构,下面就该学习如何操作DOM文档了。对于这样一个树型结构,比较重要的操作有文档生成、文档遍历、节点内容的处理(读取、修改等等)、节点本身的操作(插入、删除、替换等等)以及文档的序列化。下面,我们将逐个学习这些操作。

DOM文档的生成

用DOM处理XML数据,首先需要以下三个步骤:

1. 创建DocumentBuilderFactory。该对象将创建DocumentBuilder。

2. 创建 DocumentBuilder。 DocumentBuilder将对输入实际进行解析以创建Document对象。

3. 解析输入的XML,创建Document对象。

DocumentBuilderFactory是一个Singleton,所以不能直接new出来,应该调用DocumentBuilderFactory.newInstance()来得到DocumentBuilderFactory的实例。此外,DocumentBuilderFactory也是一个对象工厂(从名字就能看出),可以用它来创建DocumentBuilder。

通常会使用DocumentBuilder的parse方法返回一个Document对象(需要插一句:Document只是一个接口,用javax.xml.parsers.DocumentBuilder的parse方法得到的实际上是org.apache.crimson.tree.XmlDocument对象)。parse方法接受很多输入参数,包括File、InputStream、InputSource、String型的URI等等。parse方法会把输入源进行解析,在内存中生成一个DOM的树型结构——Document对象。

上面这三个步骤的常用代码如下:

File docFile = new File("orders.xml");

Document doc = null;

try {

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

DocumentBuilder db = dbf.newDocumentBuilder();

doc = db.parse(docFile);

} catch (Exception e) { System.out.print("Problem parsing the file."); }

parse方法可能会抛出IOException或者SAXException,分别表示输入异常和解析异常。

在创建DocumentBuilder之前,可以为DocumentBuilder设置一些参数,调节它在生成Document时的行为方式。可控的参数包括:

l setCoalescing:确定解析器是否将 CDATA 节点转成文本,并将 CDATA 节点与其周围的文本节点合并(如果合适)。缺省值是 false。

l setExpandEntityReferences:确定是否扩展外部实体引用。如果为 true,则将外部数据插入文档。缺省值是 true。

l setIgnoringcomments:确定是否忽略文件中的注释。缺省值是 false。

l setIgnoringElementContentWhitespace:确定是否忽略元素内容中的空白(类似于浏览器处理 HTML 的方式)。缺省值是 false。

l setNameSpaceAware:确定解析器是否注意名称空间信息。缺省值是 false。

l setValidating:缺省情况下,解析器将不验证文档。将该参数设置为 true 以打开验证。

设置参数的语句如下:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

dbf.setValidating(true);

DocumentBuilder db = dbf.newDocumentBuilder();

DOM文档的遍历

DOM采用了Composite模式。Node类是所有XML单元的基类,Element、Attr、Document等等都是Node的派生类。每个Node都可以包容其他的Node,也可以包容文本格式的内容。所以,DOM文档的遍历相当简单。

首先要获取文档的根节点。用Document.getDocumentElement()方法可以得到一个Element类型的对象,它就是文档的根节点。对于一个HTML文档,getDocumentElement()方法得到的就是<html>节点。

只要得到根节点,就可以用Node.getChildNodes()方法得到该节点的所有直接子节点,从而遍历整个树型结构。另外,可以用Node.hasChildNodes()方法判断一个节点是否叶节点,从而得到遍历算法的结束条件。getChildNodes()方法的返回值是NodeList对象,NodeList有两个方法:int getLength()和Node item(int),可以使用这两个方法来安全地访问其中的每个元素。

上面这种方法是深度优先的遍历(采用迭代算法),还有一种方法是广度优先的遍历算法,要使用的方法是getFirstChild()(获取第一个孩子节点)和getNextSibling()(获取下一个兄弟节点)。

处理元素的内容

首先必须搞清楚“节点(node)”和“元素(element)”的概念:在DOM中节点和元素不是等价的。“元素”是指一对标记(tag)及其内部包含的字符串值的总和,例如下面这就是一个元素:

<Country>

China

</Country>

但是它却不是一个节点,而是两个。第一个节点是<Country>节点,它的值是null;第二个节点是一个文本节点(节点名是#text),它的值是"China\n"。文本节点是<Country>节点的子节点。

所以,要处理一个元素的内容时,需要两个步骤:

1. 找到代表该元素的节点;

2. 处理该节点的第一个子节点;

只要知道某个元素的名称,就可以用Element.getElementsByTagName(String name)方法来找到所有代表该元素的节点。getElementsByTagName方法会自动遍历整个树型结构,将找到的节点全部保存在一个NodeList中返回。由于DOM的树型结构是建立在内存中的,所以这个操作不会太慢。找到节点之后,用Node.getFirstChild()方法就可以得到代表该元素值的文本节点,用Node.setNodeValue(String)方法就可以修改节点的值。

处理其他类型节点的内容

如果要访问的节点是属性节点(Node.getNodeType()==ATTRIBUTE_NODE),则可以通过getAttributes()方法获得节点中所有的属性。getAttributes方法会返回一个NamedNodeMap型的对象,这是一个名-值映射表,可以通过String型的名称来随机访问,也可以通过int型的顺序号来顺序访问。Attr类(属性节点)有getValue()和setValue()两个accessor,用于访问属性的值。

节点共有12种不同的类型,这里只介绍了元素节点和属性节点这两种最常用的,其他的就要自己查帮助了。Node有一个getNodeType()方法,会返回short型值,从而判断一个对象的真实类型,起到RTTI的作用。下面是getNodeType()方法所有可能的返回值:

public static final short ELEMENT_NODE = 1;

public static final short ATTRIBUTE_NODE = 2;

public static final short TEXT_NODE = 3;

public static final short CDATA_SECTION_NODE = 4;

public static final short ENTITY_REFERENCE_NODE = 5;

public static final short ENTITY_NODE = 6;

public static final short PROCESSING_INSTRUCTION_NODE = 7;

public static final short COMMENT_NODE = 8;

public static final short DOCUMENT_NODE = 9;

public static final short DOCUMENT_TYPE_NODE = 10;

public static final short DOCUMENT_FRAGMENT_NODE = 11;

public static final short NOTATION_NODE = 12;

节点的处理

对于树型数据结构,常见的节点处理就是节点的插入、删除和替换。DOM为这些操作提供了非常简单易用的API。

插入节点可以用Node.appendChild(Node),也可以用Node.insertBefore(Node newChild, Node refChild);删除节点可以用Node.removeChild(Node oldChild);替换节点可以用Node.replaceChild(Node newChild, Node oldChild)。DOM会自动调整树型结构,删除、替换的操作还会返回oldChild这个节点,非常方便。

文档(Document)也是一个节点(Node),所以也可以把节点直接插入到文档中。不过要注意:只有该文档创建出的节点才能插入到该文档中,否则会引发WRONG_DOCUMENT_ERR异常。创建节点使用Document.createXxxx方法。可以用cloneNode(boolean deep)方法来克隆一个节点,用boolean型的参数决定是否深度拷贝,但是克隆出的节点也不能插入别的文档中。另外,可以用Document.importNode(Node importedNode, boolean deep)方法来引入别的文档中的节点。

需要处理元素的属性时,可以用Element.setAttributeNode(Attr newAttr)来插入属性,用Element.removeAttribute(String name)来删除不需要的属性。如果属性有同名的,可以用Element. removeAttributeNode(Attr oldAttr)来指定删除某一个属性节点。

文档的序列化

每个Element都覆盖了toString方法,所以只要指定某一个Element作为根,再调用它的toString方法,它就会递归得到其下的整个树型结构,并转换成String型对象。只要把这个String型对象输出到指定的设备上,就可以得到XML文档,非常方便。下面这段代码会生成一个新的HTML文档(HTML可以说是XML的子集),并在标准输出设备上输出。

Document newdoc = null;

try {

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

DocumentBuilder db = dbf.newDocumentBuilder();

newdoc = db.newDocument();

} catch(Exception e){};

Element head = newdoc.createElement("Head");

Element title = newdoc.createElement("Title");

title.appendChild(newdoc.createTextNode("Document created by DOM"));

head.appendChild(title);

Element body = newdoc.createElement("Body");

body.appendChild(newdoc.createTextNode("This is a test document"));

Element newroot = newdoc.createElement("Html");

newroot.appendChild(body);

newroot.insertBefore(head, body);

newdoc.appendChild(newroot);

System.out.println(newroot);

总结

DOM在内存中生成树型结构来处理XML数据,在处理速度和方便性上有优势,但是比较耗存储空间。如果XML文档比较大的话,解析过程可能会需要比较长的时间。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有