在JDK 6.0中基於StAX分析XML資料

來源:互聯網
上載者:User
xml|資料

  J2EE/XML開發人員通常都是使用文件物件模型(DOM)API或簡單的API for XML(SAX) API來分析XML文檔。然而,這些API都有其缺點。其中,DOM API的缺點之一是消耗大量的記憶體,因為在該XML文檔可以被導航之前,必須建立一個完整的XML文檔的記憶體結構。而SAX API的缺點在於,它執行個體了一種推分析模型API,其中分析事件是由分析器產生的。比較之下,StAX則是基於一種拉分析模型。在本文中,你將首先建立你自己的XML文檔,然後學習使用各種不同方法來對之進行分析;最後,我們使用事件產生的StAX拉方法。

  一、 推分析之於拉分析

  比較於推分析,拉分析具有如下一些優點:

  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中。這需要把<jwsdp-1.6>\sjsxp\lib\ jsr173_api.jar和<jwsdp-1.6>\sjsxp\lib\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中得到你的XMLStreamWriter。因此,首先你必須建立一個新的XMLOutputFactory:

XMLOutputFactory outputFactory=XMLOutputFactory.newInstance();
  接下來,建立一個FileWriter以輸出XML文檔-它將被產生到一個XML檔案中:

FileWriter output=new FileWriter(new File("C:/STAX/catalog.xml"));
  接下來,建立一個XMLStreamWriter:

XMLStreamWriter XMLStreamWriterr=outputFactory.createXMLStreamWriter(output);
  現在,使用writeStartDocument()方法建立一個文檔開頭。添加要在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介面還提供布爾方法來獲得事件類型。例如,isStartDocument()返回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目錄下。

  最終,基於拉的事件產生把事件規則提供到分析器應用程式而不是提供到分析器。

相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。