1、操作XML文件的開(kāi)源軟件包括DOM、SAX、JDOM等,程序員需要熟悉并掌握這些常用的接口的使用,能夠通過(guò)這些接口編寫(xiě)java語(yǔ)句來(lái)實(shí)現(xiàn)對(duì)XML文件的處理。
2、DTD主要有下列幾方面的作用:
1)可以驗(yàn)證XML文件數(shù)據(jù)的有效性。
2)可以為某類(lèi)XML文件提供統(tǒng)一的格式和相同的結(jié)構(gòu)。
3)可以保證在一定的范圍內(nèi),XML文件數(shù)據(jù)的交流和共享。
4)應(yīng)用程序設(shè)計(jì)人員根據(jù)DTD就能夠知道對(duì)應(yīng)XML文件的邏輯結(jié)構(gòu),從而編寫(xiě)出相應(yīng)的處理應(yīng)用程序。
3、在DTD中引進(jìn)Namespaces這個(gè)概念是為了解決命名沖突問(wèn)題,設(shè)置url并不是說(shuō)真的要到那個(gè)網(wǎng)址去讀取,僅僅作為一種區(qū)別的標(biāo)志而已。
4、DOM
1)DOM的類(lèi)
目前主流的解析器有:JAXP(Java Api for XML Processing)、Xerces(Apache)、XML4J(IBM)和xalan等,主流的解析器都支持SAX和DOM,支持JDOM的解析器目前只有SUN公司發(fā)布的jdom包。DOM即文件對(duì)象模型。在應(yīng)用程序中,基于DOM的XML分析器將一個(gè)XML文件轉(zhuǎn)換成了一個(gè)對(duì)象模型的集合(通常被稱為DOM樹(shù)),應(yīng)用程序可以通過(guò)對(duì)該對(duì)象模型的操作,實(shí)現(xiàn)對(duì)XML文件中數(shù)據(jù)的操作。
§Document類(lèi),描述了整個(gè)XML的文件語(yǔ)法結(jié)構(gòu),它包含了一系列Node類(lèi)形成的樹(shù)形結(jié)構(gòu)。程序員可以先掃描XML源文件,得到相應(yīng)的Document對(duì)象,遍歷這顆樹(shù)來(lái)得到XML文件的所有內(nèi)容,這是對(duì)XML文件操作的起點(diǎn)。
§Node對(duì)象,Node類(lèi)是DOM結(jié)構(gòu)中最為基本的類(lèi),經(jīng)描述了文件樹(shù)中的一個(gè)抽象的節(jié)點(diǎn)。它包含類(lèi)型為Element、Attr、Text和其他類(lèi)的特征。Node對(duì)象引用其成員的變量來(lái)操作XML文件。
§NodeList對(duì)象,代表了一個(gè)包含了一個(gè)或者多個(gè)Node的列表。
§Element對(duì)象,Element類(lèi)描述XML文件中的標(biāo)志元素,繼承于Node,也是Node的最主要的子對(duì)象。標(biāo)志中要以包含屬性,因而Element對(duì)象中有存取其屬性的方法,而任何Node中定義的方法,Element都繼承下來(lái)。
§Attribute對(duì)象,它代表了某個(gè)標(biāo)志的屬性。繼承Node,但因?yàn)锳ttr實(shí)際上包含在Element中,不能被看作Element的子對(duì)。在DOM中Attributer并不是DOM樹(shù)的一個(gè)節(jié)點(diǎn),所以Node中的getparentNode()、getpreviousSibling()和getnextSibling()返回的都將是null。即,Attribute是Element類(lèi)的一部分,并不作為DOM樹(shù)中單獨(dú)的一個(gè)節(jié)點(diǎn)出現(xiàn)。
DOM類(lèi)在DOM中都是用接口語(yǔ)言IDL定義的,因而,DOM可以映射到任何面向?qū)ο蟮恼Z(yǔ)言,只要它實(shí)現(xiàn)了DOM所定義的接口就可以了。許多公司和廠家都提供了符合DOM規(guī)范的DOM接口和程序包。以微軟的DOM接口為例:
2)DOM讀取XML文件,通常用到以下5個(gè)基本步驟:
?建立一個(gè)解析器工廠。
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstace();
‚利用工廠獲得一個(gè)具體的解析器對(duì)象。
DocumentBuilder builder=factory.newDocumentBuilder();
ƒ利用DocumentBuilder的parse()方法接受一個(gè)XML文件名作為輸入?yún)?shù),返回一個(gè)Document對(duì)象。Document對(duì)象代表了一個(gè)XML文件的樹(shù)模型。
Document doc=builder.parse("file.xml");
„使用Document對(duì)象的getElementsByTagName()方法,我們可以得到一個(gè)NodeList對(duì)象,它是XML文件中的標(biāo)簽元素列表,可以使用NodeList對(duì)象的item()方法來(lái)得到列表中的每一個(gè)Node對(duì)象。
NodeList nl=doc.getElementsByTagName("person");
Element node=(Element)nl.item(i);
…通過(guò)Node對(duì)象的getNodeValue()方法提取某個(gè)標(biāo)簽內(nèi)的內(nèi)容。
node.getElementsByTagName("NAME").item(0).getFirstChild().getNodeValue();
3)DOM讀取XML文件實(shí)例:本實(shí)例有兩個(gè)文件(book.xml與bookDisplay.jsp)
book.xml的代碼如下:
<?xml version="1.0" encoding="gb2312"?>
<books>
<book>
<name>J2EE編程技術(shù)</name>
<author>郝玉龍等</author>
<price cointype="¥">27.00元</price>
<publish>清華大學(xué)出版社</publish>
<date>
<day>15</day>
<month>3</month>
<year>2005</year>
</date>
</book>
<book>
<name>JSP大學(xué)實(shí)用教程</name>
<author>耿祥義等</author>
<price cointype="¥">24.00元</price>
<publish>電子工業(yè)出版社</publish>
<date>
<day>21</day>
<month>9</month>
<year>2007</year>
</date>
</book>
<book>
<name>JAVA2游戲編程</name>
<author>Thomas Petchel</author>
<price cointype="$">10.00元</price>
<publish>清華大學(xué)出版社</publish>
<date>
<day>1</day>
<month>8</month>
<year>2005</year>
</date>
</book>
<book>
<name>JSP應(yīng)用開(kāi)發(fā)</name>
<author>鄧子云等</author>
<price cointype="¥">49.00元</price>
<publish>機(jī)械工業(yè)出版社</publish>
<date>
<day>11</day>
<month>12</month>
<year>2007年</year>
</date>
</book>
</books>
bookDisplay.jsp的代碼如下:

