在JAVA中XML解析可以使用DOM,SAX,JDOM,JAXB四种方式。
DOM是基于树和节点的文档对象模型(Document Object Module)。DOM编程不要其它的依赖包,因为JDK里自带的JDK里含有的解析所需要用到的org.w3c.dom和javax.xml.parsers等包。DOM不适合于解析较大的XML文件,因为它会将XML全部加载到内存,如果XML文件很大,则会很费内存,而且解析得很慢。这点在使用时应考虑。
本次示例中,我们将解析一个XML文件,并将其数据保存到一个VO对象集合中。
(1)book.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person id="0001">
<name>Smith</name>
<sex>male</sex>
<age>20</age>
</person>
<person id="0002">
<name>Tom</name>
<sex>male</sex>
<age>22</age>
</person>
<person id="0003">
<name>Tom</name>
<sex>female</sex>
<age>33</age>
</person>
</persons>
(2)建立一个Person.java的VO对象
public class Person {
private String id;
private String name;
private String sex;
private int age;
//省略了Getter和Setter方法
}
(3)DOM解析XML文件的代码如下:
package review.fileoper;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class DomParseXMLTest {
/**
* DOM解析XML文件
* @param file
* @return
* @throws Exception
*/
public List<Person> domParseXML(File file) throws Exception{
List<Person> personList = new ArrayList<Person>(); //保存解析得到的Person对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(file);
// 获得文档的根元素
Element element = doc.getDocumentElement();
// 根据节点名来获得所有的person元素
NodeList personNodes = element.getElementsByTagName("person");
for (int i = 0; i < personNodes.getLength(); i++) {
Element personEle = (Element) personNodes.item(i);
Person p = new Person();
// 得到节点的属性值
p.setId(personEle.getAttribute("id"));
// 得到元素下的所有子节点
NodeList personMeta = personEle.getChildNodes();
// System.out.println("personMeta.getLength() = " + personMeta.getLength());
for (int j = 0; j < personMeta.getLength(); j++) {
Node meta = personMeta.item(j);
if("name".equals(meta.getNodeName())){
p.setName(meta.getTextContent());
}else if("sex".equals(meta.getNodeName())){
p.setSex(meta.getTextContent());
}else if("age".equals(meta.getNodeName())){
p.setAge(Integer.parseInt(meta.getTextContent()));
}
}
personList.add(p);
}
return personList;
}
/**
* 打印解析得到的结果personList
* @param personList
*/
public void printPerson(List<Person> personList){
System.out.println("----------printPerson------------");
for(Person per : personList){
System.out.println("id:" + per.getId() + ",name : " + per.getName()
+ "\nsex : " + per.getSex() + ",age: " + per.getAge());
}
}
public static void main(String[] args) throws Exception {
DomParseXMLTest test = new DomParseXMLTest();
//获得工程的根目录
String root = DomParseXMLTest.class.getResource("/").getPath();
// InputStream is = DomParseXMLTest.class.getClassLoader().getResourceAsStream("person.xml");
File file = new File(root + "/review/fileoper/person.xml");
List<Person> personList = test.domParseXML(file);
test.printPerson(personList);
}
}
运行结果如下:
DOM解析的过程中,我们需要注意以下几点:
(1)获得元素子节点的问题
代码中personMeta.getLength()的结果为7,这可能让多数初学者困惑不已,XML文件中person节点下明明只有三个子节点,怎么会变成7个了呢,我们可以调试程序发现了下面的结果:
事实上XML文件中各节点之间都存在换行符“\n\t”或者“\n\t\t”等,DOM解析时也会把它当成是一个子节点(文本节点)所以就会比我们预期的要多,person节点的子节点分布如下图,其中1、3、5、7都是换行符。文本节点的类型是“#text”,值为“[\n[\t]*]+”。大家也可以试下,把上面的XML文件中的内容写在一行,这样解析的结果就变成我们预期的3个子节点了
(2)谈下Node 和Element的区别
Node(节点)是DOM层次结构中的任何类型的对象的通用名称,Node有很多类型,如元素节点,属性节点,文本节点,注释节点等,通过NodeType区分,常见的有:
枚举值 | 对应类型 |
ELEMENT_NODE | Element节点 |
ATTRIBUTE_NODE | Attr节点 |
TEXT_NODE | 文本节点 |
COMMENT_NODE | Comment节点 |
DOCUMENT_NODE | Document节点 |
DOCUMENT_TYPE_NODE | DocumentType节点 |
NOTATION_NODE | 注释节点 |
而Element是继承自Node接口,范围比Node要小,必须是含有完整信息的节点才是一个元素,一个节点不一定是一个元素,但元素一定是一个结点
node只是具有了一些通用的方法,而element则具有更具体的功能,尤其是对节点的属性值操作更加方便,具体可以查看API文档。