stax解析xml
解析XML文档时, XMLEventReader
实例通过其next()
方法将事件对象传递给客户端应用程序-文档中每个语法单元一个。 但是,应用程序并不总是对接收所有事件类感兴趣。 仅查看XML元素及其属性的应用程序不关心表示注释或处理指令的事件。 幸运的是,StAX允许您通过实现事件过滤器来跳过某些事件类。
清单1显示了一个跳过所有XML处理指令的事件过滤器。 这些事件不会传递给事件读取器的hasNext()
, next()
或peek()
方法。 要将过滤器添加到给定的事件阅读器,必须构造一个新的阅读器。 这是通过工厂方法createFilteredReader()
。 此方法接受原始阅读器和EventFilter
作为参数。 然后,我将使用这个新的过滤后的事件阅读器来解析文档。
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 implementation
System.setProperty(
"javax.xml.stream.XMLInputFactory",
"com.bea.xml.stream.MXParserFactory");
// Create the XML input factory
XMLInputFactory 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 EventFilter() {
public boolean accept(XMLEvent event) {
// Exclude PIs
return (!event.isProcessingInstruction());
}
});
// Main event loop
while (filteredEventReader.hasNext()) {
XMLEvent e = filteredEventReader.next();
System.out.println(e);
}
}
}
您可以用相同的方式从主应用程序逻辑中隐藏其他事件类。 您甚至可以通过相互叠加构造经过过滤的事件读取器,以分层的方式组合多个EventFilter
。
在下一个示例中,我将显示一个跳过XML文档整个分支的过滤器。 这次,我将使用基于游标的API和经过筛选的流阅读器,而不是事件阅读器,因为我发现最好将复杂的筛选器实现为流筛选器。 与上面的示例类似,在基本流读取器的顶部构造了一个新的过滤流读取器:
// Create stream reader
XMLStreamReader xmlr =
xmlif.createXMLStreamReader(new FileReader("somefile.xml"));
// Create a filtered stream reader
XMLStreamReader xmlfr = xmlif.createFilteredReader(xmlr, filter);
清单3中显示了第二个参数中使用的StreamFilter
。 它作用于XML元素的开始和结束,并将各个元素的名称与路径段进行比较。 该路径指定应跳过文档的哪些部分,并以QName
数组的形式实现。 在此示例中,路径发票/项目中的所有元素都将被跳过。
在实现这样的过滤器时,您需要意识到以下事实:每当hasNext()
, next()
或peek()
方法时,都会调用过滤器的accept()
方法。 因此,对于同一事件,可以多次调用accept()
方法。 在这里,我确保过滤器逻辑对于每个事件仅执行一次; 仅当文档中的字符位置已更改时才执行此操作。
// 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 process = 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.getEventType()) {
case XMLStreamConstants.START_ELEMENT :
// Increment element depth
if (++depth < exclude.length && match == depth - 1) {
// Compare path segment with current element
if (reader.getName().equals(exclude[depth]))
// Equal - set segment pointer
match = depth;
}
// 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 (--depth < match)
// Update segment pointer
match = depth;
break;
}
}
return process;
}
};
本技巧说明了StAX解析器中过滤器的使用。 在下一个技巧中,我将展示如何使用这些技术和其他技术来有效地筛选XML文档。
翻译自: https://www.ibm.com/developerworks/xml/library/x-tipstx2/index.html
stax解析xml