DOM概述
- DOM全称为Document Object
Model,中文名为文档对象模型,是W3C组织推荐的处理可扩展置标语言的标准编程接口。它是一种与平台和语言无关的应用程序接口(API),它可以动态地访问程序和脚本,更新其内容、结构和www文档的风格。 - DOM是把整个XML文件看成是一个倒挂的树形结构来解析,其中使用的包是org.w3c.dom。
XML文件
现在有一个文件名为department.xml的XML文件,文件所在位置为Java文件所在的文件夹下,文件内容如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<department>
<student>
<name id="100">阿伟</name>
<age>20</age>
</student>
<student>
<name>杰哥</name>
<age>40</age>
</student>
<student>
<name>彬彬</name>
<age>20</age>
</student>
</department>
在XML文件中,一切皆为节点
使用DOM获取一个节点的名称和值
在解析XML文件时,需要获取节点的值和名称。首先要先获取根节点,然后才能对根节点进行操作来获取子节点的名称或值。获取根节点需要通过四个步骤:
- 获取DocumentBuilderFactory解析工厂对象
- 通过DocumentBuilder解析工厂对象,获取解析对象
- 通过文档解析器Document获取文档对象
- 获取根节点root
//单例模式,获取document解析工厂对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//通过文档解析工厂对象,获取解析对象
DocumentBuilder builder = factory.newDocumentBuilder();
//通过文档解析器获取文档对象
Document doc = builder.parse("department.xml");
//获取根节点
Element root = doc.getDocumentElement();
获取到根节点之后,需要通过几个常用方法来获取XML中节点的名称或值:
- getFirstChild():获取此节点的第一个子节点
- getNextSibling():获取此节点的下一个兄弟节点
- getTextContent():获取此节点的文本内容
然后先来看看XML文件的构造:
假如想获取student下面的name中的值,一般情况下只需要获取到student节点,它的第一个子节点即是我们要找的值,用上述函数表示就是:
root.getFirstChild().getFirstChild().getTextContent()
但是实际运行起来,却根本无法找到name里的内容。
原因是:在XML里,一切皆为节点
因为要保证XML文件代码的可读性和美观,人们编写XML文件时喜欢进行换行,平时看不见的换行符在XML里也作为节点被看待,所以在department.xml文件中,student节点存在一个兄弟节点,也就是看不见的换行。所以要找到name节点的节点名称和name的值时,用上述函数正确表示为:
//万物皆为节点
//获取节点名称"name"并输出
System.out.println(root.getFirstChild().getNextSibling().getFirstChild().getNextSibling().getNodeName());
//获取"name"的值"阿伟"并输出
System.out.println(root.getFirstChild().getNextSibling().getFirstChild().getNextSibling().getTextContent());
编写工具类解析XML的所有节点
上述是使用DOM解析XML的基本操作。因为“一切皆为节点”的缘故,解析过程繁琐且不灵活。为了解析更为方便,我们可以编写一个工具类来方便解析。其中用到了NameNodeMap接口和方法:
- NameNodeMap接口:表示可以通过名称访问的节点的集合
- item():返回NameNodeMap集合中第 index 个项
- getLength():获取NameNodeMap集合的长度
封装获取文档对象代码。
public static Document getDocumentObject(String xmlName) throws ParserConfigurationException, SAXException, IOException {
//单例模式,获取document解析工厂对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//通过文档解析工厂对象,获取解析对象
DocumentBuilder builder = factory.newDocumentBuilder();
//通过文档解析器获取文档对象
Document doc = builder.parse(xmlName);
return doc;
}
定义visit()方法用于解析。
public static void visit(Node start) {
System.out.println(start.getNodeName()+"···"+start.getNodeValue());
//确保传递的节点对象是Element
//因为Attriubte一定是在Element中
if(start.getNodeType() == Node.ELEMENT_NODE) {
NamedNodeMap nnm = start.getAttributes();
//处理属性节点对象
for(int i = 0;i < nnm.getLength();i++) {
//通过NameNodeMap获取节点索引,便于循环操作
Node attr = nnm.item(i);
System.out.println(attr.getNodeName()+"···"+attr.getNodeValue());
}
for(Node sub = start.getFirstChild();sub != null;sub = sub.getNextSibling()) {
visit(sub);
}
}
}
工具类完整代码
public class DOMTool {
public static Document getDocumentObject(String xmlName) throws ParserConfigurationException, SAXException, IOException {
//单例模式,获取document解析工厂对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//通过文档解析工厂对象,获取解析对象
DocumentBuilder builder = factory.newDocumentBuilder();
//通过文档解析器获取文档对象
Document doc = builder.parse(xmlName);
return doc;
}
public static void visit(Node start) {
System.out.println(start.getNodeName()+"···"+start.getNodeValue());
//确保传递的节点对象是Element
//因为Attriubte一定是在Element中
if(start.getNodeType() == Node.ELEMENT_NODE) {
NamedNodeMap nnm = start.getAttributes();
//处理属性节点对象
for(int i = 0;i < nnm.getLength();i++) {
//通过NameNodeMap获取节点索引,便于循环操作
Node attr = nnm.item(i);
System.out.println(attr.getNodeName()+"···"+attr.getNodeValue());
}
for(Node sub = start.getFirstChild();sub != null;sub = sub.getNextSibling()) {
visit(sub);
}
}
}