DOM(Document Object Model)是一種處理XML文檔的技術(shù),通過DOM能夠讀取、修改XML文檔。本例將介紹用DOM處理XML文檔,把一個描述學(xué)生信息的XML文檔讀到內(nèi)存中,構(gòu)成多個學(xué)生對象,然后把這些學(xué)生對象的信息保存到另一個XML文檔中。
DOM將整個XML文檔讀到內(nèi)存中,用基本對象描述XML文檔的元素,基本對象之間以樹形的結(jié)構(gòu)組織。
DOM常用的基本對象類有5個:
org.w3c.dom.Document:該類的對象代表了整個XML的文檔,所有其他的XML元素,都以一定的順序包含在Document對象內(nèi),排列成一個樹形結(jié)構(gòu),可以通過遍歷這棵樹來得到XML文檔的所有內(nèi)容,這也是對XML文檔操作的起點(diǎn)。
org.w3c.dom.Node:該類是一個接口類,定義了DOM結(jié)構(gòu)中的一個抽象的節(jié)點(diǎn)。
org.w3c.dom.NodeList:該對象代表了一個包含多個Node的列表。
org.w3c.dom.Element:該對象代表的是XML文檔中的標(biāo)簽元素,繼承與Node.在標(biāo)簽中可以包含屬性,因此Element對象中的存取其屬性的方法。
org.w3c.dom.Attr:該對象代表了某個標(biāo)簽中的屬性。繼承于Node,但是因為Attr實(shí)際上是包含在Element中的,所以Attr并不是DOM樹的一部分。
通過DOM解析器工廠DocumentBuilderFactory的newDocumentBuilder方法可以創(chuàng)建一個DOM解析器對象,類型為DocumentBuilder,它的parse方法能夠?qū)ML文檔讀取到內(nèi)存,返回一個Document對象。
通過DocumentBuilder的newDocument方法創(chuàng)建一個新的XML文檔,返回一個Document對象。通過Document的appendChild方法往文檔中添加子節(jié)點(diǎn)。
使用JAXP(Java API for XML Processing)技術(shù)能將Document對象存儲到文件中。根據(jù)Document對象創(chuàng)建DOMSource,使用Transformer的transform方法將DOMSource轉(zhuǎn)換成XML文檔。