<%
@ page contentType="text/html;charset=gb2312"%>

<%
@ page import="javax.xml.parsers.*,org.w3c.dom.*"%>
<html>
<head>
<title> DOM讀取book.xml</title>
</head>
<body>
<table border=1 align="center">
<!--輸出表頭-->
<tr bgcolor="yellow">
<td>書(shū)名</td>
<td>作者</td>
<td>定價(jià)</td>
<td>出版社</td>
<td>出版日期</td>
</tr>

<%
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
//此處用的是絕對(duì)路徑,相對(duì)路徑不太好使。
Document doc=builder.parse("C:/Program Files/Apache Software Foundation/Tomcat 6.0/webapps/readXml/book.xml");
doc.normalize();
NodeList books=doc.getElementsByTagName("book");
for(int i=0;i<books.getLength();i++){
Element book=(Element)books.item(i);
out.print("<tr>");
out.print("<td>"+book.getElementsByTagName("name").item(0).getFirstChild().getNodeValue()+"</td>");
out.print("<td>"+book.getElementsByTagName("author").item(0).getFirstChild().getNodeValue()+"</td>");
out.print("<td>"+book.getElementsByTagName("price").item(0).getFirstChild().getNodeValue()+"</td>");
out.print("<td>"+book.getElementsByTagName("publish").item(0).getFirstChild().getNodeValue()+"</td>");
Element bookdate=(Element)book.getElementsByTagName("date").item(0);
String day=bookdate.getElementsByTagName("day").item(0).getFirstChild().getNodeValue();
String month=bookdate.getElementsByTagName("month").item(0).getFirstChild().getNodeValue();
String year=bookdate.getElementsByTagName("year").item(0).getFirstChild().getNodeValue();
out.print("<td>"+year+"年"+month+"月"+day+"日"+"</td>");
out.println();
}
%>
</table>
</body>
</html>
4)DOM修改XML文件
修改XML文件就是在修改了DOM樹(shù)后重新寫(xiě)入到XML文件中去,通常會(huì)遇到兩個(gè)方面的問(wèn)題:
Œ在XML文件中增加記錄:首先要在DOM樹(shù)中增加一個(gè)節(jié)點(diǎn)元素,然后在這個(gè)節(jié)點(diǎn)元素上增加子節(jié)點(diǎn)元素,并給相應(yīng)的葉節(jié)點(diǎn)賦值,最后把DOM樹(shù)保存到XML文件中。
?在XML文件中修改節(jié)點(diǎn)的值,要修改XML文件中節(jié)點(diǎn)的值,需要先將XML文件讀入到DOM樹(shù)中,再遍歷DOM樹(shù),并在遍歷的過(guò)程中找到相應(yīng)的節(jié)點(diǎn)并修改其值,并把修改的DOM保存到XML文件中。
5)DOM修改XML文件實(shí)例,所操作的XML文件依然是book.xml,用以創(chuàng)修改book.xml文件的文件是bookChange.jsp,代碼如下:

