(五)使用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 }