stax解析xml
解析XML文档时,XMLEventReader
实例通过其next()
方法将事件对象传递给客户端应用程序-文档中每个语法单元一个。 但是,应用程序并不总是对接收所有事件类感兴趣。 仅查看XML元素及其属性的应用程序不关心表示注释或处理指令的事件。 幸运的是,StAX允许您通过实现事件过滤器来跳过某些事件类。
清单1显示了一个跳过所有XML处理指令的事件过滤器。 这些事件不会传递给事件读取器的hasNext()
,next()
或peek()
方法。 要将过滤器添加到给定的事件阅读器,必须构造一个新的阅读器。 这是通过工厂方法createFilteredReader()
。 此方法接受原始阅读器和EventFilter
作为参数。 然后,我将使用这个新的过滤后的事件阅读器来解析文档。
清单1.过滤XML事件
import java.io.*;import javax.xml.stream.*;import javax.xml.stream.events.XMLEvent;public class ParseFilteredByEvent {public static void main(String[] args)throws FileNotFoundException, XMLStreamException {// Use reference implementationSystem.setProperty("javax.xml.stream.XMLInputFactory","com.bea.xml.stream.MXParserFactory");// Create the XML input factoryXMLInputFactory factory = XMLInputFactory.newInstance();// Create event readerFileReader reader = new FileReader("somefile.xml");XMLEventReader eventReader = factory.createXMLEventReader(reader);// Create a filtered readerXMLEventReader filteredEventReader =factory.createFilteredReader(eventReader, new EventFilter() {public boolean accept(XMLEvent event) {// Exclude PIsreturn (!event.isProcessingInstruction());}});// Main event loopwhile (filteredEventReader.hasNext()) {XMLEvent e = filteredEventReader.next();System.out.println(e);}}}
您可以用相同的方式从主应用程序逻辑中隐藏其他事件类。 您甚至可以通过相互叠加构造经过过滤的事件读取器,以分层的方式组合多个EventFilter
。
隐藏文档分支
在下一个示例中,我将显示一个跳过XML文档整个分支的过滤器。 这次,我将使用基于游标的API和经过筛选的流阅读器,而不是事件阅读器,因为我发现最好将复杂的筛选器实现为流筛选器。 与上面的示例类似,在基本流读取器的顶部构造了一个新的过滤流读取器:
清单2.创建一个过滤的流阅读器
// Create stream readerXMLStreamReader xmlr =xmlif.createXMLStreamReader(new FileReader("somefile.xml"));// Create a filtered stream readerXMLStreamReader xmlfr = xmlif.createFilteredReader(xmlr, filter);
清单3中显示了第二个参数中使用的StreamFilter
。 它作用于XML元素的开始和结束,并将各个元素的名称与路径段进行比较。 该路径指定应跳过文档的哪些部分,并以QName
数组的形式实现。 在此示例中,路径发票/项目中的所有元素都将被跳过。
在实现这样的过滤器时,您需要意识到以下事实:每当hasNext()
,next()
或peek()
方法时,都会调用过滤器的accept()
方法。 因此,对于同一事件,可以多次调用accept()
方法。 在这里,我确保过滤器逻辑对于每个事件仅执行一次; 仅当文档中的字符位置已更改时才执行此操作。
清单3.流过滤器
// Exclusion pathprivate static QName[] exclude = new QName[] { new QName("invoice"), new QName("item")};private static StreamFilter filter = new StreamFilter() {// Element levelint depth = -1;// Last matching path segmentint match = -1;// Filter resultboolean process = true;// Character position in documentint currentPos = -1;public boolean accept(XMLStreamReader reader) {// Get character positionLocation loc = reader.getLocation();int pos = loc.getCharacterOffset();// Inhibit double executionif (pos != currentPos) {currentPos = pos;switch (reader.getEventType()) {case XMLStreamConstants.START_ELEMENT :// Increment element depthif (++depth < exclude.length && match == depth - 1) {// Compare path segment with current elementif (reader.getName().equals(exclude[depth]))// Equal - set segment pointermatch = depth;}// Process all elements not in pathprocess = match < exclude.length - 1;break;// End of XML elementcase XMLStreamConstants.END_ELEMENT :// Process all elements not in pathprocess = match < exclude.length - 1;// Decrement element depthif (--depth < match)// Update segment pointermatch = depth;break;}}return process;}};
下一步
本技巧说明了StAX解析器中过滤器的使用。 在下一个技巧中,我将展示如何使用这些技术和其他技术来有效地筛选XML文档。
翻译自: /developerworks/xml/library/x-tipstx2/index.html
stax解析xml