官术网_书友最值得收藏!

3.6.1 使用SAX解析器

SAX解析器在解析XML輸入數(shù)據(jù)的各個組成部分時會報告事件,但不會以任何方式存儲文檔,而是由事件處理器建立相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。實際上,DOM解析器是在SAX解析器的基礎(chǔ)上構(gòu)建的,它在接收到解析器事件時構(gòu)建DOM樹。

在使用SAX解析器時,需要一個處理器來為各種解析器事件定義事件動作。ContentHandler接口定義了若干個在解析文檔時解析器會調(diào)用的回調(diào)方法。下面是最重要的幾個:

·startElement和endElement在每當(dāng)遇到起始或終止標(biāo)簽時調(diào)用。

·characters在每當(dāng)遇到字符數(shù)據(jù)時調(diào)用。

·startDocument和endDocument分別在文檔開始和結(jié)束時各調(diào)用一次。

例如,在解析以下片段時:

解析器會產(chǎn)生以下回調(diào):

1)startElement,元素名:font

2)startElement,元素名:name

3)characters,內(nèi)容:Helvetica

4)endElement,元素名:name

5)startElement,元素名:size,屬性:units="pt"

6)characters,內(nèi)容:36

7)endElement,元素名:size

8)endElement,元素名:font

處理器必須覆蓋這些方法,讓它們執(zhí)行在解析文件時我們想要讓它們執(zhí)行的動作。本節(jié)最后的程序會打印出一個HTML文件中的所有鏈接<a href="...">。它直接覆蓋了處理器的startElement方法,以檢查名字為a,且屬性名為href的鏈接,其潛在用途包括用于實現(xiàn)“網(wǎng)絡(luò)爬蟲”,即一個沿著鏈接到達(dá)越來越多網(wǎng)頁的程序。

注意:遺憾的是,HTML不必是合法的XML,大多數(shù)HTML頁面都與良構(gòu)的XML差別很大,以至于示例程序無法解析它們。但是,W3C編寫的大部分頁面都是用XHTML編寫的,XHTML是一種HTML方言,且是良構(gòu)的XML,你可以用這些頁面來測試示例程序。例如,運行:

將看到那個頁面上所有鏈接的URL列表。

示例程序是一個很好的使用SAX的例子。我們根本不在乎a元素出現(xiàn)的上下文環(huán)境,而且不必存儲樹形結(jié)構(gòu)。

下面是如何得到SAX解析器的代碼:

現(xiàn)在可以處理文檔了:

這里的source可以是一個文件、一個URL字符串或者是一個輸入流。handler屬于DefaultHandler的一個子類,DefaultHandler類為以下四個接口定義了空的方法:

示例程序定義了一個處理器,它覆蓋了ContentHandler接口的startElement方法,以觀察帶有href屬性的a元素。

startElement方法有3個描述元素名的參數(shù),其中qname參數(shù)以prefix:localname的形式報告限定名。如果命名空間處理特性已經(jīng)打開,那么namespaceURI和lname參數(shù)提供的就是命名空間和本地(非限定)名。

與DOM解析器一樣,命名空間處理特性默認(rèn)是關(guān)閉的,可以調(diào)用工廠類的setNamespaceAware方法來激活命名空間處理特性:

在這個程序中,我們還處理了另一個常見的問題。XHTML文件總是以一個包含對DTD引用的標(biāo)簽開頭,解析器會加載這個DTD。可以理解的是,W3C肯定不樂意對諸如www.w3.org/TR/xhtml/DTD/xhtml-strict.dtd這樣的文件提供千萬億次的下載。總有一天他們會完全拒絕提供這些文件,但到寫本章時為止,他們還在并不情愿地提供DTD下載。如果你不需要驗證文件,只需調(diào)用:

程序清單3-8包含了網(wǎng)絡(luò)爬蟲程序的代碼。在本章的后續(xù)部分,將會看到SAX的另一個有趣用法,即將非XML數(shù)據(jù)源轉(zhuǎn)換成XML的一種簡單方式是報告XML解析器將要報告的SAX事件。詳情請參見3.8節(jié)。

程序清單3-8 sax/SAXTest.java

javax.xml.parsers.SAXParserFactory 1.4

·static SAXParserFactory newInstance()

返回SAXParserFactory類的一個實例。

·SAXParser newSAXParser()

返回SAXParser類的一個實例。

·boolean isNamespaceAware()

·void setNamespaceAware(boolean value)

獲取和設(shè)置工廠的namespaceAware屬性。當(dāng)設(shè)為true時,該工廠生成的解析器是命名空間感知的。

·boolean isValidating()

·void setValidating(boolean value)

獲取和設(shè)置工廠的validating屬性。當(dāng)設(shè)為true時,該工廠生成的解析器將要驗證其輸入。

javax.xml.parsers.SAXParser 1.4

·void parse(File f,DefaultHandler handler)

·void parse(String url,DefaultHandler handler)

·void parse(InputStream in,DefaultHandler handler)

解析來自給定文件、URL或輸入流的XML文檔,并把解析事件報告給指定的處理器。

org.xml.sax.ContentHandler 1.4

·void startDocument()

·void endDocument()

在文檔的開頭和結(jié)尾處被調(diào)用。

·void startElement(String uri,String lname,String qname,Attributes attr)

·void endElement(String uri,String lname,String qname)

在元素的開頭和結(jié)尾處被調(diào)用。

參數(shù):uri 命名空間的URI(如果解析器是命名空間感知的)

lname 不帶前綴的本地名(如果解析器是命名空間感知的)

qname 元素名(如果解析器是命名空間感知的),或者是帶有前綴的限定名(如果解析器除了報告本地名之外還報告限定名)

·void characters(char[]data,int start,int length)

解析器報告字符數(shù)據(jù)時被調(diào)用。

參數(shù):data 字符數(shù)據(jù)數(shù)組

start 在作為被報告的字符數(shù)據(jù)的一部分的字符數(shù)組中,第一個字符的索引

length 被報告的字符串的長度

org.xml.sax.Attributes 1.4

·int getLength()

返回存儲在該屬性集合中的屬性數(shù)量。

·String getLocalName(int index)

返回給定索引的屬性的本地名(無前綴),或在解析器不是命名空間感知的情況下返回空字符串。

·String getURI(int index)

返回給定索引的屬性的命名空間URI,或者,當(dāng)該節(jié)點不是命名空間的一部分,或解析器并非命名空間感知時返回空字符串。

·String getQName(int index)

返回給定索引的屬性的限定名(帶前綴),或當(dāng)解析器不報告限定名時返回空字符串。

·String getValue(int index)

·String getValue(String qname)

·String getValue(String uri,String lname)

根據(jù)給定索引、限定名或命名空間URI+本地名來返回屬性值;當(dāng)該值不存在時,返回null。

主站蜘蛛池模板: 绥棱县| 汶上县| 新巴尔虎右旗| 蒙城县| 张掖市| 屏山县| 乌什县| 若尔盖县| 阳春市| 临江市| 汪清县| 赤峰市| 吉安市| 隆德县| 五莲县| 三原县| 临桂县| 二手房| 曲松县| 海伦市| 建湖县| 台江县| 葫芦岛市| 宜宾县| 福泉市| 锦州市| 湘乡市| 高邑县| 深州市| 晋州市| 和龙市| 寿阳县| 江孜县| 庆城县| 镇安县| 南宫市| 托克托县| 齐齐哈尔市| 宜州市| 韶关市| 崇仁县|