posts - 20,  comments - 7,  trackbacks - 0

          ?

          J2EE/XML 開發(fā)者通常都是使用文檔對象模型 (DOM)API 或簡單的 API for XML(SAX) API 來分析 XML 文檔。然而,這些 API 都有其缺點。其中, DOM API 的缺點之一是消耗大量的內(nèi)存,因為在該 XML 文檔可以被導航之前,必須創(chuàng)建一個完整的 XML 文檔的內(nèi)存結(jié)構(gòu)。而 SAX API 的缺點在于,它實例了一種推分析模型 API ,其中分析事件是由分析器生成的。比較之下, StAX 則是基于一種拉分析模型。在本文中,你將首先創(chuàng)建你自己的 XML 文檔,然后學習使用各種不同方法來對之進行分析;最后,我們使用事件生成的 StAX 拉方法。

          一、 Push 推分析之于拉分析 Pull

          ?



            比較于推分析,拉分析具有如下一些優(yōu)點:

             1. 在拉分析中,事件是由分析應用程序生成的,因此把分析規(guī)則提供到客戶端而不是分析器。

             2. 拉分析的代碼更簡單并且它比推分析有更少的庫。

             3. 拉分析客戶端能同時讀多個 XML 文檔。

             4. 拉分析允許你過濾 XML 文檔并且跳過分析事件。

          二、了解 StAX


          針對于 XML 的流式 API(StAX) ,是在 2004 3 月的 JSR 173 規(guī)范中引入,這是一種針對 XML 的流式拉分析 API StAX JDK 6.0 提供的一種新特征,你可以從此處下載它的測試版本試用。

          一個推模型分析器不斷地生成事件,直到 XML 文檔被完全分析結(jié)束。但是,拉分析由應用程序進行調(diào)整;因此,分析事件是由應用程序生成的。這意味著,使用 StaX ,你可以推遲分析 - 在分析時跳過元素并且分析多個文檔。在使用 DOM API 的時候,你必須把整個的 XML 文檔分析成一棵 DOM 結(jié)構(gòu),這樣也就降低了分析效率。而借助于 StAX ,在分析 XML 文檔時生成分析事件。有關(guān)于 StAX 分析器與其它分析器的比較在此不多介紹。

          StAX API
          的實現(xiàn)是使用了 Java Web 服務開發(fā)( JWSDP 1.6 ,并結(jié)合了 Sun Java 流式 XML 分析器 (SJSXP)- 它位于 javax.xml.stream 包中。 XMLStreamReader 接口用于分析一個 XML 文檔,而 XMLStreamWriter 接口用于生成一個 XML 文檔。 XMLEventReader 負責使用一個對象事件迭代子分析 XML 事件 - 這與 XMLStreamReader 所使用的光標機制形成對照。本教程將基于 JDK 6.0 中的 StAX 實現(xiàn)來完成對一個 XML 文檔的分析。

          其實, StaX 僅僅是 JDK 6.0 所提供的 XML 新特征之一。新的 JDK 6.0 還提供了對針對于 XML-Web 服務的 Java 架構(gòu)( JAX-WS 2.0 ,針對于 XML 綁定的 Java API(JAXB) 2.0 XML 數(shù)字簽名 API 的支持,甚至還支持 SQL:2003 'XML' 數(shù)據(jù)類型。

          三、安裝

          ?

            如果你正在使用 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 實現(xiàn) JAR

          ?

          四、使用 XMLStreamWriter 進行寫操作

          ?

          ?

            首先,你要創(chuàng)建將待分析的 XML 文檔。由 StAX XMLStreamWriter 生成 XML 。然而, XMLStreamWriter 的一個限制是,它不一定會生成良構(gòu)的文檔 - 而且生成的文檔也不一定是有效的。你需要確保生成的 XML 文檔是良構(gòu)的。列表 1 是一個由 XMLStreamWriter 生成的原始 XML 文檔的示例。

            在此,你試圖使用 XMLStreamWriter API 生成列表 1 中的 catalog.xml 。在本節(jié)中的代碼片斷節(jié)選自 XMLWriter.java 應用程序,顯示于列表 2 中。首先,你將導入 StAX 包類,請參考下列編碼:

          import javax.xml.stream.*;
          import javax.xml.stream.events.*;
          import javax.xml.stream.XMLOutputFactory;
            

          // 首先你必須創(chuàng)建一個新的 XMLOutputFactory
          XMLOutputFactory outputFactory=XMLOutputFactory.newInstance();


          //
          接下來,創(chuàng)建一個 FileWriter 以輸出 XML 文檔 - 它將被生成到一個 XML 文件中:
          FileWriter output=new FileWriter(new File("C:/STAX/catalog.xml"));

          // 接下來,創(chuàng)建一個 XMLStreamWriter
          XMLStreamWriter XMLStreamWriterr=outputFactory.createXMLStreamWriter(output);

          // 添加要在 XML 聲明中指定的編碼和版本(記住,指定的編碼并不是生成的 XML 文檔的編碼)。如果你需要指定 XML 文檔的編碼,該怎么辦呢?當從一個 XMLOutputFactory 對象創(chuàng)建一個 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");

          // 任何包含文本或子元素的元素都要有一個結(jié)束標簽。使用 writeEndElement() 元素來添加 'title' 元素的結(jié)束標簽:
          XMLStreamWriter.writeEndElement();

          // 添加 'author' 元素和 'journal' 元素的結(jié)束標簽。在 writeEndElement() 方法中,不必要指定元素前綴和命名空間 URI 。以類似方式添加另一個 'journal' 元素。然后,添加 'catalog' 元素的結(jié)束標簽。最后,輸出緩沖的數(shù)據(jù):

          XMLStreamWriter.flush();

          // 最后一步,關(guān)閉 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;

          // 創(chuàng)建一個 XMLInputFactory ,由此你會得到一個 XMLStreamReader
          XMLInputFactory inputFactory=XMLInputFactory.newInstance();

          // 創(chuàng)建一個 InputStream ,作為一個輸入流,它描述了將被分析的文件。另外,還要從前面創(chuàng)建的 XMLInputFactory 對象中創(chuàng)建一個 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 分析的優(yōu)點是,一個分析事件可以被跳過 - 通過調(diào)用 next() 方法 ,詳見下面的代碼。例如,如果分析事件類型為 ENTITY_DECLARATION ,那么開發(fā)者可以決定是要從當前事件中獲得事件信息,還是檢索下一個事件:

          If(event.getEventType()==XMLStreamConstants.ENTITY_DECLARATION){
          ?????????????? int event=xmlStreamReader.next();
          }

          通過不調(diào)用 next() 方法,分析也可以被推遲。 next() 方法返回 int ,它代表了一個分析事件 - 通過使用一個 XMLStreamConstants 常量指定。

          XMLStreamReader
          所返回的不同的事件類型列舉于表格1中。

          事件類型

          描述

          START_DOCUMENT

          一個文檔的開始

          START_ELEMENT

          一個元素的開始

          ATTRIBUTE

          一個元素屬性

          NAMESPACE

          一個命名空間聲明

          CHARACTERS

          字符可以是文本,或是一個空格

          COMMENT

          一個注釋

          SPACE

          可忽略的空格

          PROCESSING_INSTRUCTION

          處理指令

          DTD

          一個 DTD

          ENTITY_REFERENCE

          一個實體參考

          CDATA

          Cdata 節(jié)

          END_ELEMENT

          結(jié)束元素

          END_DOCUMENT

          結(jié)束文檔

          ENTITY_DECLARATION

          一個實體聲明

          NOTATION_DECLARATION

          一個標志聲明

          ?

          表格 1.XMLStreamReader 事件

          ?

          ?

          這些不同的分析事件能夠使你獲得 XML 文檔中的數(shù)據(jù)和元數(shù)據(jù)。如果分析事件類型是 START_DOCUMENT ,那么你將使用 getEncoding() 方法獲得 XML 文檔中的指定編碼,而你將使用 getVersion() 方法返回 XML 文檔的 XML 版本。


          同樣,如果你在使用一個 START_ELEMENT 事件類型工作,那么你將使用 getPrefix() 方法來返回元素前綴并且使用 getNamespaceURI 來返回元素前綴命名空間或默認命名空間。為了獲得元素的本地命名,你將使用 getLocalName() 方法并且使用 getAttributesCount() 方法獲得屬性數(shù)目。你將使用 getAttributePrefix(i) 方法得到一個指定的屬性索引 i 的屬性前綴,而使用 getAttributeNamespace(i) 方法取得屬性命名空間。使用 getAttributeLocalName(i) 方法獲得屬性本地命名,使用 getAttributeValue(i) 方法獲得屬性值。如果事件類型是 CHARACTERS COMMENT ,則使用 getText() 方法獲得相應的文本。

          列表 4 顯示了示例 XML 文檔, catalog.xml 的分析輸出結(jié)果。

          列表 3 顯示了用于分析 XML 文檔的 Java 應用程序。你可以從命令行上或在一種例如 Eclipse 這樣的 IDE 中來運行該應用程序。記住:如果你沒有首先運行 XMLWriter.java 應用程序而運行 XMLParser.java( 見源碼中的列表 2) ,那么你需要把 catalog.xml( 見源碼中的列表 1) 復制到 C:/StAX 目錄下。

          ?

          ?

          六、使用 XMLEventReader 進行分析

          ?

          本節(jié)將向你展示如何使用 XMLEventReader 來分析 catalog.xml XMLEventReader 接口使用一個事件對象迭代算子分析一個 XML 文檔;通過這種方式,一個 XML 事件生成一個 XMLEvent 對象。 XMLEventReader 類似于 XMLStreamReader- 分析事件是由 StAX 分析器生成的。然而, XMLEventReader XMLStreamReader 有一個優(yōu)點:通過使用 XMLEventReader ,一個應用程序可以使用 peek() 方法來 " 偷看 " 下一個事件,而不必從流中讀取事件。這樣,一個應用程序客戶端可以決定是否有必要分析下一個事件。 本節(jié)中的代碼片斷節(jié)選自 XMLEventParser.java 應用程序,請參見列表 5

          首先,導入 StAX 類:

          import javax.xml.stream.*;
          import javax.xml.stream.events.*;
          import javax.xml.stream.XMLInputFactory;
            接下來,創(chuàng)建一個 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 目錄下。

          最終,基于拉的事件生成把事件規(guī)則提供到分析器應用程序而不是提供到分析器。

          ?

          posted on 2006-09-17 22:24 Lizzie 閱讀(438) 評論(1)  編輯  收藏 所屬分類: 專業(yè)積木

          FeedBack:
          # re: 在JDK 6.0中基于StAX分析XML數(shù)據(jù)
          2009-11-23 07:05 | anon
          you might also want to look at vtd-xml, the latest and most advanced XML processing API available today

          http://vtd-xml.sf.net  回復  更多評論
            

          <2006年9月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          1234567

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          文章分類

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 日喀则市| 轮台县| 体育| 甘肃省| 康平县| 潮州市| 东莞市| 泰兴市| 英山县| 蕲春县| 堆龙德庆县| 彰武县| 包头市| 乐亭县| 阳信县| 浦江县| 徐水县| 灵石县| 云安县| 和林格尔县| 隆昌县| 金山区| 广河县| 巴东县| 东丽区| 利川市| 永登县| 澳门| 德钦县| 黄大仙区| 巨鹿县| 义乌市| 武冈市| 潼南县| 乡宁县| 南和县| 历史| 莎车县| 昌吉市| 富民县| 清镇市|