欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

XMl解析之DOM解析

程序员文章站 2022-05-29 08:19:23
...

在很早的时候就听说过文件解析,但是一直没有了解,今天了解了一下。其实理解起来并不困难,弄清楚逻辑就行。

首先就是获取到文档对象,一般是用到的是DocumentBuilderFactory.newInstance()来创建一个解析器工厂,然后通过解析器工厂创建解析器,解析器根据传入的路径或File对象生成文档对象。根据文档的内容一层一层往下遍历即可。

package cn.analyse.dom;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Demo {

	public static void main(String[] args) {
		// 创建解析器工厂
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		// 由工厂创建一个DocumentBuilder解析器
		try {
			DocumentBuilder db = factory.newDocumentBuilder();
			// 创建一个Document对象
			Document doc = db.parse("src/student.xml");
			// 获取所有节点
			NodeList nodes = doc.getChildNodes();
			// 获取根节点
			Node root = nodes.item(0);
			System.out.println(root.getNodeName());
			// 获取根节点的所有子节点
			NodeList students = root.getChildNodes();
			for (int i = 0; i < students.getLength(); i++) {
				// 遍历获得根节点的子节点
				Node student = students.item(i);
				// 获得根节点下子节点的所有子节点
				NodeList texts = student.getChildNodes();
				for (int j = 0; j < texts.getLength(); j++) {
					// 遍历根节点下子节点的子节点,并输出其文本内容
					Node text = texts.item(j);
					if (text.getNodeName().equals("stuno")) {
						System.out.println("学号:" + text.getTextContent());
					} else if (text.getNodeName().equals("name")) {
						System.out.println("姓名:" + text.getTextContent());
					} else if (text.getNodeName().equals("sex")) {
						System.out.println("性别:" + text.getTextContent());
					} else if (text.getNodeName().equals("grade")) {
						System.out.println("班级:" + text.getTextContent());
					}
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

这个是我在网上找的一个例子,也可以在遍历子节点的时候用判断来做:

	private void listAllChildNodes(Node node, int level) {
		// 只处理ElementNode类型的节点,感觉这种类型的节点(还有有效的文本节点)才是真正有用的数据,其他注释节点,空白节点等都用不上.
		if (node.getNodeType() == Node.ELEMENT_NODE) {
			boolean hasTextChild = false;// 变量表示该节点的第一个子节点是否就是一个有有效内容的文本节点)
			// Ⅰ❶【打印 - 空格】空格的长度 - level(n级ElementNode有n个长度的空格在前面)
			String levelSpace = "";
			for (int i = 0; i < level; i++) {
				levelSpace += "    ";
			}
			// Ⅱ❷【打印 - 开始标签】先打印ElementNode的开始标签(有属性的话也要打印)
			System.out.print(levelSpace + "<" + node.getNodeName() + (node.hasAttributes() ? " " : ">"));// 有属性的话节点的开始标签后面的尖括号">"就留待属性打印完再打印
			// Ⅲ❸【打印 - 属性】遍历打印节点的所有属性
			if (node.hasAttributes()) {
				NamedNodeMap nnmap = node.getAttributes();
				for (int i = 0; i < nnmap.getLength(); i++) {
					System.out.print(nnmap.item(i).getNodeName() + "=\""// 字符串里含双引号要用到转义字符\
							+ nnmap.item(i).getNodeValue() + "\"" + (i == (nnmap.getLength() - 1) ? "" : " "));// 不是最后一个属性的话属性之间要留空隙
				}
				System.out.print(">");// 开始标签里的属性全部打印完加上尖括号">"
			}
			// Ⅳ❹【打印 - 子节点】该ElementNode包含子节点时候的处理
			if (node.hasChildNodes()) {
				level++;// 有下一级子节点,层次加1,新的层次表示的是这个子节点的层次(递归调用时传给了它)
				// 获得所有的子节点列表
				NodeList nodelist = node.getChildNodes();
				// 循环遍历取到所有的子节点
				for (int i = 0; i < nodelist.getLength(); i++) {
					// Ⅳ❹❶【有效文本子节点】子节点为TextNode类型,并且包含的文本内容有效
					if (nodelist.item(i).getNodeType() == Node.TEXT_NODE
							&& (!nodelist.item(i).getTextContent().matches("\\s+"))) {// 用正则选取内容包含非空格的有效字符的文本节点
						hasTextChild = true;// 该ElementNode的一级子节点是存在有效字符的文本节点
						System.out.print(nodelist.item(i).getTextContent());// 在开始标签后面添加文本内容
						// Ⅳ❹❷【ElementNode子节点】子节点是正常的ElementNode的处理
					} else if (nodelist.item(i).getNodeType() == Node.ELEMENT_NODE) {
						System.out.println();
						// 递归调用方法 - 以遍历该节点下面所有的子节点
						listAllChildNodes((Node) nodelist.item(i), level);// level表示该节点处于第几个层次(相应空格)
					}
				}
				level--;// 遍历完所有的子节点,层次变量随子节点的层数,依次递减,回归到该节点本身的层次
				// level++ 和 level--对于该节点的子节点影响的是子节点的初值
			}
			// Ⅴ❺【打印 - 结束标签】打印元素的结束标签.如果它的第一个一级子节点是有效文本的话,文本和结束标签添加到开始标签后面,
			// 层次什么的就作废用不上了,否则,才按层次打印结束标签.
			System.out.print(((hasTextChild) ? "" : "\n" + levelSpace) + "</" + node.getNodeName() + ">");
		}

大体的情况就是这样,网上的说明也很详细,动手试一下就会明白!