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

<%
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();
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樹后重新寫入到XML文件中去,通常會遇到兩個方面的問題:
Œ在XML文件中增加記錄:首先要在DOM樹中增加一個節(jié)點元素,然后在這個節(jié)點元素上增加子節(jié)點元素,并給相應(yīng)的葉節(jié)點賦值,最后把DOM樹保存到XML文件中。
?在XML文件中修改節(jié)點的值,要修改XML文件中節(jié)點的值,需要先將XML文件讀入到DOM樹中,再遍歷DOM樹,并在遍歷的過程中找到相應(yīng)的節(jié)點并修改其值,并把修改的DOM保存到XML文件中。
5)DOM修改XML文件實例,所操作的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文件實例</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項目案例";
String author="劉乃麗";
String price="85.00元";
String publish="人民郵電出版社";
//---創(chuàng)建一個book對象---
Text textseg;
Element book=doc.createElement("book");
//XML文件中添加一個book項目的具體元素
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é)點添加到DOM樹中
doc.getDocumentElement().appendChild(book);
//用xslt把DOM樹輸出
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>書名</td>
<td>作者</td>
<td>定價</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è)計接口,采用 observer 模式,將XML文件視為一個文字流的數(shù)據(jù),在讀取XML 元素時觸發(fā)一系列的事件
2). 使用DOM 時是將xml 文件解析為一個樹狀結(jié)構(gòu),并對樹中的節(jié)點進行操作
使用SAX 加載XML文件時,他的操作像打開一個“順序的文件字符流”,在讀到XML元素的開始標記,結(jié)尾標記和內(nèi)容標記時將產(chǎn)生一系列的事件
如一個簡單的XML文件:<hello><message>hello XML!</message></hello>
會相應(yīng)的觸發(fā):startDocument, startElement, characters, endElement, endDocument, 只需編寫這些事件處理程序就可以解析XML文件了
3). SAX 可以高效的使用內(nèi)存,因為SAX 只是順序的讀取XML 文件的內(nèi)容,并不會將XML 文件完全加載,這樣就比DOM 的處理效率高
但SAX 只能讀取XML 文件的內(nèi)容,而不能更改XML 的內(nèi)容,也不能隨機訪問XML 元素
4). 在SAX 中有4個處理器是要實現(xiàn)的:ContentHandler,DTDHandler,EntityResolver,ErrorHandler,以處理不同的事件,這是比較麻煩的,
幸好SAX 定義了一個 DefaultHandler 類把這幾個實現(xiàn)了,我們只需在 DefaultHandler中定義事件處理方法,然后注冊到XMLReader,而SAXParser封裝了XMLReader的實現(xiàn)類,
SAXParser又是由SAXParserFactory提供的,所以我們實際用到的類只有:SAXParserFactory,SAXParser,DefaultHandler
5). SAX 的解析步驟:
(1)寫一個類繼承 DefaultHandler, 實現(xiàn)自己的事件處理方法
(2)在主程序中建立 SAXParserFactory
(3)可以設(shè)置這個factory 的參數(shù)
(4)從這個factory 得到SAXParser
(5)解析XML文件
6)SAX解析XML實例,被解析的文件依然是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();
//文檔解析開始
public void startDocument() throws SAXException {
tempString.append("開始解析xml文件
<br>");
}
//標簽解析開始
public void startElement(String namespaceURI, String localName,String qName, Attributes atts) throws SAXException{
tempString.append("開始解析結(jié)點,結(jié)點名稱:"+qName+"<br>");
//解析得到標簽所有的屬性
for(int i=0;i<atts.getLength();i++){
tempString.append(" 屬性"+atts.getQName(i)+",值為:"+atts.getValue(i)+"<br>");
}
}
//標簽解析結(jié)束
public void endElement(String namespaceURI,String localName,String qName) throws SAXException{
tempString.append("解析結(jié)點結(jié)束,結(jié)點名稱:"+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解析器工廠長
SAXParserFactory spf = SAXParserFactory.newInstance();
XMLReader xmlReader = null;
SAXParser saxParser=null;
SAXParseUser saxParseUser=new SAXParseUser();
String filename=pageContext.getServletContext().getRealPath("/book.xml");
try {
// 創(chuàng)建一個解析器SAXParser對象
saxParser = spf.newSAXParser();
// 得到SAXParser中封裝的SAX XMLReader
xmlReader = saxParser.getXMLReader();
//設(shè)置解析時處理事件的對象
xmlReader.setContentHandler(saxParseUser);
//開始解析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>