Java中解析XML文件的方式有四种,分别是:
- DOM解析
- SAX解析
- DOM4J解析
- JDOM解析
其中,DOM和SAX是Java内置提供的解析方式,无需引用JAR包;而DOM4J和JDOM则是第三方提供的,需要引入相应JAR包才可使用。
本篇文章介绍DOM解析。
DOM解析的基本步骤如下:
- 创建DocumentBuilderFactory的对象(通过newInstance()方法)
- 创建DocumentBuilder的对象(通过DocumentBuilderFactory的newDocumentBuilder()方法)
- 通过DocumentBuilder对象的parse()方法对xml文件进行解析
下面开始动手操作:
首先,先创建一个xml文件。这里以books.xml为例,记录两本书的信息。
books.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="1">
<name>冰与火之歌</name>
<author>乔治马丁</author>
<price>89</price>
</book>
<book id="2">
<name>安徒生通话</name>
<author>安徒生</author>
<price>24</price>
</book>
</bookstore>
该XML文件的根节点为bookstore,可以理解为这个文件就相当于是一家书店,而其中每个book节点都是一本书,文件中存储了这些书的书名、作者、价格信息。
为了与books.xml文件对应,需要定义一个Book类来封装书的那些属性。
package domain;
public class Book {
private String name;
private String author;
private float price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
@Override
public String toString() {
return "Book [name=" + name + ", author=" + author + ", price=" + price + "]";
}
}
准备工作做完了,下面就该对XML文件进行解析。
第一步:创建DocumentBuilderFactory对象
//创建DocumentBuilderFactory的对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
第二步:创建DocumentBuilder对象
//通过DocumentBuilderFactory创建一个DocumentBuilder对象
DocumentBuilder builder = factory.newDocumentBuilder();
第三步:通过DocumentBuilder对象的parse()方法对XML文件进行解析
//通过DocumentBuilder对象的parse方法解析xml文件,并用Document对象接收
Document document = builder.parse(file);
接下来,就该获取XML文件中的内容了。
由于我们需要获取每一本书的信息,所以我们可以对每个book节点进行解析。
使用getElementsByTagName()方法,可以获取所有指定名称的节点。这里我们需要获取所有的book节点:
//通过document.getElementsByTagName获取所有名为book的节点的集合
NodeList bookList = document.getElementsByTagName("book");
通过getLength()方法,可以获得book节点集合的长度,相当于总共有多少本书。
System.out.println("共有 " + bookList.getLength() + " 本书");
接下来,需要遍历所有的书,并记录下他们的信息。
在XML文件中可以看到,我们为每本书指定了一个id属性,现在我们来获取这个id。由于id是book节点的属性,所以我们需要获取book的所有属性。
通过item()方法可以获得一个NodeList中的某个元素。
Node book = bookList.item(0);//获取NodeList中的第一个元素,即第一本书
通过getAttributes可获取该书的所有属性,可以对这些属性进行遍历并打印这些属性:
NamedNodeMap attrs = book.getAttributes();
for(int k=0; k<attrs.getLength(); ++k){
Node node = attrs.item(k);
System.out.println(node.getNodeName() + " : " + node.getNodeValue());
}
这样,book节点的属性就获取到了。
接下来,获取book的所有子节点(即书的属性)。
通过getChildNodes()方法可以获取当前节点的所有子节点的集合:
NodeList child = book.getChildNodes();
接下来获取每个子节点的属性。
遍历每个子节点,并获取他们的节点名称和值:
for(int j=0; j<child.getLength(); ++j){
Node node = child.item(j);
//过滤掉换行、空格等text类型的节点,只保留带标签的元素节点
if(node.getNodeType() == Node.ELEMENT_NODE){
//标签之间的内容被认为是该标签的子节点,所以需要使用node.getFirstChild()获取到这个子节点的第一个孩子节点后再获取其值,并封装到一个Book类的对象中即可。
switch(node.getNodeName()){
case "name" :
aBook.setName(node.getFirstChild().getNodeValue());
break;
case "author" :
aBook.setAuthor(node.getFirstChild().getNodeValue());
break;
case "price":
aBook.setPrice(Float.valueOf(node.getFirstChild().getNodeValue()));
break;
}
//使用getTextContent()方法可获取该标签节点下的所有子节点内容
// System.out.println(node.getNodeName() + " : " + node.getTextContent());
}
}
完整的程序代码:
package utils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import domain.Book;
public class ParseUtil {
/*
* DOM解析
* */
public static void parseByDOM(File file){
//创建DocumentBuilderFactory的对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
//通过DocumentBuilderFactory创建一个DocumentBuilder对象
DocumentBuilder builder = factory.newDocumentBuilder();
//通过DocumentBuilder对象的parse方法解析xml文件,并用Document对象接收
Document document = builder.parse(file);
//通过document.getElementsByTagName获取所有名为book的节点的集合
NodeList bookList = document.getElementsByTagName("book");
System.out.println("共有 " + bookList.getLength() + " 本书");
//遍历每一本书
for(int i=0; i<bookList.getLength(); ++i){
System.out.println("第" + (i+1) + "本书:");
Node book = bookList.item(i);
Book aBook = new Book();
//获取book节点的所有属性
NamedNodeMap attrs = book.getAttributes();
for(int k=0; k<attrs.getLength(); ++k){
Node node = attrs.item(k);
System.out.println(node.getNodeName() + " : " + node.getNodeValue());
}
//获取book节点的所有子节点的 名及值
NodeList child = book.getChildNodes();
for(int j=0; j<child.getLength(); ++j){
Node node = child.item(j);
//过滤掉换行、空格等text类型的节点,只保留带标签的元素节点
if(node.getNodeType() == Node.ELEMENT_NODE){
//标签之间的内容被认为是该标签的子节点,所以需要使用node.getFirstChild()获取到这个子节点的第一个孩子节点后再获取其值
switch(node.getNodeName()){
case "name" :
aBook.setName(node.getFirstChild().getNodeValue());
break;
case "author" :
aBook.setAuthor(node.getFirstChild().getNodeValue());
break;
case "price":
aBook.setPrice(Float.valueOf(node.getFirstChild().getNodeValue()));
break;
}
//使用getTextContent()方法可获取该标签节点下的所有子节点内容
// System.out.println(node.getNodeName() + " : " + node.getTextContent());
}
}
System.out.println(aBook);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
输出的结果:
共有 2 本书
第1本书:
id : 1
Book [name=冰与火之歌, author=乔治马丁, price=89.0]
第2本书:
id : 2
Book [name=安徒生童话, author=安徒生, price=24.0]