/**-------------------------------------StudentBean.java-----------------------------------------------*/
/**
* 描述學(xué)生的JavaBean
*/
public class StudentBean {
// 學(xué)生姓名
private String name;
// 學(xué)生性別
private String gender;
// 學(xué)生年齡
private int age;
// 學(xué)生電話號碼
private String phone;

public String toString(){
StringBuffer sb = new StringBuffer();
sb.append("姓名:").append(this.name).append("; ");
sb.append("性別:").append(gender).append("; ");
sb.append("年齡:").append(age).append("; ");
sb.append("電話:").append(phone);
return sb.toString();
}
/**
* @return 返回 age。
*/
public int getAge() {
return age;
}
/**
* @param age 要設(shè)置的 age。
*/
public void setAge(int age) {
this.age = age;
}
/**
* @return 返回 gender。
*/
public String getGender() {
return gender;
}
/**
* @param gender 要設(shè)置的 gender。
*/
public void setGender(String gender) {
this.gender = gender;
}
/**
* @return 返回 name。
*/
public String getName() {
return name;
}
/**
* @param name 要設(shè)置的 name。
*/
public void setName(String name) {
this.name = name;
}
/**
* @return 返回 phone。
*/
public String getPhone() {
return phone;
}
/**
* @param phone 要設(shè)置的 phone。
*/
public void setPhone(String phone) {
this.phone = phone;
}
}
/**----------------------------------DomXML.java------------------------------------*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

/**
* dom的基本對象有5個:document,node,nodelist,element和attr
* document對象代表了整個xml的文檔,所有其它的node,都以一定的順序包含在document對象之內(nèi),排列成一個樹形的結(jié)構(gòu),程序員可以通過遍歷這顆樹來得到xml文檔的所有的內(nèi)容,這也是對xml文檔操作的起點(diǎn)。我們總是先通過解析xml源文件而得到一個document對象,然后再來執(zhí)行后續(xù)的操作.
* node對象是dom結(jié)構(gòu)中最為基本的對象,代表了文檔樹中的一個抽象的節(jié)點(diǎn)。在實(shí)際使用的時候,很少會真正的用到node這個對象,而是用到諸如element、attr、text等node對象的子對象來操作文檔。node對象為這些對象提供了一個抽象的、公共的根。雖然在node對象中定義了對其子節(jié)點(diǎn)進(jìn)行存取的方法,但是有一些node子對象,比如text對象,它并不存在子節(jié)點(diǎn),這一點(diǎn)是要注意的。
* nodelist對象,顧名思義,就是代表了一個包含了一個或者多個node的列表.
* element對象代表的是xml文檔中的標(biāo)簽元素,繼承于node,亦是node的最主要的子對象。在標(biāo)簽中可以包含有屬性,因而element對象中有存取其屬性的方法,而任何node中定義的方法,也可以用在element對象上面。
* attr對象代表了某個標(biāo)簽中的屬性。attr繼承于node,但是因為attr實(shí)際上是包含在element中的,它并不能被看作是element的子對象,因而在dom中attr并不是dom樹的一部分,所以node中的getparentnode(),getprevioussibling()和getnextsibling()返回的都將是null。也就是說,attr其實(shí)是被看作包含它的element對象的一部分,它并不作為dom樹中單獨(dú)的一個節(jié)點(diǎn)出現(xiàn)。這一點(diǎn)在使用的時候要同其它的node子對象相區(qū)別。
*/
public class DomXML {

public static List readXMLFile(String inFile) throws Exception {
// 得到DOM解析器的工廠實(shí)例
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = null;
try {
// 從DOM工廠獲得DOM解析器
db = dbf.newDocumentBuilder();
} catch (ParserConfigurationException pce) {
System.err.println(pce);
return null;
}

Document doc = null;
try {
// 解析XML文檔的輸入流,得到一個Document
doc = db.parse(inFile);
// 對document對象調(diào)用normalize(),可以去掉xml文檔中作為格式化內(nèi)容的空白,
// 避免了這些空白映射在dom樹中成為不必要的text node對象。
// 否則你得到的dom樹可能并不是你所想象的那樣。
// 特別是在輸出的時候,這個normalize()更為有用。
doc.normalize();
} catch (DOMException dom) {
System.err.println(dom.getMessage());
return null;
} catch (IOException ioe) {
System.err.println(ioe);
return null;
}

List studentBeans = new ArrayList();
StudentBean studentBean = null;
// 得到XML文檔的根節(jié)點(diǎn)“學(xué)生花名冊”
Element root = doc.getDocumentElement();
// 取"學(xué)生"元素列表
NodeList students = root.getElementsByTagName("學(xué)生");
for (int i = 0; i < students.getLength(); i++) {
// 依次取每個"學(xué)生"元素
Element student = (Element) students.item(i);
// 創(chuàng)建一個學(xué)生的Bean實(shí)例
studentBean = new StudentBean();
// 取學(xué)生的性別屬性
studentBean.setGender(student.getAttribute("性別"));
// 取“姓名”元素
NodeList names = student.getElementsByTagName("姓名");
if (names.getLength() == 1) {
Element e = (Element) names.item(0);
// 取姓名元素的第一個子節(jié)點(diǎn),即為姓名的值節(jié)點(diǎn)
Text t = (Text) e.getFirstChild();
// 獲取值節(jié)點(diǎn)的值
studentBean.setName(t.getNodeValue());
}

// 取“年齡”元素
NodeList ages = student.getElementsByTagName("年齡");
if (ages.getLength() == 1) {
Element e = (Element) ages.item(0);
Text t = (Text) e.getFirstChild();
studentBean.setAge(Integer.parseInt(t.getNodeValue()));
}

// 取“電話”元素
NodeList phones = student.getElementsByTagName("電話");
if (phones.getLength() == 1) {
Element e = (Element) phones.item(0);
Text t = (Text) e.getFirstChild();
studentBean.setPhone(t.getNodeValue());
}
// 將新建的Bean加到結(jié)果列表中
studentBeans.add(studentBean);
}
// 返回結(jié)果列表
return studentBeans;
}
/**
* 用DOM寫XML文檔,把學(xué)生信息以XML文檔的形式存儲
* @param outFile 輸出XML文檔的路徑
* @param studentGeans 學(xué)生信息
* @throws Exception
*/
public static String writeXMLFile(String outFile, List studentGeans) throws Exception {
//為解析XML作準(zhǔn)備,創(chuàng)建DocumentBuilderFactory實(shí)例,指定DocumentBuilder
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = null;
try {
db = dbf.newDocumentBuilder();
} catch (ParserConfigurationException pce) {
System.err.println(pce);
return null;
}
// 新建一個空文檔
Document doc = null;
doc = db.newDocument();

// 下面是建立XML文檔內(nèi)容的過程.
// 先建立根元素"學(xué)生花名冊",并添加到文檔中
Element root = doc.createElement("學(xué)生花名冊");
doc.appendChild(root);

//取學(xué)生信息的Bean列表
for (int i = 0; i < studentGeans.size(); i++) {
// 依次取每個學(xué)生的信息
StudentBean studentBean = (StudentBean) studentGeans.get(i);
// 建立“學(xué)生”元素,有一個“性別”屬性,然后添加到根元素
Element student = doc.createElement("學(xué)生");
student.setAttribute("性別", studentBean.getGender());
root.appendChild(student);
// 建立"姓名"元素,添加到學(xué)生下面
Element name = doc.createElement("姓名");
student.appendChild(name);
// 為“姓名”元素賦值
Text tName = doc.createTextNode(studentBean.getName());
name.appendChild(tName);
// 建立“年齡”元素,然后給元素賦值
Element age = doc.createElement("年齡");
student.appendChild(age);
Text tAge = doc .createTextNode(
String.valueOf(studentBean.getAge()));
age.appendChild(tAge);
// 建立“電話”元素,然后給元素賦值
Element phone = doc.createElement("電話");
student.appendChild(phone);
Text tPhone = doc.createTextNode(studentBean.getPhone());
phone.appendChild(tPhone);
}
// 把XML文檔輸出到指定的文件
return domDocToFile(doc, outFile, "GB2312");
}
/**
* 使用JAXP將DOM對象寫到XML文檔里
* @param doc DOM的文檔對象
* @param fileName 寫入的XML文檔路徑
* @param encoding XML文檔的編碼
* @throws TransformerException
*/
public static String domDocToFile(Document doc, String fileName, String encoding)
throws TransformerException {
// 首先創(chuàng)建一個TransformerFactory對象,再由此創(chuàng)建Transformer對象。
// Transformer類相當(dāng)于一個XSLT引擎。通常我們使用它來處理XSL文件,
// 但是在這里我們使用它來輸出XML文檔。
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
// 獲取Transformser對象的輸出屬性,亦即XSLT引擎的缺省輸出屬性,是java.util.Properties對象
Properties properties = transformer.getOutputProperties();
// 設(shè)置新的輸出屬性:輸出字符編碼為GB2312,這樣可以支持中文字符,
// XSLT引擎所輸出的XML文檔如果包含了中文字符,可以正常顯示。
properties.setProperty(OutputKeys.ENCODING, "GB2312");
// 這里設(shè)置輸出為XML格式,實(shí)際上這是XSLT引擎的默認(rèn)輸出格式
properties.setProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperties(properties);
// 創(chuàng)建一個DOMSource對象,該構(gòu)造函數(shù)的參數(shù)可以是一個Document對象
DOMSource source = new DOMSource(doc);
// 創(chuàng)建XSLT引擎的輸出對象,這里將輸出寫如文件
File file = new File(fileName);
StreamResult result = new StreamResult(file);
// 執(zhí)行DOM文檔到XML文件的轉(zhuǎn)換
transformer.transform(source, result);
// 將輸出文件的路徑返回
return file.getAbsolutePath();
}

public static void main(String[] args) {
String inFileName = "students.xml";
String outFileName = "students_new.xml";
try {
List studentBeans = DomXML.readXMLFile(inFileName);
DomXML.writeXMLFile(outFileName, studentBeans);
} catch (Exception e) {
e.printStackTrace();
}
}
}
用DOM生成的student_new.xml文件的內(nèi)容如下:











































































































































































































































































































