《2022年使用StAX部分解析XML文档整理 .pdf》由会员分享,可在线阅读,更多相关《2022年使用StAX部分解析XML文档整理 .pdf(6页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、使用 StAX 部分解析XML 文档上一篇技巧中介绍的Streaming API for XML(StAX ), 不仅提供了一个快捷、易用、占用内存少的XML 解析器,它还提供了过滤器接口,允许程序员向应用程序业务逻辑隐藏不需要的文档细节,这篇技巧介绍如何将事件过滤器和流过滤器用于StAX 解析器。和第一篇技巧一样, 我将同时使用迭代器风格的API 和基于指针的API 进行说明和介绍。解析 XML 文档时,XMLEventReader实例通过它的next()方法向客户传递事件对象,文档中的每个语法单位都有一个事件。但是,应用程序不一定愿意接受所有的事件类;只查看XML 元素及其属性的应用程序并
2、不关心代表注释和处理指令的事件。幸运的是,StAX 允许您通过实现事件过滤器忽略某些事件类。清单 1 给出了一个忽略所有XML 处理指令的事件过滤器。这些事件没有传递给事件阅读器的hasNext()、 next()或 peek()方法。向给定的事件阅读器增加过滤器,必须构造一个新的阅读器,可以通过工厂方法createFilteredReader()完成。该方法接收原来的阅读器和EventFilter作为参数。接下来我使用这个新的事件过滤阅读器解析文档。import java.io.*; import javax.xml.stream.*; import javax.xml.stream.eve
3、nts.XMLEvent; public class ParseFilteredByEvent public static void main(String args) throws FileNotFoundException, XMLStreamException / Use reference implementation System.setProperty( javax.xml.stream.XMLInputFactory, com.bea.xml.stream.MXParserFactory); / Create the XML input factory XMLInputFacto
4、ry factory = XMLInputFactory.newInstance(); / Create event reader FileReader reader = new FileReader(somefile.xml); XMLEventReader eventReader = factory.createXMLEventReader(reader); / Create a filtered reader XMLEventReader filteredEventReader = factory.createFilteredReader(eventReader, new EventFi
5、lter() public boolean accept(XMLEvent event) / Exclude PIs return (!event.isProcessingInstruction(); ); / Main event loop while (filteredEventReader.hasNext() XMLEvent e = filteredEventReader.next(); System.out.println(e); 隐藏文档分支名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - -
6、 - - - 第 1 页,共 6 页 - - - - - - - - - 在下面的例子中,我要介绍的过滤器能够忽略XML 文档的整个分支。这一次我使用基于指针的API 和流过滤阅读器而不是事件阅读器,因为我发现复杂的过滤器最好用流过滤器实现。与上面的例子类似,新的流过滤阅读器建立在基本流阅读器的基础上:清单2. 创建流过滤阅读器/ Create stream reader XMLStreamReader xmlr = xmlif.createXMLStreamReader(new FileReader(somefile.xml); / Create a filtered stream read
7、er XMLStreamReader xmlfr = xmlif.createFilteredReader(xmlr, filter); 其中第二个参数所用的StreamFilter由 清单 3 给出。在XML 元素开始和结束的时候,它把相应的元素名和一个路径片段进行比较。路径作为一个QName 数组实现,指定应该忽略文档的哪些部分。在这个例子中,路径invoice/item 中的所有元素将被忽略。实现这种过滤器必须要知道,每次激活hasNext()、 next()或 peek()方法时都会调用过滤器的accept()方法。因此,同一个事件可能多次调用accept()方法。在这里,我保证对每个
8、事件过滤逻辑只执行一次,只有当文档中的字符位置发生变化时才会执行。清单3. 流过滤器/ Exclusion path private static QName exclude = new QName new QName(invoice), new QName(item); private static StreamFilter filter = new StreamFilter() / Element level int depth = -1; / Last matching path segment int match = -1; / Filter result boolean proces
9、s = true; / Character position in document int currentPos = -1; public boolean accept(XMLStreamReader reader) / Get character position Location loc = reader.getLocation(); int pos = loc.getCharacterOffset(); / Inhibit double execution if (pos != currentPos) currentPos = pos; switch (reader.getEventT
10、ype() case XMLStreamConstants.START_ELEMENT : / Increment element depth if (+depth exclude.length & match = depth - 1) / Compare path segment with current element if (reader.getName().equals(excludedepth) / Equal - set segment pointer match = depth; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - -
11、 - - - 名师精心整理 - - - - - - - 第 2 页,共 6 页 - - - - - - - - - / Process all elements not in path process = match exclude.length - 1; break; / End of XML element case XMLStreamConstants.END_ELEMENT : / Process all elements not in path process = match exclude.length - 1; / Decrement element depth if (-dep
12、th match) / Update segment pointer match = depth; break; return process; ; 使用 XML 流解析器这篇技巧展示了如何利用与规范一起部署的StAX 参考实现,有效地使用Streaming API for XML (StAX) 解析 XML 文档。 Berthold Daum 解释了StAX 中可用的两个API 层:迭代器风格的API 和基于指针的 API。XML 拉式解析器以其卓越的性能和低内存占用而闻名。但是由于功能有限, 直到最近XML 拉式解析器还仅限于特定的应用。StAX 改变了这一切,它是Java Communi
13、ty Process JSR-173 (请参阅参考资料 )的成果。随着规范进程进入最后阶段,各个厂商很快将推出用于实际应用的版本实现。使用StAX对于多数应用程序员而言,与Simple API for XML (SAX) 相比,StAX 将更加直观更容易使用。有两个API 层 可供程序员选择:方便的、容易使用的、迭代器风格的API 。快速的、基于底层指针的API。无论使用哪一种,客户应用程序都可以完全控制解析过程和维护事件循环。这是拉式解析器和推式解析器的主要区别,如SAX 自行组织事件循环并通过回调通知客户应用程序。使用迭代器风格的API我们从迭代器风格的API 开始。 XMLEventRe
14、ader实例通过next()方法提交XMLEvent类型的对象。通过调用适当的API,您可以确定事件的类型和细节。或者可以使用Java 语言的instanceof操作符确定具体的事件子类型。清单1. 迭代XML 事件import java.io.*; import java.util.Iterator; import javax.xml.namespace.QName; import javax.xml.stream.*; import javax.xml.stream.events.*; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - -
15、 - - 名师精心整理 - - - - - - - 第 3 页,共 6 页 - - - - - - - - - public class ParseByEvent public static void main(String args) throws FileNotFoundException, XMLStreamException / Use the reference implementation for the XML input factory System.setProperty(javax.xml.stream.XMLInputFactory, com.bea.xml.stream
16、.MXParserFactory); / Create the XML input factory XMLInputFactory factory = XMLInputFactory.newInstance(); / Create the XML event reader FileReader reader = new FileReader(somefile.xml); XMLEventReader r = factory.createXMLEventReader(reader); / Loop over XML input stream and process events while(r.
17、hasNext() XMLEvent e = r.next(); processEvent(e); /* * Process a single XML event * param e - the event to be processed */ private static void processEvent(XMLEvent e) if (e.isStartElement() QName qname = (StartElement) e).getName(); String namespaceURI = qname.getNamespaceURI(); String localName =
18、qname.getLocalPart(); Iterator iter = (StartElement) e).getAttributes(); while (iter.hasNext() Attribute attr = (Attribute) iter.next(); QName attributeName = attr.getName(); String attributeValue = attr.getValue(); if (e.isEndElement() QName qname = (EndElement) e).getName(); if (e.isCharacters() S
19、tring text = (Characters) e).getData(); if (e.isStartDocument() String version = (StartDocument) e).getVersion(); String encoding = (StartDocument) e).getCharacterEncodingScheme(); boolean isStandAlone = (StartDocument) e).isStandalone(); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心
20、整理 - - - - - - - 第 4 页,共 6 页 - - - - - - - - - XML Information Set 的其他对象类型,如注解、处理指令或者实体,也可以类似地检测和处理。使用基于指针的API尽管迭代器风格的API 非常方便和易于使用,它也带来了一些开销。解析器需要创建事件对象,这些对象在以后被无用单元收集器回收。对于高性能极其重要的应用程序,您可以选择基于指针的API 。XMLStreamReader类型的特点是next()方法提交一个整数值(而不是事件对象)表示事件类型。客户机应用程序可以查询阅读器获得其他的信息。清单2. 基于指针的XML 处理import j
21、ava.io.*; import javax.xml.stream.*; public class ParseByIterator public static void main(String args) throws FileNotFoundException, XMLStreamException / Use reference implementation System.setProperty( javax.xml.stream.XMLInputFactory, com.bea.xml.stream.MXParserFactory); / Create an input factory
22、XMLInputFactory xmlif = XMLInputFactory.newInstance(); / Create an XML stream reader XMLStreamReader xmlr = xmlif.createXMLStreamReader(new FileReader(somefile.xml); / Loop over XML input stream and process events while (xmlr.hasNext() processEvent(xmlr); xmlr.next(); /* * Process a single event * p
23、aram xmlr - the XML stream reader */ private static void processEvent(XMLStreamReader xmlr) switch (xmlr.getEventType() case XMLStreamConstants.START_ELEMENT : processName(xmlr); processAttributes(xmlr); break; case XMLStreamConstants.END_ELEMENT : processName(xmlr); break; 名师资料总结 - - -精品资料欢迎下载 - -
24、- - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 6 页 - - - - - - - - - case XMLStreamConstants.SPACE : case XMLStreamConstants.CHARACTERS : int start = xmlr.getTextStart(); int length = xmlr.getTextLength(); String text = new String(xmlr.getTextCharacters(), start, length); break; case X
25、MLStreamConstants.COMMENT : case XMLStreamConstants.PROCESSING_INSTRUCTION : if (xmlr.hasText() String piOrComment = xmlr.getText(); break; private static void processName(XMLStreamReader xmlr) if (xmlr.hasName() String prefix = xmlr.getPrefix(); String uri = xmlr.getNamespaceURI(); String localName
26、 = xmlr.getLocalName(); private static void processAttributes(XMLStreamReader xmlr) for (int i = 0; i xmlr.getAttributeCount(); i+) processAttribute(xmlr, i); private static void processAttribute(XMLStreamReader xmlr, int index) String prefix = xmlr.getAttributePrefix(index); String namespace = xmlr
27、.getAttributeNamespace(index); String localName = xmlr.getAttributeName(index); String value = xmlr.getAttributeValue(index); 类似地,您也可以检测和处理其他事件类型,如 CDATA 、ENTITY_REFERENCE或 START_DOCUMENT 。根据我使用参考实现的体会,XMLStreamReader解析文档比XMLEventReader快大约30%。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 6 页 - - - - - - - - -