?
J2EE/XML
開發者通常都是使用文檔對象模型
(DOM)API
或簡單的
API for XML(SAX) API
來分析
XML
文檔。然而,這些
API
都有其缺點。其中,
DOM API
的缺點之一是消耗大量的內存,因為在該
XML
文檔可以被導航之前,必須創建一個完整的
XML
文檔的內存結構。而
SAX API
的缺點在于,它實例了一種推分析模型
API
,其中分析事件是由分析器生成的。比較之下,
StAX
則是基于一種拉分析模型。在本文中,你將首先創建你自己的
XML
文檔,然后學習使用各種不同方法來對之進行分析;最后,我們使用事件生成的
StAX
拉方法。
一、
Push
推分析之于拉分析
Pull
?
比較于推分析,拉分析具有如下一些優點:
1.
在拉分析中,事件是由分析應用程序生成的,因此把分析規則提供到客戶端而不是分析器。
2.
拉分析的代碼更簡單并且它比推分析有更少的庫。
3.
拉分析客戶端能同時讀多個
XML
文檔。
4.
拉分析允許你過濾
XML
文檔并且跳過分析事件。
二、了解
StAX
針對于
XML
的流式
API(StAX)
,是在
2004
年
3
月的
JSR 173
規范中引入,這是一種針對
XML
的流式拉分析
API
。
StAX
是
JDK 6.0
提供的一種新特征,你可以從此處下載它的測試版本試用。
一個推模型分析器不斷地生成事件,直到
XML
文檔被完全分析結束。但是,拉分析由應用程序進行調整;因此,分析事件是由應用程序生成的。這意味著,使用
StaX
,你可以推遲分析
-
在分析時跳過元素并且分析多個文檔。在使用
DOM API
的時候,你必須把整個的
XML
文檔分析成一棵
DOM
結構,這樣也就降低了分析效率。而借助于
StAX
,在分析
XML
文檔時生成分析事件。有關于
StAX
分析器與其它分析器的比較在此不多介紹。
StAX API
的實現是使用了
Java Web
服務開發(
JWSDP
)
1.6
,并結合了
Sun Java
流式
XML
分析器
(SJSXP)-
它位于
javax.xml.stream
包中。
XMLStreamReader
接口用于分析一個
XML
文檔,而
XMLStreamWriter
接口用于生成一個
XML
文檔。
XMLEventReader
負責使用一個對象事件迭代子分析
XML
事件
-
這與
XMLStreamReader
所使用的光標機制形成對照。本教程將基于
JDK 6.0
中的
StAX
實現來完成對一個
XML
文檔的分析。
其實,
StaX
僅僅是
JDK 6.0
所提供的
XML
新特征之一。新的
JDK 6.0
還提供了對針對于
XML-Web
服務的
Java
架構(
JAX-WS
)
2.0
,針對于
XML
綁定的
Java API(JAXB) 2.0
,
XML
數字簽名
API
的支持,甚至還支持
SQL:2003 'XML'
數據類型。
三、安裝
?
如果你正在使用
JDK 6.0
,那么默認情況下,
StAX API
位于
Classpath
中。如果你在使用
JWSDP 1.6
,請把
JWSDP 1.6 StAX API
添加到
classpath
中。
?
jsr173_api.jar
和
sjsxp.jar
添加到
CLASSPATH
變量中。在
<jwsdp-1.6>
目錄下安裝
JWSDP 1.6
。
Jsr173_api.jar
相應于
JSR-173 API JAR
,
Sjsxp.jar
相應于
SJXSP
實現
JAR
。
?
四、使用
XMLStreamWriter
進行寫操作
?
?
首先,你要創建將待分析的
XML
文檔。由
StAX
的
XMLStreamWriter
生成
XML
。然而,
XMLStreamWriter
的一個限制是,它不一定會生成良構的文檔
-
而且生成的文檔也不一定是有效的。你需要確保生成的
XML
文檔是良構的。列表
1
是一個由
XMLStreamWriter
生成的原始
XML
文檔的示例。
在此,你試圖使用
XMLStreamWriter API
生成列表
1
中的
catalog.xml
。在本節中的代碼片斷節選自
XMLWriter.java
應用程序,顯示于列表
2
中。首先,你將導入
StAX
包類,請參考下列編碼:
import javax.xml.stream.*;
import javax.xml.stream.events.*;
import javax.xml.stream.XMLOutputFactory;
//
首先你必須創建一個新的
XMLOutputFactory
XMLOutputFactory outputFactory=XMLOutputFactory.newInstance();
//
接下來,創建一個
FileWriter
以輸出
XML
文檔
-
它將被生成到一個
XML
文件中:
FileWriter output=new FileWriter(new File("C:/STAX/catalog.xml"));
//
接下來,創建一個
XMLStreamWriter
:
XMLStreamWriter XMLStreamWriterr=outputFactory.createXMLStreamWriter(output);
//
添加要在
XML
聲明中指定的編碼和版本(記住,指定的編碼并不是生成的
XML
文檔的編碼)。如果你需要指定
XML
文檔的編碼,該怎么辦呢?當從一個
XMLOutputFactory
對象創建一個
XMLStreamWriter
對象時,你會這樣做:
XMLStreamWriter.writeStartDocument("UTF-8"
,
"1.0");
//
使用
writeComment()
方法以輸出一個注釋:
XMLStreamWriter.writeComment("A OReilly Journal Catalog");
//
使用
writeProcessingInstruction()
方法以輸出一條處理指令:
XMLStreamWriter.writeProcessingInstruction("catalog"
,
"journal='OReilly'");
//
使用
writeStartElement()
方法以輸出
'catalog'
元素的開始(元素前綴和命名空間
URI
也可以在這個方法中指定的):
XMLStreamWriter.writeStartElement("journal"
,
"catalog"
,
"http://OnJava.com/Journal");
//
使用
writeNamespace()
方法以添加
'journal'
命名空間聲明(命名空間前綴和命名空間
URI
也是在這個方法中指定的):
XMLStreamWriter.writeNamespace("journal"
,
"http://OnJava.com/Journal");
?
//
再次使用
writeNamespace()
方法添加
xsi
命名空間:
XMLStreamWriter.writeNamespace("xsi"
,
"http://www.w3.org/2001/XMLSchema-instance");
//
使用
writeAttribute()
方法添加
xsi:namespaceSchemaLocation
屬性:
XMLStreamWriter.writeAttribute("xsi:noNamespaceSchemaLocation"
,
"file://c:/Schemas/catalog.xsd");
//
使用
writeAttribute()
方法添加
'publisher'
屬性:
XMLStreamWriter.writeAttribute("publisher"
,
"OReilly");
?
//
輸出
'journal'
元素的開始。當增加一個新元素時,前一個元素的
'>'
括號也被添加上:
XMLStreamWriter.writeStartElement("journal"
,
"journal"
,
"http:
//OnJava.com/Journal");
//
使用
writeAttribute()
方法以添加
'date'
和
'title'
屬性。然后,使用
writeElement()
方法以添加
'article'
和
'title'
元素。然后,使用
writeCharacters()
方法輸出
'title'
元素的文本:
XMLStreamWriter.writeCharacters("Data Binding with XMLBeans");
//
任何包含文本或子元素的元素都要有一個結束標簽。使用
writeEndElement()
元素來添加
'title'
元素的結束標簽:
XMLStreamWriter.writeEndElement();
//
添加
'author'
元素和
'journal'
元素的結束標簽。在
writeEndElement()
方法中,不必要指定元素前綴和命名空間
URI
。以類似方式添加另一個
'journal'
元素。然后,添加
'catalog'
元素的結束標簽。最后,輸出緩沖的數據:
XMLStreamWriter.flush();
//
最后一步,關閉
XMLStreamWriter
。
XMLStreamWriter.close();
?
//
這就是生成
catalog.xml
的過程。
源碼中的列表
2
展示了完整的
Java
應用程序
-XMLWriter.java
。這個應用程序可以作為一個命令行應用程序運行或在一種例如
Eclipse
這樣的
IDE
中運行。
?
五、使用
XMLStreamReader
進行分析
?
?
通過使用
XMLStreamReader API
分析列表
1
中的文檔,我們來詳細分析一下其工作原理。
XMLStreamReader
使用一種光標分析
XML
文檔。它的接口包含一個
next()
方法
-
由它分析下一個分析事件。
getEventType()
方法返回事件類型。后面的代碼片斷來自于
XMLParser.java
應用程序,詳見列表
3
。
在這個
XMLParser.java
應用程序中,首先,你要導入
StAX
類:
import javax.xml.stream.*;
import javax.xml.stream.events.*;
import javax.xml.stream.XMLInputFactory;
//
創建一個
XMLInputFactory
,由此你會得到一個
XMLStreamReader
:
XMLInputFactory inputFactory=XMLInputFactory.newInstance();
//
創建一個
InputStream
,作為一個輸入流,它描述了將被分析的文件。另外,還要從前面創建的
XMLInputFactory
對象中創建一個
XMLStreamReader
。
InputStream input=new FileInputStream(new File("C:/STAX/catalog.xml"));
XMLStreamReader xmlStreamReader =inputFactory.createXMLStreamReader(input);
//
如果更多分析事件可用,
hasNext()
方法返回
true
。然后,使用
next()
方法獲得下一個分析事件:
int event=xmlStreamReader.next();
比較于
SAX
分析,
StAX
分析的優點是,一個分析事件可以被跳過
-
通過調用
next()
方法
,詳見下面的代碼。例如,如果分析事件類型為
ENTITY_DECLARATION
,那么開發者可以決定是要從當前事件中獲得事件信息,還是檢索下一個事件:
If(event.getEventType()==XMLStreamConstants.ENTITY_DECLARATION){
?????????????? int event=xmlStreamReader.next();
}
通過不調用
next()
方法,分析也可以被推遲。
next()
方法返回
int
,它代表了一個分析事件
-
通過使用一個
XMLStreamConstants
常量指定。
XMLStreamReader
所返回的不同的事件類型列舉于表格1中。
事件類型
|
描述
|
START_DOCUMENT
|
一個文檔的開始
|
START_ELEMENT
|
一個元素的開始
|
ATTRIBUTE
|
一個元素屬性
|
NAMESPACE
|
一個命名空間聲明
|
CHARACTERS
|
字符可以是文本,或是一個空格
|
COMMENT
|
一個注釋
|
SPACE
|
可忽略的空格
|
PROCESSING_INSTRUCTION
|
處理指令
|
DTD
|
一個
DTD
|
ENTITY_REFERENCE
|
一個實體參考
|
CDATA
|
Cdata
節
|
END_ELEMENT
|
結束元素
|
END_DOCUMENT
|
結束文檔
|
ENTITY_DECLARATION
|
一個實體聲明
|
NOTATION_DECLARATION
|
一個標志聲明
|
?
表格
1.XMLStreamReader
事件
?
?
這些不同的分析事件能夠使你獲得
XML
文檔中的數據和元數據。如果分析事件類型是
START_DOCUMENT
,那么你將使用
getEncoding()
方法獲得
XML
文檔中的指定編碼,而你將使用
getVersion()
方法返回
XML
文檔的
XML
版本。
同樣,如果你在使用一個
START_ELEMENT
事件類型工作,那么你將使用
getPrefix()
方法來返回元素前綴并且使用
getNamespaceURI
來返回元素前綴命名空間或默認命名空間。為了獲得元素的本地命名,你將使用
getLocalName()
方法并且使用
getAttributesCount()
方法獲得屬性數目。你將使用
getAttributePrefix(i)
方法得到一個指定的屬性索引
i
的屬性前綴,而使用
getAttributeNamespace(i)
方法取得屬性命名空間。使用
getAttributeLocalName(i)
方法獲得屬性本地命名,使用
getAttributeValue(i)
方法獲得屬性值。如果事件類型是
CHARACTERS
或
COMMENT
,則使用
getText()
方法獲得相應的文本。
列表
4
顯示了示例
XML
文檔,
catalog.xml
的分析輸出結果。
列表
3
顯示了用于分析
XML
文檔的
Java
應用程序。你可以從命令行上或在一種例如
Eclipse
這樣的
IDE
中來運行該應用程序。記住:如果你沒有首先運行
XMLWriter.java
應用程序而運行
XMLParser.java(
見源碼中的列表
2)
,那么你需要把
catalog.xml(
見源碼中的列表
1)
復制到
C:/StAX
目錄下。
?
?
六、使用
XMLEventReader
進行分析
?
本節將向你展示如何使用
XMLEventReader
來分析
catalog.xml
。
XMLEventReader
接口使用一個事件對象迭代算子分析一個
XML
文檔;通過這種方式,一個
XML
事件生成一個
XMLEvent
對象。
XMLEventReader
類似于
XMLStreamReader-
分析事件是由
StAX
分析器生成的。然而,
XMLEventReader
比
XMLStreamReader
有一個優點:通過使用
XMLEventReader
,一個應用程序可以使用
peek()
方法來
"
偷看
"
下一個事件,而不必從流中讀取事件。這樣,一個應用程序客戶端可以決定是否有必要分析下一個事件。
本節中的代碼片斷節選自
XMLEventParser.java
應用程序,請參見列表
5
。
首先,導入
StAX
類:
import javax.xml.stream.*;
import javax.xml.stream.events.*;
import javax.xml.stream.XMLInputFactory;
接下來,創建一個
XMLInputFactory
,由它獲得一個
XMLEventReader
對象:
XMLInputFactory inputFactory=XMLInputFactory.newInstance();
InputStream input=new FileInputStream(new File("C:/STAX/catalog.xml"));
XMLEventReader xmlEventReader =inputFactory.createXMLEventReader(input);
在
StAX
中,
XML
文檔事件是通過
XMLEvent
對象描述的。使用
nextEvent()
方法來遍歷
XMLEventReader
對象以獲得下一個事件:
XMLEvent event=xmlEventReader.nextEvent();
使用
getEventType()
方法來獲得事件類型
(
請參考表格1
)
。
XMLEvent
接口還提供布爾方法來獲得事件類型。例如,
isStartDocum ent()
返回
true
,如果事件是開始文檔類型。在下列代碼中,事件是開始元素類型,因此一個
StartElement
對象可以從這個
XMLEvent
接口獲得:
if(event.isStartElement()){
StartElement startElement=event.asStartElement();
}
使用
getAttributes()
方法獲得元素屬性:
Iterator attributes=startElement.getAttributes();
這個
Iterator
描述了一個
javax.xml.stream.events.Attribute
對象。使用
next()
方法遍歷該
Iterator
。
Attribute attribute=(javax.xml.stream.events.Attribute)(attributes.next());
最后,使用
getName()
方法獲得屬性命名,使用
getValue()
方法獲得屬性值。
列表
5
顯示出分析該
XML
文檔的
Java
應用程序。應用程序
XMLEventReader
可以作為一個命令行應用程序運行,或在一種例如
Eclipse
這樣的
IDE
中運行。記住:如果你運行
XMLWriter.java
或
XMLParser.java
應用程序而不首先運行
XMLEventParser.java
應用程序,那么你將需要把
catalog.xml
復制到
C:/StAX
目錄下。
最終,基于拉的事件生成把事件規則提供到分析器應用程序而不是提供到分析器。
?
posted on 2006-09-17 22:24
Lizzie 閱讀(434)
評論(1) 編輯 收藏 所屬分類:
專業積木