Java 解析XML文档(DOM & SAX)

时间:2022-10-31 13:34:58

要处理XML文档,就要像解析(parse)。就要用到解析器。
解析器的工作原理是这样的:它读入一个文件,确认这个文件具有正确的格式,然后将其分解成各种元素,使得程序员能够访问这些元素。


Java库提供了两种XML解析器:

  • 像文档对象模型解析器(Document Object Model,DOM),这样的树形解析器,它将读入的XML文档转换成树形结构。
  • 像XML简单API解析器(Simple API for XML,SAX),这样的流机制解析器,它在读取XML文档时生成相应的事件。

现在我自己在工程中用的最多的是DOM的树形解析器,相比流机制解析器,它相对来说更容易一些。如果你要处理很长的文档,用它生成树结构将会消耗大量的内存,或者如果你只是对于某些元素感兴趣,而不关心他们的上下文,那么在这些情况下你应该考虑使用流机制解析器。

要读入一个XML文档,首先需要一个DocumentBuilder对象,其中DocumentBuilderFactory是DocumentBuilder的子类,所以我们只需要创建子类对象就得可以得到需要的父类对象。

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();

接着从文件中读入某个文档:

    File f = "这里写文件路径";
Document doc = builder.parse(f);

或者可以用个URL:

    URL u = "...";
Document doc = builder.parse(u);

甚至可以指定一个输入流:

    InputStream in = ...
Document doc = builder.parse(in);

在XML文档中的一般格式是这样的:

<?xml version = "1.0" ?>
<config>
<className>
edu.fjnu.Computer.Sever
</className>
<name>???</name>
<size></size>
</config>

调用getDocumentElement方法可以返回config元素。getTagName方法可以返回元素的标签名。在前面的例子中返回的就是字符串“config”。
如果要得到该元素的子元素,就需要使用getChile Nodes方法,这个方法返回一个类型为NodeList的集合。这个类型在标准的Java集合类创建之间在存在了,它有一个不同的访问协议;item方法将得到指定索引值的项;getLength方法则提供了项的总数。

    Element root = document.getDocumentElement();
System.out.println(root.getTagName());
NodeList children = root.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
...
}

注意 解析器会把节点之间的空白元素当做是子元素。

如果你只需要子元素就这么写:

   for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child instanceof Element) {
Element childElement = (Element) child;
System.out.println(childElement.getNodeName().toString());
}
}

如果你需要的是节点中的信息,你就只需要调用getData().trim()方法(如果直接使用getData方法挥造成数据中有空白符,trim可以解决这个问题)。


再比如要枚举节点的属性,可以调用getAttributes方法。它返回一个NamedNodeMap对象,其中包含了描述属性的Node对象。可以用遍历NodeList一样的办法在NamedNodeMap中遍历各子节点。调用getNodeName和getNodeValue方法可以得到属性和属性值。


下面是配合反射的用法,从一个XML文件中获取节点信息,接着利用反射得到一个对象,在设计模式中使用的比较多。

package edu.fjnu.Computer;

/**
* Created by Administrator on 2017/3/20 0020.
*/


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

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;

public class XMLUtil {
/**
* 从配置文件中获取具体类名
* @return
*/

public static Object getBean() {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("Computer.xml"));

NodeList nodeList = doc.getElementsByTagName("className");
Node node = nodeList.item(0).getFirstChild();
String cname = node.getNodeValue();

// System.out.println(cname);
//这里是反射的用法,需要写全名
Class c = Class.forName(cname);
Object object = c.newInstance();
System.out.println(c.getName());
return object;

//return new SqlFactory();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

在你的Java工程中添加一个新的类:XMLUtil.java
大家看到在上面的代码中有个绝对路径文件
new File(“Computer.xml”)
就是在你的工程文件下要新建一个Computer.xml文件,里面要写上对应的内容,我的是这样的:

<?xml version = "1.0" ?>
<config>
<className>
edu.fjnu.Computer.Sever
</className>
</config>

上面的className就是我们在代码中设置的对应节点,这当中的信息就是我们要提取的。
就这么简单。