(五)使用StAX接口操作xml
StAX,全稱Streaming API for XML,一種全新的,基於流的JAVA XML解析標准類庫。其最終版本於 2004 年 3 月發布,並成為了 JAXP 1.4(將包含在即將發布的 Java 6 中)的一部分。在某種程度上來說,StAX與SAX一樣是基於XML事件的解析方式,它們都不會一次性加載整個XML文件。但是它們之間也有很大的不同。
StAX和SAX的區別——拉式解析器和推式解析器的區別
雖然StAX與SAX一樣基於XML事件解析,相比於DOM將整個XML加載進內存來說效率高。不同的是,StAX在在處理XML事件的方式上使得應用程序更接近底層,所以在效率上比SAX更優秀。
使用SAX時,我們知道XML事件是由解析器調用開發人員編寫的回調方法來處理的,也就是說應用程序是被動於解析器的。應用程序只能被動的等待解析器將XML事件推送給自己處理,對於每一種事件都需要在解析開始之前就做好准備。這種方式被稱為“推(push)”。而StAX正好相反,StAX采用一種“拉(pull)”的方式,由應用程序主動從解析器中獲取當前XML事件然后根據需求處理(保存或者忽略)。StAX使得應用程序掌握了主動權,可以簡化調用代碼來准確地處理它預期的內容,或者發生意外時停止解析。此外,由於該方法不基於處理程序回調,應用程序不需要像使用 SAX 那樣模擬解析器的狀態。
基於指針的API:
基於指針(Cursor)的 API 允許應用程序把 XML 作為一個標記(或事件)流來處理。在這里,解析器就像一跟指針一樣在文件流上前進,應用程序可以跟隨解析器從文件的開頭一直處理到結尾。這是一種低層 API,盡管效率高,但是沒有提供底層 XML 結構的抽象。Cursor API 由兩個主要API組成,XMLStreamReader和XMLStreamWriter,分別由XMLInputStreamFactory和XMLOutputStreamFactory獲取。
基於迭代器的API:
基於迭代器的API允許應用程序把 XML 作為一系列事件對象來處理,每個對象和應用程序交換 XML 結構的一部分。應用程序只需要確定解析事件的類型,將其轉換成對應的具體類型,然后利用其方法獲得屬於該事件的信息。基於事件迭代器的方法具有一個基於指針的方法不具備的重要優點。通過將解析器事件變成一級對象,從而讓應用程序可以采用面向對象的方式處理它們。這樣做有助於模塊化和不同應用程序組件之間的代碼重用。Iterator API 由兩個主要API組成,XMLEventReader和XMLEventWriter,分別由XMLInputStreamFactory和XMLOutputStreamFactory獲取。
測試代碼:
1 public class StAXTest { 2 private InputStream is; 3 4 @Before 5 public void setUp() throws Exception{ 6 is=StAXTest.class.getClassLoader() 7 .getResourceAsStream("books.xml"); 8 } 9 10 /** 11 * 基於指針的方式讀取xml文檔——XMLStreamReader 12 * @throws Exception 13 */ 14 @Test 15 public void testRetrieveByCursor() throws Exception{ 16 //創建讀取流工廠對象 17 XMLInputFactory factory = XMLInputFactory.newInstance(); 18 //創建基於指針的讀取流對象 19 XMLStreamReader streamReader = factory.createXMLStreamReader(is); 20 //用指針迭代 21 while(streamReader.hasNext()){ 22 //事件的ID 23 int eventId=streamReader.next(); 24 25 switch (eventId) { 26 case XMLStreamConstants.START_DOCUMENT: 27 System.out.println("start docmuent"); 28 break; 29 30 case XMLStreamConstants.START_ELEMENT: 31 System.out.println("<"+streamReader.getLocalName()+">"); 32 for(int i=0;i<streamReader.getAttributeCount();i++){ 33 System.out.println(streamReader.getAttributeLocalName(i)+ 34 "="+streamReader.getAttributeValue(i)); 35 } 36 break; 37 38 case XMLStreamConstants.CHARACTERS: 39 if(streamReader.isWhiteSpace()){ 40 break; 41 } 42 System.out.println(streamReader.getText()); 43 break; 44 case XMLStreamConstants.END_ELEMENT: 45 System.out.println("</"+streamReader.getLocalName()+">"); 46 47 break; 48 case XMLStreamConstants.END_DOCUMENT: 49 System.out.println("end docmuent"); 50 break; 51 default: 52 break; 53 } 54 } 55 } 56 57 /** 58 * 基於迭代器的方式讀取xml文檔——XMLEventReader 59 * @throws Exception 60 */ 61 @Test 62 public void testRetrieveByIterator() throws Exception{ 63 //創建讀取流工廠對象 64 XMLInputFactory factory = XMLInputFactory.newInstance(); 65 //創建基於迭代器(事件流對象)的流對象 66 XMLEventReader eventReader = factory.createXMLEventReader(is); 67 //迭代xml文檔 68 while (eventReader.hasNext()) { 69 //得到具體的 事件對象,就是引發事件的對象(可以是元素節點、文本節點、屬性節點) 70 XMLEvent event = eventReader.nextEvent(); 71 72 switch (event.getEventType()) { 73 case XMLStreamConstants.START_DOCUMENT: 74 System.out.println("start docmuent"); 75 break; 76 77 case XMLStreamConstants.START_ELEMENT: 78 //將事件對象可以轉換為元素節點對象 79 StartElement element = (StartElement) event; 80 System.out.println("<" + element.getName().getLocalPart() + ">"); 81 for (Iterator it = element.getAttributes(); it.hasNext();) { 82 Attribute attr = (Attribute) it.next(); 83 System.out.println(attr.getName().getLocalPart() + "=" + attr.getValue()); 84 } 85 break; 86 87 case XMLStreamConstants.CHARACTERS: 88 //將事件對象可以轉換成文本節點 89 Characters charData = (Characters) event; 90 if (charData.isIgnorableWhiteSpace() && charData.isWhiteSpace()) { 91 break; 92 } 93 System.out.println(charData.getData()); 94 break; 95 case XMLStreamConstants.END_ELEMENT: 96 //將事件對象可以轉換為元素節點對象 97 EndElement endElement = (EndElement) event; 98 System.out.println("</" + endElement.getName().getLocalPart() + ">"); 99 100 break; 101 case XMLStreamConstants.END_DOCUMENT: 102 System.out.println("end docmuent"); 103 break; 104 default: 105 break; 106 } 107 } 108 } 109 110 /** 111 * 基於指針的API輸出流——XMLStreamWriter 112 * @throws Exception 113 */ 114 @Test 115 public void testCreateByCursor() throws Exception{ 116 //創建輸出流對象工廠 117 XMLOutputFactory factory = XMLOutputFactory.newInstance(); 118 //創建輸出流對象 119 XMLStreamWriter streamWriter = factory.createXMLStreamWriter(System.out); 120 //創建xml文檔,根據對象方法創建對象元素 121 streamWriter.writeStartDocument(); 122 //book start 123 streamWriter.writeStartElement("book"); 124 streamWriter.writeAttribute("category", "CODING"); 125 126 streamWriter.writeStartElement("title"); 127 streamWriter.writeCharacters("Java Coding"); 128 streamWriter.writeEndElement(); 129 130 streamWriter.writeStartElement("author"); 131 streamWriter.writeCharacters("lisa"); 132 streamWriter.writeEndElement(); 133 134 streamWriter.writeStartElement("year"); 135 streamWriter.writeCharacters("2013"); 136 streamWriter.writeEndElement(); 137 138 streamWriter.writeStartElement("price"); 139 streamWriter.writeCharacters("79.9"); 140 streamWriter.writeEndElement(); 141 142 //book end 143 streamWriter.writeEndElement(); 144 145 streamWriter.writeEndDocument(); 146 streamWriter.flush(); 147 } 148 149 /** 150 * 基於迭代器的API輸出流——XMLEventWriter 151 * @throws Exception 152 */ 153 @Test 154 public void testCreateByIterator() throws Exception{ 155 //創建輸出流對象工廠 156 XMLOutputFactory factory = XMLOutputFactory.newInstance(); 157 //創建輸出流對象 158 XMLEventWriter eventWriter = factory.createXMLEventWriter(System.out); 159 //創建xml文檔,根據對象方法創建對象元素 160 eventWriter.add(new StartDocumentEvent()); 161 eventWriter.add(new StartElementEvent(new QName("book"))); 162 163 eventWriter.add(new StartElementEvent(new QName("title"))); 164 eventWriter.add(new CharacterEvent("Java Coding")); 165 eventWriter.add(new EndElementEvent(new QName("title"))); 166 167 eventWriter.add(new StartElementEvent(new QName("author"))); 168 eventWriter.add(new CharacterEvent("rilay")); 169 eventWriter.add(new EndElementEvent(new QName("author"))); 170 171 eventWriter.add(new StartElementEvent(new QName("year"))); 172 eventWriter.add(new CharacterEvent("2008")); 173 eventWriter.add(new EndElementEvent(new QName("year"))); 174 175 eventWriter.add(new StartElementEvent(new QName("price"))); 176 eventWriter.add(new CharacterEvent("29.9")); 177 eventWriter.add(new EndElementEvent(new QName("price"))); 178 179 eventWriter.add(new EndElementEvent(new QName("book"))); 180 eventWriter.add(new EndDocumentEvent()); 181 eventWriter.flush(); 182 } 183 184 }