原帖地址:http://www.ibm.com/developerworks/cn/xml/x-stax1.html
2007 年 3 月 02 日
Streaming API for XML (StAX) 是用 Java™ 語(yǔ)言處理 XML 的最新標(biāo)準(zhǔn)。作為一種面向流的方法,無(wú)論從性能還是可用性上都優(yōu)于其他方法,如 DOM 和 SAX。本系列分為 3 部分,本文是第 1 部分,簡(jiǎn)要介紹了 StAX 及其處理 XML 的基于指針的 API。
StAX 概述
從一開(kāi)始,Java API for XML Processing (JAXP) 就提供了兩種方法來(lái)處理 XML:文檔對(duì)象模型(DOM)方法是用標(biāo)準(zhǔn)的對(duì)象模型表示 XML 文檔;Simple API for XML (SAX) 方法使用應(yīng)用程序提供的事件處理程序來(lái)處理 XML。JSR-173 提出了一種面向流的新方法:Streaming API for XML (StAX)。其最終版本于 2004 年 3 月發(fā)布,并成為了 JAXP 1.4(將包含在即將發(fā)布的 Java 6 中)的一部分。
如其名稱所暗示的那樣,StAX 把重點(diǎn)放在流上。實(shí)際上,StAX 與其他方法的區(qū)別就在于應(yīng)用程序能夠把 XML 作為一個(gè)事件流來(lái)處理。將 XML 作為一組事件來(lái)處理的想法并不新穎(事實(shí)上 SAX 已經(jīng)提出來(lái)了),但不同之處在于 StAX 允許應(yīng)用程序代碼把這些事件逐個(gè)拉出來(lái),而不用提供在解析器方便時(shí)從解析器中接收事件的處理程序。
StAX 實(shí)際上包括兩套處理 XML 的 API,分別提供了不同程度的抽象。基于指針的 API 允許應(yīng)用程序把 XML 作為一個(gè)標(biāo)記(或事件)流來(lái)處理;應(yīng)用程序可以檢查解析器的狀態(tài),獲得解析的上一個(gè)標(biāo)記的信息,然后再處理下一個(gè)標(biāo)記,依此類推。這是一種低層 API,盡管效率高,但是沒(méi)有提供底層 XML 結(jié)構(gòu)的抽象。較為高級(jí)的基于迭代器的 API 允許應(yīng)用程序把 XML 作為一系列事件對(duì)象來(lái)處理,每個(gè)對(duì)象和應(yīng)用程序交換 XML 結(jié)構(gòu)的一部分。應(yīng)用程序只需要確定解析事件的類型,將其轉(zhuǎn)換成對(duì)應(yīng)的具體類型,然后利用其方法獲得屬于該事件的信息。
基本原理
為了使用這兩類 API,應(yīng)用程序首先必須獲得一個(gè)具體的 XMLInputFactory
。根據(jù)傳統(tǒng)的 JAXP 風(fēng)格,要用到抽象工廠模式;XMLInputFactory
類提供了靜態(tài)的 newInstance
方法,它負(fù)責(zé)定位和實(shí)例化具體的工廠。配置該實(shí)例可設(shè)置定制或者預(yù)先定義好的屬性(其名稱在類 XMLInputFactory 中定義)。最后,為了使用基于指針的 API,應(yīng)用程序還要通過(guò)調(diào)用某個(gè) createXMLStreamReader
方法獲得一個(gè) XMLStreamReader
。如果要使用基于事件迭代器的 API,應(yīng)用程序就要調(diào)用 createXMLEventReader
方法獲得一個(gè) XMLEventReader
(如清單 1 所示)。
清單 1. 獲取和配置默認(rèn)的 XMLInputFactory
// get the default factory instance
XMLInputFactory factory = XMLInputFactory.newInstance();
// configure it to create readers that coalesce adjacent character sections
factory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
XMLStreamReader r = factory.createXMLStreamReader(input);
// ...
|
XMLStreamReader
和 XMLEventReader
都允許應(yīng)用程序迭代底層的 XML 流。兩種方法的差別在于如何公開(kāi)解析后的 XML InfoSet 信息片段。XMLStreamReader
就像一個(gè)指針,指在剛剛解析過(guò)的 XML 標(biāo)記的后面,并提供了方法獲得更多關(guān)于該標(biāo)記的信息。這種方法節(jié)約內(nèi)存,因?yàn)椴挥脛?chuàng)建新的對(duì)象。但是,業(yè)務(wù)應(yīng)用程序開(kāi)發(fā)人員可能會(huì)發(fā)現(xiàn) XMLEventReader
更直觀一些,因?yàn)樗鼘?shí)際上就是一個(gè)標(biāo)準(zhǔn)的 Java 迭代器,將 XML 變成了事件對(duì)象流。每個(gè)事件對(duì)象都封裝了它所表示的特定 XML 結(jié)構(gòu)固有的信息。本系列的第二部分將詳細(xì)討論這種基于事件迭代器的 API。
使用哪種風(fēng)格的 API 取決于具體情況。和基于指針的 API 相比,基于事件迭代器的 API 具有更多的面向?qū)ο筇卣鳌R虼烁阌趹?yīng)用于模塊化的體系結(jié)構(gòu),因?yàn)楫?dāng)前的解析器狀態(tài)反映在事件對(duì)象中,應(yīng)用程序組件在處理事件的時(shí)候不需要訪問(wèn)解析器/讀取器。此外,還可以使用 XMLInputFactory
的 createXMLEventReader(XMLStreamReader)
方法從 XMLStreamReader
創(chuàng)建 XMLEventReader
。
StAX 還定義了一種序列化器 API,Java 標(biāo)準(zhǔn) XML 處理支持中一直缺少的一種特性。和解析一樣,也包含兩種風(fēng)格的流式 API:處理標(biāo)記的底層 XMLStreamWriter
和處理事件對(duì)象的高層 XMLEventWriter
。XMLStreamWriter
提供了寫(xiě)入單個(gè) XML 記號(hào)(比如開(kāi)始和關(guān)閉標(biāo)記或者元素屬性)的方法,不檢查這些標(biāo)記是否格式良好。另一方面,XMLEventWriter
允許應(yīng)用程序向輸出中添加完整的 XML 事件。第 3 部分將詳細(xì)討論 StAX 序列化器 API。
為什么使用 StAX?
開(kāi)始學(xué)習(xí)一種新的處理 XML 的 API 之前,可能要問(wèn)是否值得這樣做。事實(shí)上,StAX 所采用的基于拉的方法和其他方法相比有一些突出的優(yōu)點(diǎn)。首先,不管使用哪種 API 風(fēng)格,都是應(yīng)用程序調(diào)用讀取器(解析器)而不是相反。通過(guò)保留解析過(guò)程的控制權(quán),可以簡(jiǎn)化調(diào)用代碼來(lái)準(zhǔn)確地處理它預(yù)期的內(nèi)容。或者發(fā)生意外時(shí)停止解析。此外,由于該方法不基于處理程序回調(diào),應(yīng)用程序不需要像使用 SAX 那樣模擬解析器的狀態(tài)。
StAX 仍然保留了 SAX 相對(duì)于 DOM 的優(yōu)點(diǎn)。通過(guò)把重心從結(jié)果對(duì)象模型轉(zhuǎn)移到解析流本身,從理論上說(shuō)應(yīng)用程序能夠處理無(wú)限的 XML 流,因?yàn)槭录逃械呐R時(shí)性,不會(huì)在內(nèi)存中累積起來(lái)。對(duì)于那些使用 XML 作為消息傳遞協(xié)議而非表示文檔內(nèi)容的那些應(yīng)用程序尤其重要,比如 Web 服務(wù)或即時(shí)消息應(yīng)用程序。比方說(shuō),如果只是將其轉(zhuǎn)換成特定于應(yīng)用程序的對(duì)象模型然后就將其丟棄,那么為 Web 服務(wù)路由器 servlet 提供一個(gè) DOM 就沒(méi)有多少用處。使用 StAX 直接轉(zhuǎn)化成應(yīng)用程序模型效率更高。對(duì)于 Extensible Messaging and Presence Protocol(XMPP)客戶機(jī),根本不能使用 DOM,因?yàn)?XMPP 客戶機(jī)/服務(wù)器流是隨著用戶輸入的消息實(shí)時(shí)生成。等待流的關(guān)閉標(biāo)簽(以便最終建立 DOM)就意味著等待整個(gè)會(huì)話結(jié)束。通過(guò)把 XML 作為一系列的事件來(lái)處理,應(yīng)用程序能夠以最合適的方式響應(yīng)每個(gè)事件(比如顯示收到的即時(shí)消息等等)。
由于其雙向性,StAX 也支持鏈?zhǔn)教幚恚貏e是在事件層上。接收事件(無(wú)論什么來(lái)源)的能力被封裝在 XMLEventConsumer(XMLEventWriter 的擴(kuò)展)接口中。因此,可以模塊化地編寫(xiě)應(yīng)用程序從 XMLEventReader(也是一個(gè)普通的迭代器,可以按迭代器處理)讀取和處理 XML 事件、然后傳遞給事件消費(fèi)者(如果需要可以進(jìn)一步擴(kuò)展處理鏈)。在第 2 部分將看到,也可使用應(yīng)用程序提供的篩選器(實(shí)現(xiàn)了 EventFilter 接口的類)來(lái)定制 XMLEventReader 或者使用 EventReaderDelegate 修飾已有的 XMLEventReader。
總而言之,和 DOM 以及 SAX 相比,StAX 使應(yīng)用程序更貼近底層的 XML。使用 StAX,應(yīng)用程序不僅可以建立需要的對(duì)象模型(而不需要處理標(biāo)準(zhǔn) DOM),而且可以隨時(shí)這樣做,而不必等到解析器回調(diào)。
下一節(jié)將深入討論基于指針的 API 以及如何有效地使用它處理 XML 流。
基于指針的 API
如果使用基于指針的 API,應(yīng)用程序通過(guò)在 XML 標(biāo)記流中移動(dòng)邏輯指針來(lái)處理 XML。基于指針的解析器實(shí)質(zhì)上是一個(gè)狀態(tài)機(jī),在事件的驅(qū)動(dòng)下從一個(gè)良好定義的狀態(tài)轉(zhuǎn)移到另一個(gè)狀態(tài)。這里的觸發(fā)事件是隨著應(yīng)用程序使用適當(dāng)?shù)姆椒ㄍ苿?dòng)解析器在標(biāo)記流中前進(jìn)而解析出來(lái)的 XML 標(biāo)記。在每個(gè)狀態(tài),都可使用一組方法獲得上一個(gè)事件的信息。一般來(lái)說(shuō),并非每個(gè)狀態(tài)下都能使用所有的方法。
使用基于指針的方法,應(yīng)用程序首先必須通過(guò)調(diào)用其 createXMLStreamReader
方法從 XMLInputFactory
得到 XMLStreamReader
。該方法有多個(gè)版本,支持不同類型的輸入。比方說(shuō),可以創(chuàng)建 XMLStreamReader
解析 plain java.io.InputStream
、java.io.Reader
或者 JAXP Source(javax.xml.transform.Source
)。從理論上說(shuō),后一種辦法很容易和其他 JAXP 技術(shù)交互,比如 SAX 和 DOM。
清單 2. 創(chuàng)建 XMLStreamReader
解析 InputStream
URL url = new URL(uri);
InputStream input = url.openStream();
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader r = factory.createXMLStreamReader(uri, input);
// process the stream
// ...
r.close();
input.close();
|
XMLStreamReader
接口基本上定義了基于指針的 API(雖然標(biāo)記常量在其超類型 XMLStreamConstants
接口中定義)。之所以稱為基于指針,是因?yàn)樽x取器就像是底層標(biāo)記流上的指針。應(yīng)用程序可以沿著標(biāo)記流向前推進(jìn)指針并分析當(dāng)前指針?biāo)谖恢玫臉?biāo)記。
XMLStreamReader
提供了多種方法導(dǎo)航標(biāo)記流。為了確定當(dāng)前指針?biāo)赶虻臉?biāo)記(或事件)的類型,應(yīng)用程序可以調(diào)用 getEventType()
。該方法返回接口 XMLStreamConstants
中定義的一個(gè)標(biāo)記常量。移動(dòng)到下一個(gè)標(biāo)記,應(yīng)用程序可以調(diào)用 next()
。該方法也返回解析的標(biāo)記的類型,如果接著調(diào)用 getEventType()
則返回的值相同。只有當(dāng)方法 hasNext()
返回 true 時(shí)(就是說(shuō)還有其他標(biāo)記需要解析)才能調(diào)用該方法(以及其他移動(dòng)讀取器的方法)。
清單 3. 使用 XMLStreamReader
處理 XML 的常用模式
// create an XMLStreamReader
XMLStreamReader r = ...;
try {
int event = r.getEventType();
while (true) {
switch (event) {
case XMLStreamConstants.START_DOCUMENT:
// add cases for each event of interest
// ...
}
if (!r.hasNext())
break;
event = r.next();
}
} finally {
r.close();
}
|
還與其他幾種方法可以移動(dòng) reader
。 nextTag()
方法將跳過(guò)所有的空白、注釋或處理指令,直到遇到 START_ELEMENT
或 END_ELEMENT
。該方法在解析只含元素的內(nèi)容時(shí)很有用,如果在發(fā)現(xiàn)標(biāo)記之前遇到非空白文本(不包括注釋或處理指令),就會(huì)拋出異常。getElementText()
方法返回元素的開(kāi)始和關(guān)閉標(biāo)簽(即 START_ELEMENT
和 END_ELEMENT
)之間的所有文本內(nèi)容。如果遇到嵌套的元素就會(huì)拋出異常。
請(qǐng)注意,這里的 “標(biāo)記” 和 “事件” 可以互換使用。雖然基于指針的 API 的文檔說(shuō)的是事件,但把輸入源看成標(biāo)記流很方便。而且不容易造成混亂,因?yàn)檫€有一整套基于事件的 API(那里的事件是真正的對(duì)象)。不過(guò),XMLStreamReader
的事件本質(zhì)上并非都是標(biāo)記。比方說(shuō),START_DOCUMENT
和 END_DOCUMENT
事件不需要對(duì)應(yīng)的標(biāo)記。前一個(gè)事件是解析開(kāi)始之前發(fā)生,后者則在沒(méi)有更多解析工作要做的時(shí)候發(fā)生(比如解析完成最后一個(gè)元素的關(guān)閉標(biāo)簽之后,讀取器處于 END_ELEMENT
狀態(tài),但是如果沒(méi)有發(fā)現(xiàn)更多的標(biāo)記需要解析,讀取器就會(huì)切換到 END_DOCUMENT
狀態(tài))。
處理 XML 文檔
在每個(gè)解析器狀態(tài),應(yīng)用程序都可通過(guò)可用的方法獲得相關(guān)信息。比如,無(wú)論當(dāng)前是什么類型的事件,getNamespaceContext()
和 getNamespaceURI()
方法可以獲得當(dāng)前有效的名稱空間上下文和名稱空間 URI。類似的,getLocation()
可以獲得當(dāng)前事件的位置信息。方法 hasName()
和 hasText()
可以分別判斷當(dāng)前事件是否有名稱(比如元素或?qū)傩裕┗蛭谋荆ū热缱址⒆⑨尰?CDATA)。方法 isStartElement()
、isEndElement()
、isCharacters()
和 isWhiteSpace()
可以方便地確定當(dāng)前事件的性質(zhì)。最后,方法 require(int
, String
, String
) 可以聲明預(yù)期的解析器狀態(tài);除非當(dāng)前事件是指定的類型,并且本地名和名稱空間(如果給出的話)與當(dāng)前事件匹配,否則該方法將拋出異常。
清單 4. 如果當(dāng)前事件是 START_ELEMENT
使用有關(guān)的屬性方法
if (reader.getEventType() == XMLStreamConstants.START_ELEMENT) {
System.out.println("Start Element: " + reader.getName());
for(int i = 0, n = reader.getAttributeCount(); i < n; ++i) {
QName name = reader.getAttributeName(i);
String value = reader.getAttributeValue(i);
System.out.println("Attribute: " + name + "=" + value);
}
}
|
創(chuàng)建之后,XMLStreamReader
將從 START_DOCUMENT
狀態(tài)開(kāi)始(即 getEventType()
返回 START_DOCUMENT
)。處理標(biāo)記的時(shí)候應(yīng)考慮到這一點(diǎn)。和迭代器不同,不需要先移動(dòng)指針(使用 next()
)來(lái)進(jìn)入合法的狀態(tài)。同樣地,當(dāng)讀取器轉(zhuǎn)換到最終狀態(tài) END_DOCUMENT
之后,應(yīng)用程序也不應(yīng)再移動(dòng)它。在這種狀態(tài)下,hasNext()
方法將返回 false。
START_DOCUMENT
事件提供了獲取關(guān)于文檔本身信息的方法,如 getEncoding()
、getVersion()
和 isStandalone()
。應(yīng)用程序也可調(diào)用 getProperty(String)
獲得命名屬性的值,不過(guò)一些屬性僅在特定狀態(tài)做了定義(比方說(shuō),如果當(dāng)前事件是 DTD,則屬性 javax.xml.stream.notations
和 javax.xml.stream.entities
分別返回所有的符號(hào)和實(shí)體聲明)。
在 START_ELEMENT
和 END_ELEMENT
事件中,可以使用和元素名稱以及名稱空間有關(guān)的方法(如 getName()
、getLocalName()
、getPrefix()
和 getNamespaceXXX()
),在 START_ELEMENT
事件中還可使用與屬性有關(guān)的方法(getAttributeXXX()
)。
ATTRIBUTE
和 NAMESPACE
也被識(shí)別為獨(dú)立的事件,雖然在解析 典型的 XML 文檔時(shí)不會(huì)用到。但是當(dāng) ATTRIBUTE
或 NAMESPACE
節(jié)點(diǎn)作為 XPath 查詢結(jié)果返回時(shí)可以使用。
和基于文本的事件(如 CHARACTERS
、CDATA
、COMMENT
和 SPACE
),可使用各種 getTextXXX()
方法取得文本。可以分別使用 getPITarget()
和 getPIData()
檢索 PROCESSING_INSTRUCTION
的目標(biāo)和數(shù)據(jù)。ENTITY_REFERENCE
和 DTD
也支持 getText()
,ENTITY_REFERENCE
還支持 getLocalName()
。
解析完成后,應(yīng)用程序關(guān)閉讀取器并釋放解析過(guò)程中獲得的資源。請(qǐng)注意這樣并沒(méi)有關(guān)閉底層的輸入源。
清單 5 提供了一個(gè)完整的例子,使用基于指針的 API 處理 XML 文檔。首先取得 XMLInputFactory
的默認(rèn)實(shí)例并創(chuàng)建一個(gè) XMLStreamReader
解析給定的輸入流。然后不斷檢查讀取器的狀態(tài),根據(jù)當(dāng)前事件的類型報(bào)告某些信息(比如在 START_ELEMENT
狀態(tài)下報(bào)告元素名及元素屬性)。最后,遇到 END_DOCUMENT
時(shí)關(guān)閉讀取器。
清單 5. 使用 XMLStreamReader
解析 XML 文檔的完整例子
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader r = factory.createXMLStreamReader(input);
try {
int event = r.getEventType();
while (true) {
switch (event) {
case XMLStreamConstants.START_DOCUMENT:
out.println("Start Document.");
break;
case XMLStreamConstants.START_ELEMENT:
out.println("Start Element: " + r.getName());
for(int i = 0, n = r.getAttributeCount(); i < n; ++i)
out.println("Attribute: " + r.getAttributeName(i)
+ "=" + r.getAttributeValue(i));
break;
case XMLStreamConstants.CHARACTERS:
if (r.isWhiteSpace())
break;
out.println("Text: " + r.getText());
break;
case XMLStreamConstants.END_ELEMENT:
out.println("End Element:" + r.getName());
break;
case XMLStreamConstants.END_DOCUMENT:
out.println("End Document.");
break;
}
if (!r.hasNext())
break;
event = r.next();
}
} finally {
r.close();
}
|
XMLStreamReader
的高級(jí)用法
通過(guò)調(diào)用 XMLInputFactory
的帶有基本讀取器的 createFilteredReader
方法和一個(gè)應(yīng)用程序定義的篩選器(即實(shí)現(xiàn) StreamFilter
的類實(shí)例),可以創(chuàng)建篩選過(guò)的 XMLStreamReader
。導(dǎo)航篩選過(guò)的讀取器時(shí),讀取器每次移動(dòng)到下一個(gè)標(biāo)記之前都會(huì)詢問(wèn)篩選器。如果篩選器認(rèn)可了當(dāng)前事件,就將其公開(kāi)給篩選過(guò)的讀取器。否則跳過(guò)這個(gè)標(biāo)記并檢查下一個(gè),依此類推。這種方法可以讓開(kāi)發(fā)人員創(chuàng)建一個(gè)僅處理解析內(nèi)容子集的基于指針的 XML 處理程序,并與針對(duì)不同的擴(kuò)展的內(nèi)容模型的篩選器結(jié)合使用。
執(zhí)行更復(fù)雜的流操作,可以創(chuàng)建 StreamReaderDelegate
的子類并重寫(xiě)合適的方法。然后使用這個(gè)子類的實(shí)例包裝基本 XMLStreamReader
,從而為應(yīng)用程序提供一個(gè)修改過(guò)的基本 XML 流的視圖。可通過(guò)這種技術(shù)對(duì) XML 流執(zhí)行簡(jiǎn)單的轉(zhuǎn)換,比如篩掉或者替換特定的標(biāo)記,甚至增加新的標(biāo)記。
清單 6 用定制的 StreamReaderDelegate
包裝了基本 XMLStreamReader
,重寫(xiě)了 next()
方法來(lái)跳過(guò) COMMENT
和 PROCESSING_INSTRUCTION
事件。使用該讀取器時(shí),應(yīng)用程序不用擔(dān)心會(huì)遇到這種類型的標(biāo)記。
清單 6. 使用定制的 StreamReaderDelegate
篩選注釋和處理指令
URL url = new URL(uri);
InputStream input = url.openStream();
XMLInputFactory f = XMLInputFactory.newInstance();
XMLStreamReader r = f.createXMLStreamReader(uri, input);
XMLStreamReader fr = new StreamReaderDelegate(r) {
public int next() throws XMLStreamException {
while (true) {
int event = super.next();
switch (event) {
case XMLStreamConstants.COMMENT:
case XMLStreamConstants.PROCESSING_INSTRUCTION:
continue;
default:
return event;
}
}
}
};
try {
int event = fr.getEventType();
while (true) {
switch (event) {
case XMLStreamConstants.COMMENT:
case XMLStreamConstants.PROCESSING_INSTRUCTION:
// this should never happen
throw new IllegalStateException("Filter failed!");
default:
// process XML normally
}
if (!fr.hasNext())
break;
event = fr.next();
}
} finally {
fr.close();
}
input.close();
|
基于指針處理之外的其他技術(shù)
可以看到,基于指針的 API 主要是為了提高效率。所有的狀態(tài)信息可以直接從流讀取器獲得,不需要?jiǎng)?chuàng)建額外的對(duì)象。非常適用于性能和低內(nèi)存占用至關(guān)重要的應(yīng)用程序。
人們?cè)缇驼J(rèn)識(shí)到了拉式 XML 解析的好處。事實(shí)上,StAX 本身源于一種稱為 XML Pull Parsing 的方法。XML Pull Parser API 類似于 StAX 所提供的基于指針的 API,可以通過(guò)分析解析器的狀態(tài)獲得上一個(gè)解析事件的信息,然后移動(dòng)到下一個(gè),依此類推。但沒(méi)有提供基于事件迭代器的 API。這是一種非常輕型的方法,特別適合資源受限的環(huán)境,比如 J2ME。但是,很少有實(shí)現(xiàn)提供企業(yè)級(jí)特性如驗(yàn)證,因此 XML Pull 一直未受到企業(yè) Java 開(kāi)發(fā)人員的關(guān)注。
基于以往拉式解析器實(shí)現(xiàn)的經(jīng)驗(yàn),StAX 的創(chuàng)建者選擇了在基于指針的 API 之外增加一種面向?qū)ο蟮?API。雖然 XMLEventReader
接口看起來(lái)似乎很簡(jiǎn)單,但是基于事件迭代器的方法具有一個(gè)基于指針的方法不具備的重要優(yōu)點(diǎn)。通過(guò)將解析器事件變成一級(jí)對(duì)象,從而讓?xiě)?yīng)用程序可以采用面向?qū)ο蟮姆绞教幚硭鼈儭_@樣做有助于模塊化和不同應(yīng)用程序組件之間的代碼重用。
清單 7. 使用 StAX XMLEventReader
解析 XML
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLEventReader reader = inputFactory.createXMLEventReader(input);
try {
while (reader.hasNext()) {
XMLEvent e = reader.nextEvent();
if (e.isCharacters() && ((Characters) e).isWhiteSpace())
continue;
out.println(e);
}
} finally {
reader.close();
}
|
結(jié)束語(yǔ)
本文介紹了 StAX 及其基于指針的 API。第 2 部分將深入討論事件迭代器 API。
參考資料
學(xué)習(xí)
獲得產(chǎn)品和技術(shù)
討論
關(guān)于作者
 |
|
 |
Peter Nehrer 是一名專長(zhǎng)于基于 Eclipse 的企業(yè)解決方案和 Java EE 應(yīng)用程序的軟件顧問(wèn)。他創(chuàng)建了 Ecliptical Software Inc.,并且是一些和 Eclipse 有關(guān)的開(kāi)放源碼項(xiàng)目的貢獻(xiàn)者。他擁有從馬薩諸塞州大學(xué)阿默斯特校區(qū)獲得的計(jì)算機(jī)科學(xué)碩士學(xué)位。
|