<%
@ page contentType="text/html;charset=gb2312"%>

<%
@ page import="javax.xml.parsers.*, javax.xml.transform.*,javax.xml.transform.dom.*"%>

<%
@ page import="javax.xml.transform.stream.*,java.io.*, org.w3c.dom.*"%>
<html>
<head>
<title>DOM修改XML文件實(shí)例</title>
</head>
<body>

<%
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc=builder.parse("C:/Program Files/Apache Software Foundation/Tomcat 6.0/webapps/readXml/book.xml");
doc.normalize();
//---取得變量---
String name="精通Java EE項(xiàng)目案例";
String author="劉乃麗";
String price="85.00元";
String publish="人民郵電出版社";
//---創(chuàng)建一個(gè)book對(duì)象---
Text textseg;
Element book=doc.createElement("book");
//XML文件中添加一個(gè)book項(xiàng)目的具體元素
Element bookname=doc.createElement("name");
textseg=doc.createTextNode(name);
bookname.appendChild(textseg);
book.appendChild(bookname);
Element bookauthor=doc.createElement("author");
textseg=doc.createTextNode(author);
bookauthor.appendChild(textseg);
book.appendChild(bookauthor);
Element bookprice=doc.createElement("price");
textseg=doc.createTextNode(price);
bookprice.appendChild(textseg);
book.appendChild(bookprice);
Element bookpublish=doc.createElement("publish");
textseg=doc.createTextNode(publish);
bookpublish.appendChild(textseg);
book.appendChild(bookpublish);
String day="01";
String month="01";
String year="2008";
Element bookdate=doc.createElement("date");
Element bookdateday=doc.createElement("day");
textseg=doc.createTextNode(day);
bookdateday.appendChild(textseg);
Element bookdatemonth=doc.createElement("month");
textseg=doc.createTextNode(month);
bookdatemonth.appendChild(textseg);
Element bookdateyear=doc.createElement("year");
textseg=doc.createTextNode(year);
bookdateyear.appendChild(textseg);
bookdate.appendChild(bookdateday);
bookdate.appendChild(bookdatemonth);
bookdate.appendChild(bookdateyear);
book.appendChild(bookdate);
//創(chuàng)建好的節(jié)點(diǎn)添加到DOM樹(shù)中
doc.getDocumentElement().appendChild(book);
//用xslt把DOM樹(shù)輸出
TransformerFactory tFactory=TransformerFactory.newInstance();
Transformer transformer=tFactory.newTransformer();
DOMSource source=new DOMSource(doc);
StreamResult result=new StreamResult(new File("C:/Program Files/Apache Software Foundation/Tomcat 6.0/webapps/readXml/book.xml"));
transformer.transform(source,result);
%>
<table border=1 align="center">
<!--輸出表頭-->
<tr bgcolor="yellow">
<td>書(shū)名</td>
<td>作者</td>
<td>定價(jià)</td>
<td>出版社</td>
<td>出版日期</td>
</tr>

