DOM解析XML文件
程序员文章站
2022-05-29 08:21:05
...
DOM的全称是Document Object Model,也即文档对象模型。在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),应用程序正是通过对这个对象模型的操作,来实现对XML文档数据的操作。通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此,这种利用DOM 接口的机制也被称作随机访问机制。
对于XML应用开发来说, DOM就是一个对象化的XML数据接口,一个与语言无关、与平台无关的标准接口规范。它定义了HTLM文档和XML 文档的逻辑结构,给出了一种访间和处理HTML文档和XML 文档的方法。利用DOM, 程序开发人员可以动态地创建文档,遍历文档结构,添加、修改、删除文档内容,改变文档的显示方式等等。
文档代表的是数据,而DOM则代表了如何去处理这些数据。在Java中最常用作配置文件。我们最常做的就是“获取”。
Java中一切皆对象,DOM中一切皆节点。
最常见的节点类型:
- 元素节点:元素是XML 的基本构件。元素可以由其它元素、文本节点或两者都有来作为其子节点。元素节点还是可以有属性的唯一类型的节点。
- 属性节点:属性节点包含关于元素节点的信息,但实际上,不认为它是元素的子节点!
- 文本节点:确切来讲,文本节点是文本。它可以包含许多信息或仅仅是空白。(空白部分也算文本节点)
- 文档(根节点):文档节点是整个文档中所有其它节点的父节点. (根节点不等于根元素节点)
在DOM接口规范中,有四个基本的接口: Document, Node, NodeList 以及NamedNodMap。
- Document 接口是对文档进行操作的入口。它是从Node接口继承过来的。
- Node接口是其他大多数接口的父类,像Document(文档) Element(元素) Attr(属性) Text(文本) Comment(注释)等接口都是从Node接口继承过来的。
- NodeList接口是一个节点的集合,它包含了某个节点中的所有子节点。
- NamedNodMap接口也是一个节点的集合,通过该接口,可以建立节点名和节点之间的一映射关系,从而利用节点名可以直接访问特定的节点。
平常我们最常操作的四个对象:
- Node对象: DOM 结构中最为基本的对象
- Document对象:代表整个XML的文档。(通过它可以获取整个文档的所有内容)
- NodeList对象: 包含一 个或者多个Node的列表。
- Element对象:代表XML文档中的标签元素。
概念性问题我觉得了解以上这些就可以了,下面用程序来说明。注释已经说的很清楚了。
先来看xml文件结构
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<mapping>
<property name = "haha" age = "17">123</property>
<property name = "heihei" age = "18"></property>
</mapping>
<mapping></mapping>
</mappings>
public class Test {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); //获的文档解析工厂
DocumentBuilder db = dbf.newDocumentBuilder(); //获取文档解析器
InputStream is = Test.class.getResourceAsStream("/config.xml"); //加载xml文件资源
Document doc = db.parse(is); //解析获取Document对象
Element root = doc.getDocumentElement(); //获取根标签元素
parseElement(root);
}
//递归遍历文档内所有节点 =====> Node 可以判断其节点类型 //XML中一切都是节点
public static void parseElement(Element element) {
//显示开始标签
String tagName = element.getTagName(); //利用元素Element对象获取标签名。例如<mappings> ---> mappings
StringBuffer sb = new StringBuffer("<" + tagName);
NamedNodeMap attrMap = element.getAttributes();
for(int index = 0; index < attrMap.getLength(); index++) {
Attr attr = (Attr) attrMap.item(index); //获取属性对象Attr
String attrName = attr.getName(); //获取属性名
String attrValue = attr.getValue(); //获取属性值
sb.append(" " + attrName + " = \"" + attrValue + "\"");
}
System.out.print(sb.append(">").toString());
NodeList nodeList = element.getChildNodes(); //获取该元素节点的所有子节点(包含该元素节点下的所有文本节点,子元素节点,注释节点等)
for(int index = 0; index < nodeList.getLength(); index++) {
Node charNode = nodeList.item(index);
short nodeType = charNode.getNodeType(); //获取节点类型
switch (nodeType) {
case Node.ELEMENT_NODE:
parseElement((Element)charNode);//如果是元素(即可能存在子元素),递归判断
break;
case Node.TEXT_NODE: //如果是文本
System.out.print(charNode.getTextContent()); //获取文本内容
break;
case Node.COMMENT_NODE: //如果是注释
System.out.print("<!-- " + ((Comment) charNode).getData() + " -->"); //获取注释内容
break;
default:
break;
}
}
//显示结束标签
System.out.print("</" + tagName +">");
}
}
输出结果:
对该xml文件,就程序的流程:
- 输出:<mappings>
- 遇到文本节点(即第一行与第二行之间的空白内容)原样输出
- 遇到元素节点再次执行方法(进入递归),输出:空白内容 + <property name = "haha" age = "17">123</property>
- ......
工具化:
为了方便以后的操作,自制解析工具如下:
public abstract class MecXmlParse {
private static DocumentBuilder db = null;
static {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); //获取文档解析工厂
try {
db = dbf.newDocumentBuilder(); //获取文档解析器
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
public MecXmlParse() {}
//拿到Document对象
public static Document load(String filePath) throws FileNotFoundException {
InputStream fis = null;
try {
fis = MecXmlParse.class.getResourceAsStream(filePath);
return db.parse(fis);
} catch (Exception e) {
throw new FileNotFoundException("[" + filePath + "]");
}finally {
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void parseTag(Document document, String tagName) {
NodeList nodeList = document.getElementsByTagName(tagName);
for(int index = 0; index < nodeList.getLength(); index++) {
Element element = (Element) nodeList.item(index);
dealElement(element, index);
}
}
public Element getRoot(Document document) {
return document.getDocumentElement(); //获取根节点
}
public void parseNode(Element element) {
NodeList nodeList = element.getChildNodes();
for(int index = 0; index < nodeList.getLength(); index++) {
Node node = nodeList.item(index);
if(node.getNodeType() == Node.ELEMENT_NODE) {
dealElement((Element)node, index); //给的工具中只处理元素
}
}
}
public abstract void dealElement(Element element, int index);
}
测试:
public class Test02 {
public static void main(String[] args) {
MecXmlParse parse = new MecXmlParse() {
@Override
public void dealElement(Element element, int index) {
String tagName = element.getTagName();
System.out.print("\n<" + tagName +">");
parseNode(element);
System.out.print("</" + tagName + ">\n");
}
};
try {
Element root = parse.getRoot(MecXmlParse.load("/config.xml"));
parse.parseNode(root);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
结果:
上一篇: macOS安装anaconda之后无法进入本地其他的虚拟环境
下一篇: DOM解析XML文件