/**----------------------------------文件名:studnet.xml------------------------------------*/
<?xml version="1.0" encoding="GB2312"?>
<學(xué)生花名冊>
<學(xué)生 性別 = "男">
<姓名>張三</姓名>
<年齡>145</年齡>
<電話>62875555</電話>
</學(xué)生>
<學(xué)生 性別 = "女">
<姓名>李四</姓名>
<年齡>16</年齡>
<電話>82734254</電話>
</學(xué)生>
</學(xué)生花名冊>
<?xml version="1.0" encoding="GB2312"?>
<學(xué)生花名冊>
<學(xué)生 性別 = "男">
<姓名>張三</姓名>
<年齡>145</年齡>
<電話>62875555</電話>
</學(xué)生>
<學(xué)生 性別 = "女">
<姓名>李四</姓名>
<年齡>16</年齡>
<電話>82734254</電話>
</學(xué)生>
</學(xué)生花名冊>
用DOM生成的student_new.xml文件的內(nèi)容如下:
/**----------------------------------文件名:studnet_new.xml------------------------------------*/
<?xml version="1.0" encoding="GB2312"?>
<學(xué)生花名冊>
<學(xué)生 性別 = "男">
<姓名>張三</姓名>
<年齡>145</年齡>
<電話>62875555</電話>
</學(xué)生>
<學(xué)生 性別 = "女">
<姓名>李四</姓名>
<年齡>16</年齡>
<電話>82734254</電話>
</學(xué)生>
</學(xué)生花名冊>
<?xml version="1.0" encoding="GB2312"?>
<學(xué)生花名冊>
<學(xué)生 性別 = "男">
<姓名>張三</姓名>
<年齡>145</年齡>
<電話>62875555</電話>
</學(xué)生>
<學(xué)生 性別 = "女">
<姓名>李四</姓名>
<年齡>16</年齡>
<電話>82734254</電話>
</學(xué)生>
</學(xué)生花名冊>
-- 學(xué)海無涯