<%
//修改后讀取數(shù)據(jù)
NodeList books=doc.getElementsByTagName("book");
for(int i=0;i<books.getLength();i++){
book=(Element)books.item(i);
out.print("<tr>");
out.print("<td>"+book.getElementsByTagName("name").item(0).getFirstChild().getNodeValue()+"</td>");
out.print("<td>"+book.getElementsByTagName("author").item(0).getFirstChild().getNodeValue()+"</td>");
out.print("<td>"+book.getElementsByTagName("price").item(0).getFirstChild().getNodeValue()+"</td>");
out.print("<td>"+book.getElementsByTagName("publish").item(0).getFirstChild().getNodeValue()+"</td>");
bookdate=(Element)book.getElementsByTagName("date").item(0);
day=bookdate.getElementsByTagName("day").item(0).getFirstChild().getNodeValue();
month=bookdate.getElementsByTagName("month").item(0).getFirstChild().getNodeValue();
year=bookdate.getElementsByTagName("year").item(0).getFirstChild().getNodeValue();
out.print("<td>"+year+"年"+month+"月"+day+"日"+"</td>");
out.println();
}
%>
</table>
</body>
</html>
5、SAX
1). SAX ( Simple Application interface for XML ), 是一組程序設(shè)計(jì)接口,采用 observer 模式,將XML文件視為一個(gè)文字流的數(shù)據(jù),在讀取XML 元素時(shí)觸發(fā)一系列的事件
2). 使用DOM 時(shí)是將xml 文件解析為一個(gè)樹(shù)狀結(jié)構(gòu),并對(duì)樹(shù)中的節(jié)點(diǎn)進(jìn)行操作
使用SAX 加載XML文件時(shí),他的操作像打開(kāi)一個(gè)“順序的文件字符流”,在讀到XML元素的開(kāi)始標(biāo)記,結(jié)尾標(biāo)記和內(nèi)容標(biāo)記時(shí)將產(chǎn)生一系列的事件
如一個(gè)簡(jiǎn)單的XML文件:<hello><message>hello XML!</message></hello>
會(huì)相應(yīng)的觸發(fā):startDocument, startElement, characters, endElement, endDocument, 只需編寫(xiě)這些事件處理程序就可以解析XML文件了
3). SAX 可以高效的使用內(nèi)存,因?yàn)镾AX 只是順序的讀取XML 文件的內(nèi)容,并不會(huì)將XML 文件完全加載,這樣就比DOM 的處理效率高
但SAX 只能讀取XML 文件的內(nèi)容,而不能更改XML 的內(nèi)容,也不能隨機(jī)訪問(wèn)XML 元素
4). 在SAX 中有4個(gè)處理器是要實(shí)現(xiàn)的:ContentHandler,DTDHandler,EntityResolver,ErrorHandler,以處理不同的事件,這是比較麻煩的,
幸好SAX 定義了一個(gè) DefaultHandler 類(lèi)把這幾個(gè)實(shí)現(xiàn)了,我們只需在 DefaultHandler中定義事件處理方法,然后注冊(cè)到XMLReader,而SAXParser封裝了XMLReader的實(shí)現(xiàn)類(lèi),
SAXParser又是由SAXParserFactory提供的,所以我們實(shí)際用到的類(lèi)只有:SAXParserFactory,SAXParser,DefaultHandler
5). SAX 的解析步驟:
(1)寫(xiě)一個(gè)類(lèi)繼承 DefaultHandler, 實(shí)現(xiàn)自己的事件處理方法
(2)在主程序中建立 SAXParserFactory
(3)可以設(shè)置這個(gè)factory 的參數(shù)
(4)從這個(gè)factory 得到SAXParser
(5)解析XML文件
6)SAX解析XML實(shí)例,被解析的文件依然是book.xml,用以解析的文件是bookSaxDisplay.jsp,其代碼如下:

<%
@ page contentType="text/html;charset=GB2312" %>

<%
@ page import="javax.xml.parsers.*,
org.xml.sax.*,
org.xml.sax.helpers.*,
org.xml.sax.helpers.DefaultHandler,
java.io.*"%>

<html>
<head><title>用SAX解析并遍歷user.xml</title></head>
<body>

<%
!
static class SAXParseUser extends DefaultHandler{
StringBuffer tempString=new StringBuffer();
//文檔解析開(kāi)始
public void startDocument() throws SAXException {
tempString.append("開(kāi)始解析xml文件
<br>");
}
//標(biāo)簽解析開(kāi)始
public void startElement(String namespaceURI, String localName,String qName, Attributes atts) throws SAXException{
tempString.append("開(kāi)始解析結(jié)點(diǎn),結(jié)點(diǎn)名稱:"+qName+"<br>");
//解析得到標(biāo)簽所有的屬性
for(int i=0;i<atts.getLength();i++){
tempString.append(" 屬性"+atts.getQName(i)+",值為:"+atts.getValue(i)+"<br>");
}
}
//標(biāo)簽解析結(jié)束
public void endElement(String namespaceURI,String localName,String qName) throws SAXException{
tempString.append("解析結(jié)點(diǎn)結(jié)束,結(jié)點(diǎn)名稱:"+qName+"<br>");
}
//字符串解析
public void characters(char[] ch,int start,int length){
tempString.append(" 解析出字符串,值為:'"+(new String(ch,start,length))+"'<br>");
}
//文檔解析結(jié)束
public void endDocument() throws SAXException {
tempString.append("解析xml文件結(jié)束!<br>");
}
//得到解析結(jié)果
public StringBuffer getPrintXML(){
return tempString;
}
}
%>

<%
//生成SAX解析器工廠長(zhǎng)
SAXParserFactory spf = SAXParserFactory.newInstance();
XMLReader xmlReader = null;
SAXParser saxParser=null;
SAXParseUser saxParseUser=new SAXParseUser();
String filename=pageContext.getServletContext().getRealPath("/book.xml");
try {
// 創(chuàng)建一個(gè)解析器SAXParser對(duì)象
saxParser = spf.newSAXParser();
// 得到SAXParser中封裝的SAX XMLReader
xmlReader = saxParser.getXMLReader();
//設(shè)置解析時(shí)處理事件的對(duì)象
xmlReader.setContentHandler(saxParseUser);
//開(kāi)始解析XML文件
xmlReader.parse(filename);
}catch (Exception ex) {
System.out.println(ex);
}
%>
<!--輸出解析結(jié)果-->
<table border=1>
<!--輸出表頭-->
<tr >
<td align="center">內(nèi)容</td>
</tr>

<%
out.println("<td>"+saxParseUser.getPrintXML()+"</td>");
%>
</table>
</body>
</html>