一、前言
DOM= Document Object Model,文档对象模型,DOM可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构。换句话说,这是表示和处理一个HTML或XML文档的常用方法。有一点很重要,DOM的设计是以对象管理组织(OMG)的规约为基础的,因此可以用于任何编程语言。最初人们把它认为是一种让JavaScript在浏览器间可移植的方法,不过DOM的应用已经远远超出这个范围。Dom技术使得用户页面可以动态地变化,如可以动态地显示或隐藏一个元素,改变它们的属性,增加一个元素等,Dom技术使得页面的交互性大大地增强。
DOM实际上是以面向对象方式描述的文档模型。DOM定义了表示和修改文档所需的对象、这些对象的行为和属性以及这些对象之间的关系。可以把DOM认为是页面上数据和结构的一个树形表示,不过页面当然可能并不是以这种树的方式具体实现。
优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)。
二、DOM解析XML文档
Sun公司提供了Java API for XML Parsing(JAXP)接口来使用SAX和DOM,通过JAXP,我们可以使用任何与JAXP兼容的XML解析器。
JAXP接口包含了三个包:
(1)org.w3c.dom W3C推荐的用于XML标准规划文档对象模型的接口。
(2)org.xml.sax 用于对XML进行语法分析的事件驱动的XML简单API(SAX)
(3)javax.xml.parsers解析器工厂工具,程序员获得并配置特殊的特殊语法分析器。
DOM编程不要其它的依赖包,因为JDK里自带的JDK里含有的上面提到的org.w3c.dom、org.xml.sax 和javax.xml.parsers包就可以满足条件了。
下面给出一个使用DOM解析XML文件的实例
XML文件内容如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<中国>
<北京>
<海淀>
<上地>上地七街</上地>
<中关村>鼎好</中关村>
<东北旺>杀人</东北旺>
<东北旺/></海淀>
</北京>
<河南>
<郑州>
<商丘 id="attr" 人口="100万">商丘中学</商丘>
</郑州>
<安阳/>
</河南>
<河北>
<石家庄 人口="2000万"/>
</河北>
</中国>
下面给出一个DOM解析XML的JAVA代码
package cn.csdn.XML;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class XMLDemo2 {
@Test
public void test() throws Exception {
// 获取DocumentBuilderFactory的方法
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 设置去掉空格
factory.setIgnoringElementContentWhitespace(true);
// 获取解析器
DocumentBuilder builder = factory.newDocumentBuilder();
// 解析xml文档
Document document = builder.parse(new File("src//china.xml"));
// 获取根节点对象
Element root = document.getDocumentElement();
// 调用node中的getChildNodes方法获取根节点中的子节点
NodeList Nlist = root.getChildNodes();
//遍历该子节点
display(Nlist);
}
//使用递归遍历个子节点中的子节点
public void display(NodeList Nlist) {
for (int i = 0; i < Nlist.getLength(); i++) {
Node node = Nlist.item(i);
if (node.getNodeType() != Node.TEXT_NODE) {
System.out.println(node.getNodeName());
}
if (node.hasAttributes()) {//判断是否有属性
Element element = (Element) node;
String value = element.getAttribute("人口");
System.out.println("人口:" + value);
}
//判断该节点是否还有子节点
if (node.hasChildNodes()) {
NodeList list = node.getChildNodes();
//调用方法本身
display(list);
} else {
if (node.getNodeType() == Node.TEXT_NODE) {//判断节点类型
System.out.println(node.getTextContent());
break;//当没有子节点时跳出
}
}
}
}
}
程序运行结果如下:
北京
海淀
上地
上地七街
中关村
鼎好
东北旺
软件园
河南
郑州
商丘
人口:100万
商丘中学
安阳
河北
石家庄
人口:2000万
该程序解析了XML文件中的所有元素,既然能解析XML文件,那么我们也可以创建一个XML文件件,下面给出了一个创建XML文件的JAVA源代码:
package cn.csdn.dom;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.junit.Test;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class Demo05 {
@Test
public void test2()throws Exception{
//获取dom解析的工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//获取解析器
DocumentBuilder builder = factory.newDocumentBuilder();
//创建一个新的Document对象
Document doc = builder.newDocument();
//设置此文档版本号的属性
doc.setXmlVersion("1.0");
//创建注释
Comment comment = doc.createComment("创建xml文件");
//增加注释
doc.appendChild(comment);
//创建一个学生的元素
Element root = doc.createElement("学生");
//创建一个姓名的元素
Element name = doc.createElement("姓名");
//创建 Text 节点
name.appendChild(doc.createTextNode("redarmy_chen"));
//创建一个性别元素
Element sex = doc.createElement("性别");
//给性别元素增加一个属性
sex.setAttribute("name", "男");
//将节点添加到此节点的子节点列表的末尾
root.appendChild(name);
root.appendChild(sex);
doc.appendChild(root);
//获取 TransformerFactory 的新实例
TransformerFactory factory1 = TransformerFactory.newInstance();
//创建Transformer
Transformer tformer = factory1.newTransformer();
//将 XML Source 转换为 Result输出到src目录下的ds.xml文件中
tformer.transform(new DOMSource(doc), new StreamResult("src//ds.xml"));
}
}
该程序执行后在src目录下创建一个名为ds.xml的文件,文件内容如下
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!--创建xml文件--><学生><姓名>redarmy_chen</姓名><性别 name="男"/></学生>
我们还可以修改,删除节点,下面给出部分代码用来修改,删除节点:
//增加节点
public void append() throws Exception {
// 获取dom解析的工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 获取解析器
DocumentBuilder builder = factory.newDocumentBuilder();
// 把xml文档输入到解析器中,并获取xml文档对应的document对象
Document doc = builder.parse(new File("src//dom.xml"));
// 创建一个东北旺元素
Element element = doc.createElement("东北旺");
// 创建 Text 节点
element.appendChild(doc.createTextNode("家"));
// 获取名为海淀的第一个节点
Node node = doc.getElementsByTagName("海淀").item(0);
// 在此节点末尾追加一个元素
node.appendChild(element);
// 获取 TransformerFactory 的新实例
TransformerFactory factory1 = TransformerFactory.newInstance();
// 创建Transformer
Transformer tformer = factory1.newTransformer();
// 将 XML Source 转换为 Result输出到ds.xml文件中
tformer.transform(new DOMSource(doc), new StreamResult("src//ds.xml"));
}
//删除节点
public void delete() throws Exception {
// 获取dom解析的工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 获取解析器
DocumentBuilder builder = factory.newDocumentBuilder();
// 把xml文档输入到解析器中,并获取xml文档对应的document对象
Document doc = builder.parse(new File("src//dom.xml"));
// 获取名为海淀的第一个节点
Node node = doc.getElementsByTagName("海淀").item(0);
// 移除名为东北旺的第三个节点
node.removeChild(doc.getElementsByTagName("东北旺").item(2));
// 获取 TransformerFactory 的新实例
TransformerFactory factory1 = TransformerFactory.newInstance();
// 创建Transformer
Transformer tformer = factory1.newTransformer();
// 将 XML Source 转换为 Result输出到ds.xml文件中
tformer.transform(new DOMSource(doc), new StreamResult("src//ds.xml"));
}
//修改节点内容
public void update() throws Exception {
// 获取dom解析的工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 获取解析器
DocumentBuilder builder = factory.newDocumentBuilder();
// 把xml文档输入到解析器中,并获取xml文档对应的document对象
Document doc = builder.parse(new File("src//dom.xml"));
// 获取名为东北旺的第一个节点
Node node1 = doc.getElementsByTagName("东北旺").item(0);
//设置修改的文本内容
node1.setTextContent("家人");
// 获取 TransformerFactory 的新实例
TransformerFactory factory1 = TransformerFactory.newInstance();
// 创建Transformer
Transformer tformer = factory1.newTransformer();
// 将 XML Source 转换为 Result输出到ds.xml文件中
tformer.transform(new DOMSource(doc), new StreamResult("src//ds.xml"));
}
三、总结基本的DOM对象以及一些主要方法
DOM的基本对象有5个:Document,Node,NodeList,Element和Attr。下面就这些对象的功能和实现的方法作一个大致的介绍。
Document对象代表了整个XML的文档,所有其它的Node,都以一定的顺序包含在Document对象之内,排列成一个树形的结构,程序员可以通过遍历这颗树来得到XML文档的所有的内容,这也是对XML文档操作的起点。我们总是先通过解析XML源文件而得到一个Document对象,然后再来执行后续的操作。此外,Document还包含了创建其它节点的方法,比如createAttribute()用来创建一个Attr对象。它所包含的主要的方法有:
createAttribute(String):用给定的属性名创建一个Attr对象,并可在其后使用setAttributeNode方法来放置在某一个Element对象上面。
createElement(String):用给定的标签名创建一个Element对象,代表XML文档中的一个标签,然后就可以在这个Element对象上添加属性或进行其它的操作。
createTextNode(String):用给定的字符串创建一个Text对象,Text对象代表了标签或者属性中所包含的纯文本字符串。如果在一个标签内没有其它的标签,那么标签内的文本所代表的Text对象是这个Element对象的唯一子对象。
getElementsByTagName(String):返回一个NodeList对象,它包含了所有给定标签名字的标签。
getDocumentElement():返回一个代表这个DOM树的根节点的Element对象,也就是代表XML文档根元素的那个对象。
Node对象是DOM结构中最为基本的对象,代表了文档树中的一个抽象的节点。在实际使用的时候,很少会真正的用到Node这个对象,而是用到诸如Element、Attr、Text等Node对象的子对象来操作文档。Node对象为这些对象提供了一个抽象的、公共的根。虽然在Node对象中定义了对其子节点进行存取的方法,但是有一些Node子对象,比如Text对象,它并不存在子节点,这一点是要注意的。Node对象所包含的主要的方法有:
appendChild(org.w3c.dom.Node):为这个节点添加一个子节点,并放在所有子节点的最后,如果这个子节点已经存在,则先把它删掉再添加进去。
getFirstChild():如果节点存在子节点,则返回第一个子节点,对等的,还有getLastChild()方法返回最后一个子节点。
getNextSibling():返回在DOM树中这个节点的下一个兄弟节点,对等的,还有getPreviousSibling()方法返回其前一个兄弟节点。
getNodeName():根据节点的类型返回节点的名称。
getNodeType():返回节点的类型。
getNodeValue():返回节点的值。
hasChildNodes():判断是不是存在有子节点。
hasAttributes():判断这个节点是否存在有属性。
getOwnerDocument():返回节点所处的Document对象。
insertBefore(org.w3c.dom.Node new,org.w3c.dom.Node ref):在给定的一个子对象前再插入一个子对象。
removeChild(org.w3c.dom.Node):删除给定的子节点对象。
replaceChild(org.w3c.dom.Node new,org.w3c.dom.Node old):用一个新的Node对象代替给定的子节点对象。
NodeList对象,顾名思义,就是代表了一个包含了一个或者多个Node的列表。可以简单的把它看成一个Node的数组,我们可以通过方法来获得列表中的元素:
GetLength():返回列表的长度。
Item(int):返回指定位置的Node对象。
Element对象代表的是XML文档中的标签元素,继承于Node,亦是Node的最主要的子对象。在标签中可以包含有属性,因而Element对象中有存取其属性的方法,而任何Node中定义的方法,也可以用在Element对象上面。
getElementsByTagName(String):返回一个NodeList对象,它包含了在这个标签中其下的子孙节点中具有给定标签名字的标签。
getTagName():返回一个代表这个标签名字的字符串。
getAttribute(String):返回标签中给定属性名称的属性的值。在这儿需要主要的是,应为XML文档中允许有实体属性出现,而这个方法对这些实体属性并不适用。这时候需要用到getAttributeNodes()方法来得到一个Attr对象来进行进一步的操作。
getAttributeNode(String):返回一个代表给定属性名称的Attr对象。
Attr对象代表了某个标签中的属性。Attr继承于Node,但是因为Attr实际上是包含在Element中的,它并不能被看作是Element的子对象,因而在DOM中Attr并不是DOM树的一部分,所以Node中的getparentNode(),getpreviousSibling()和getnextSibling()返回的都将是null。也就是说,Attr其实是被看作包含它的Element对象的一部分,它并不作为DOM树中单独的一个节点出现。这一点在使用的时候要同其它的Node子对象相区别。
需要说明的是,上面所说的DOM对象在DOM中都是用接口定义的,在定义的时候使用的是与具体语言无关的IDL语言来定义的。因而,DOM其实可以在任何面向对象的语言中实现,只要它实现了DOM所定义的接口和功能就可以了。同时,有些方法在DOM中并没有定义,是用IDL的属性来表达的,当被映射到具体的语言时,这些属性被映射为相应的方法。
附录:IDL简介
全称:Interface Description Language
使用Java(TM)编写的API提供基于标准的和CORBA的交互性和连接性。
用于描述接口,类似于PRC的.x文件。接口定义语言类似一个协议,来规定接入对象的行为。
用RPC / COM / CORBA技术来编写分布式系统时都需要接口定义语言(IDL)。
特点:
1、IDL是一种规范语言。
2、IDL看上去很像C语言。
3、OMG IDL的目的是定义接口和精简分布对象的过程。
4、IDL分离对象的接口与其实现。
5、IDL剥离了编程语言和硬件的依赖性。
6、使用IDL定义接口的客户机程序员不知道接口背后的实现细节。
7、IDL提供一套通用的数据类型,并以这些数据类型来定义更为复杂的数据类型。
有关的英文说明:
·Used to describe "interfaces"
similar to RPC .x file
Like a contract
Defines protocol to access objects
·Builds on OOP principle of encapsulation
Clear boundary between implementation and interface
·Well-specified, Language-independent
interface specifies names and methods that clients can use (invoke)
same lexical rules as C++ syntax
IDL modules
– logical grouping of interface and type definitions
– defines naming scope
IDL interface
– methods that are available in CORBA objects implementing the interface
– inheritance using ’:’ for example interface Z inherits interfaces A and B interface Z:A,B{ };
IDL methods
– specify signatures
– parameters are labeled as in, out and inout
– one way indicates that client will not be blocked when invoking this method
these methods use maybe invocation semantics
– raises: user-defined exceptions