JAXP(Java API for XML Parsing)
過去幾年中,XML分折已經(jīng)被標(biāo)準(zhǔn)為兩個(gè)不同的處理模型:SAX(Simple API for XML)以及DOM(Document Object Model)。這兩個(gè)標(biāo)準(zhǔn)提供了各種API以便開發(fā)人員處理XML數(shù)據(jù),分別適用於不同的分折需要。JAXP是SUN公司在1999年後期提出的,它是一個(gè)API,但更準(zhǔn)確地說,它應(yīng)該是一個(gè)抽象層。JAXP並不提供解折功能!沒有SAX、DOM或其它XML解折API,我們無法解折XML。
一、SAX(Simple API for XML)
SAX是基於事件的處理模型,在此模型中,解折程序按序列順序解釋數(shù)據(jù)元素,同時(shí)基於所選擇的結(jié)構(gòu)回調(diào)函數(shù)。它最大的優(yōu)點(diǎn)是:它並不把任何XML文檔裝載進(jìn)內(nèi)存,因此被認(rèn)為是非常迅速和輕便的。它使用一個(gè)序列只讀的方法,並不支持對(duì)XML元素的隨機(jī)訪問。
基本實(shí)現(xiàn)由以下三個(gè)驟組成
1、實(shí)現(xiàn)一個(gè)擴(kuò)展DefaultHandler的類,並為每種類型的結(jié)構(gòu)包含回調(diào)方法。
2、初始化一個(gè)新的SAXParser類。Parser讀到XML源文件,並觸發(fā)DefaultHandler類中所實(shí)現(xiàn)的一個(gè)回調(diào)方法
3、須序讀取XML源文件。在須序讀取中,無法隨機(jī)訪問結(jié)構(gòu)中的元素。剩下的工作取決於Handler類中你的實(shí)現(xiàn)方案。
示例
書寫一個(gè)用於讀取的XML文檔test.xml,具體內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8"?>
<simple date="
<name>wang</name>
<location>China DongGuan</location>
</simple>
實(shí)現(xiàn)一個(gè)擴(kuò)展DefaultHandler的類SaxTestHandler.java代碼如下
package mypack;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SaxTestHandler extends DefaultHandler {
// 重載DefaultHandler類的方法
// 以攔截SAX事件通知。
//
/* 開始解折文析進(jìn)執(zhí)行 */
public void startDocument() throws SAXException {
System.out.println("SAX Event: START DOCUMENT");
}
/* 結(jié)束解折時(shí)執(zhí)行 */
public void endDocument() throws SAXException {
System.out.println("SAX Event: END DOCUMENT");
}
/* 遇到一個(gè)節(jié)點(diǎn)時(shí)執(zhí)行 */
public void startElement(String namespaceURI, String localName,
String qName, Attributes attr) throws SAXException {
System.out.println("SAX Event: START ELEMENT[ " + localName + " ]");
// System.out.println(namespaceURI+";;;"+qName);
// 如果有屬性,打印屬性和屬性值
for (int i = 0; i < attr.getLength(); i++) {
System.out.println(" ATTRIBUTE: " + attr.getLocalName(i)
+ " VALUE: " + attr.getValue(i));
}
}
// 元素?cái)?shù)據(jù)
public void characters(char[] ch, int start, int length)
throws SAXException {
String s = new String(ch, start, length);
System.out.println(s);
}
}
這個(gè)類實(shí)現(xiàn)了內(nèi)容處理接口的實(shí)現(xiàn),該實(shí)現(xiàn)只做了一個(gè)簡(jiǎn)單的處理:把有關(guān)XML文檔的內(nèi)容打印到系統(tǒng)控制臺(tái)。
一個(gè)SAXParser類,用於指定解折器並讀取XML文檔然後調(diào)用Handler類的回調(diào)方法。代碼如下:
package mypack;
import java.io.FileReader;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
public class SAXTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自動(dòng)產(chǎn)生方法
try {
// 建立SAX2解折器
XMLReader xr = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
// 安裝ContentHandler內(nèi)容處理類
SaxTestHandler handler=new SaxTestHandler();
xr.setContentHandler( handler );
// 解折文檔
xr.parse(new InputSource(new FileReader("D:\\MyProject\\Ewebsite\\XML\\JavaSource\\test.xml")));
} catch (Exception e) {
e.printStackTrace();
}
}
}
執(zhí)行SAXTest可以打印出test.xml文件的內(nèi)容(節(jié)點(diǎn)名,節(jié)點(diǎn)的屬性及值,元素內(nèi)容)
二、DOM(Document Object Model)
XML將數(shù)據(jù)組織為一棵樹,所以DOM就是對(duì)這棵樹的一個(gè)對(duì)象描敘。通俗的說,就是通過解折XML文檔,為XML文檔在邏輯上建立一個(gè)樹模型,樹的節(jié)點(diǎn)就是一個(gè)個(gè)對(duì)象。我們通過存到這些對(duì)象就能夠存取XML文檔的內(nèi)容。當(dāng)XML文檔很大時(shí),這個(gè)過程可能需要一塊相當(dāng)大的內(nèi)存,這可能出現(xiàn)內(nèi)存不足的現(xiàn)象。
使用DOM處理的基本步驟如下:
1、實(shí)例一個(gè)DOMParser。
2、得到一個(gè)Document對(duì)象。
3、使用Document對(duì)象訪問代表了XML文檔中元素的節(jié)點(diǎn)。
XML源被完全讀入內(nèi)存,並用Document對(duì)象表示。這就使得應(yīng)用程序能夠隨機(jī)訪問任何節(jié)點(diǎn),這一點(diǎn)也是SAX所不能做到的。
一個(gè)讀取XML文檔的DOM處理示例
package mypack;
import java.io.FileReader;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.xerces.parsers.DOMParser;//導(dǎo)入DOMParser解折器
import org.w
import org.w
import org.w
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class DOMTest {
/**
* @param args
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
*/
public static void main(String[] args) throws ParserConfigurationException,
SAXException, IOException {
// TODO 自動(dòng)產(chǎn)生方法 Stub
// 實(shí)例解折器
DOMParser parser = new DOMParser();
// 以Docment對(duì)象的形式獲取DOM樹
parser.parse(new InputSource(new FileReader(
"D:\\MyProject\\Ewebsite\\XML\\JavaSource\\test.xml")));
Document doc = parser.getDocument();
// 使用Document對(duì)象的方法得到NodeList對(duì)象
NodeList nl = doc.getElementsByTagName("name");
System.out.println(nl.getLength());// 標(biāo)簽的次數(shù)
Node my_node = nl.item(0);
// 輸出name標(biāo)簽的元素?cái)?shù)據(jù)
String name = my_node.getFirstChild().getNodeValue();
System.out.println(name);
}
}
現(xiàn)在,既然我們已經(jīng)能夠從XML文件中提取出數(shù)據(jù)了,我們就可以把這些數(shù)據(jù)用在合適的地方,來構(gòu)筑應(yīng)用程序。
DOM對(duì)象詳解
1.基本的DOM對(duì)象
DOM的基本對(duì)象有5個(gè):Document,Node,NodeList,Element和Attr。下面就這些對(duì)象的功能和實(shí)現(xiàn)的方法作一個(gè)大致的介紹。
Document對(duì)象代表了整個(gè)XML的文檔,所有其它的Node,都以一定的順序包含在Document對(duì)象之內(nèi),排列成一個(gè)樹形的結(jié)構(gòu),程序員可以通過遍歷這顆樹來得到XML文檔的所有的內(nèi)容,這也是對(duì)XML文檔操作的起點(diǎn)。我們總是先通過解析XML源文件而得到一個(gè)Document對(duì)象,然后再來執(zhí)行后續(xù)的操作。此外,Document還包含了創(chuàng)建其它節(jié)點(diǎn)的方法,比如createAttribut()用來創(chuàng)建一個(gè)Attr對(duì)象。它所包含的主要的方法有:
createAttribute(String):用給定的屬性名創(chuàng)建一個(gè)Attr對(duì)象,并可在其后使用setAttributeNode方法來放置在某一個(gè)Element對(duì)象上面。
createElement(String):用給定的標(biāo)簽名創(chuàng)建一個(gè)Element對(duì)象,代表XML文檔中的一個(gè)標(biāo)簽,然后就可以在這個(gè)Element對(duì)象上添加屬性或進(jìn)行其它的操作。
createTextNode(String):用給定的字符串創(chuàng)建一個(gè)Text對(duì)象,Text對(duì)象代表了標(biāo)簽或者屬性中所包含的純文本字符串。如果在一個(gè)標(biāo)簽內(nèi)沒有其它的標(biāo)簽,那么標(biāo)簽內(nèi)的文本所代表的Text對(duì)象是這個(gè)Element對(duì)象的唯一子對(duì)象。
getElementsByTagName(String):返回一個(gè)NodeList對(duì)象,它包含了所有給定標(biāo)簽名字的標(biāo)簽。
getDocumentElement():返回一個(gè)代表這個(gè)DOM樹的根節(jié)點(diǎn)的Element對(duì)象,也就是代表XML文檔根元素的那個(gè)對(duì)象。
Node對(duì)象是DOM結(jié)構(gòu)中最為基本的對(duì)象,代表了文檔樹中的一個(gè)抽象的節(jié)點(diǎn)。在實(shí)際使用的時(shí)候,很少會(huì)真正的用到Node這個(gè)對(duì)象,而是用到諸如Element、Attr、Text等Node對(duì)象的子對(duì)象來操作文檔。Node對(duì)象為這些對(duì)象提供了一個(gè)抽象的、公共的根。雖然在Node對(duì)象中定義了對(duì)其子節(jié)點(diǎn)進(jìn)行存取的方法,但是有一些Node子對(duì)象,比如Text對(duì)象,它并不存在子節(jié)點(diǎn),這一點(diǎn)是要注意的。Node對(duì)象所包含的主要的方法有:
appendChild(org.w
getFirstChild():如果節(jié)點(diǎn)存在子節(jié)點(diǎn),則返回第一個(gè)子節(jié)點(diǎn),對(duì)等的,還有getLastChild()方法返回最后一個(gè)子節(jié)點(diǎn)。
getNextSibling():返回在DOM樹中這個(gè)節(jié)點(diǎn)的下一個(gè)兄弟節(jié)點(diǎn),對(duì)等的,還有getPreviousSibling()方法返回其前一個(gè)兄弟節(jié)點(diǎn)。
getNodeName():根據(jù)節(jié)點(diǎn)的類型返回節(jié)點(diǎn)的名稱。
getNodeType():返回節(jié)點(diǎn)的類型。
getNodeValue():返回節(jié)點(diǎn)的值。
hasChildNodes():判斷是不是存在有子節(jié)點(diǎn)。
hasAttributes():判斷這個(gè)節(jié)點(diǎn)是否存在有屬性。
getOwnerDocument():返回節(jié)點(diǎn)所處的Document對(duì)象。
insertBefore(org.w
removeChild(org.w
replaceChild(org.w
NodeList對(duì)象,顧名思義,就是代表了一個(gè)包含了一個(gè)或者多個(gè)Node的列表??梢院?jiǎn)單的把它看成一個(gè)Node的數(shù)組,我們可以通過方法來獲得列表中的元素:
GetLength():返回列表的長(zhǎng)度。
Item(int):返回指定位置的Node對(duì)象。
Element對(duì)象代表的是XML文檔中的標(biāo)簽元素,繼承于Node,亦是Node的最主要的子對(duì)象。在標(biāo)簽中可以包含有屬性,因而Element對(duì)象中有存取其屬性的方法,而任何Node中定義的方法,也可以用在Element對(duì)象上面。
getElementsByTagName(String):返回一個(gè)NodeList對(duì)象,它包含了在這個(gè)標(biāo)簽中其下的子孫節(jié)點(diǎn)中具有給定標(biāo)簽名字的標(biāo)簽。
getTagName():返回一個(gè)代表這個(gè)標(biāo)簽名字的字符串。
getAttribute(String):返回標(biāo)簽中給定屬性名稱的屬性的值。在這兒需要主要的是,應(yīng)為XML文檔中允許有實(shí)體屬性出現(xiàn),而這個(gè)方法對(duì)這些實(shí)體屬性并不適用。這時(shí)候需要用到getAttributeNodes()方法來得到一個(gè)Attr對(duì)象來進(jìn)行進(jìn)一步的操作。
getAttributeNode(String):返回一個(gè)代表給定屬性名稱的Attr對(duì)象。
Attr對(duì)象代表了某個(gè)標(biāo)簽中的屬性。Attr繼承于Node,但是因?yàn)?/span>Attr實(shí)際上是包含在Element中的,它并不能被看作是Element的子對(duì)象,因而在DOM中Attr并不是DOM樹的一部分,所以Node中的getparentNode(),getpreviousSibling()和getnextSibling()返回的都將是null。也就是說,Attr其實(shí)是被看作包含它的Element對(duì)象的一部分,它并不作為DOM樹中單獨(dú)的一個(gè)節(jié)點(diǎn)出現(xiàn)。這一點(diǎn)在使用的時(shí)候要同其它的Node子對(duì)象相區(qū)別。
需要說明的是,上面所說的DOM對(duì)象在DOM中都是用接口定義的, DOM其實(shí)可以在任何面向?qū)ο蟮恼Z言中實(shí)現(xiàn),只要它實(shí)現(xiàn)了DOM所定義的接口和功能就可以了。
三、JAXP
1、用SAX處理XML
下面是JAXP的操作示范
(1) 創(chuàng)建已實(shí)現(xiàn)的Handler類的實(shí)例。
(2) 利用SAXParserFactory的靜態(tài)方法newInstance()方法獲取一個(gè)factory類。
(3) 通過newSAXParser()靜態(tài)方法從factory中獲取SAX分折器。
(4) 分折XML數(shù)據(jù):調(diào)用SAXParser的分折方法,把XML輸入作為第一個(gè)參數(shù),而Handler實(shí)現(xiàn)方案作為第二個(gè)參數(shù)。
示例代碼如下:
package mypack;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class JaxpSaxTest {
/**
* @param args
* @throws SAXException
* @throws ParserConfigurationException
* @throws IOException
*/
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
// TODO 自動(dòng)產(chǎn)生方法 Stub
//實(shí)例一個(gè)內(nèi)容處理類
DefaultHandler handler=new SaxTestHandler();
//得到廠類
SAXParserFactory factory=SAXParserFactory.newInstance();
//在廠類中獲取SAX分折器
SAXParser parser=factory.newSAXParser();
//分折XML數(shù)據(jù)
parser.parse("D:\\MyProject\\Ewebsite\\XML\\JavaSource\\test.xml",handler);
}
}
2、用DOM處理
步聚如下:
(1)初始化一個(gè)新的Builder類。Builder類負(fù)責(zé)讀取XML數(shù)據(jù)並把XML數(shù)據(jù)轉(zhuǎn)化為樹狀表示。
(2)一旦數(shù)據(jù)轉(zhuǎn)化完成,即創(chuàng)建Document對(duì)象。一旦對(duì)象創(chuàng)建後,以後所有的對(duì)XML文檔的操作都與解折器無關(guān)了。
(3) 使用Document對(duì)象訪問代表了XML文檔中元素的節(jié)點(diǎn)。
示例代碼如下:
package mypack;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w
import org.w
import org.w
import org.xml.sax.SAXException;
public class JaxpDomTest {
/**
* @param args
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
*/
public static void main(String[] args) throws ParserConfigurationException,
SAXException, IOException {
// TODO 自動(dòng)產(chǎn)生方法 Stub
// 實(shí)例一個(gè)Builder類,用DocumentBuilder的目的是為了創(chuàng)建與具體解折器無關(guān)的程序
// 廠類的靜態(tài)方法newInstance()被調(diào)用時(shí),它根據(jù)一個(gè)系統(tǒng)變量來決定具體使用哪一個(gè)解折器。
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
// 創(chuàng)建Document對(duì)象
Document document = builder
.parse("D:\\MyProject\\Ewebsite\\XML\\JavaSource\\test.xml");
// 使用Document對(duì)象的方法得到NodeList對(duì)象
NodeList nl = document.getElementsByTagName("name");
System.out.println(nl.getLength());// 標(biāo)簽的次數(shù)
Node my_node = nl.item(0);
// 輸出name標(biāo)簽的元素?cái)?shù)據(jù)
String name = my_node.getFirstChild().getNodeValue();
System.out.println(name);
}
}
聯(lián)系客服