首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

使用 XML 流解析器

使用 XML 流解析器

XML 拉式解析器以其卓越的性能和低内存占用而闻名。但是由于功能有限,直到最近 XML 拉式解析器还仅限于特定的应用。StAX 改变了这一切,它是 Java Community Process JSR-173 ()的成果。随着规范进程进入最后阶段,各个厂商很快将推出用于实际应用的版本实现。      
使用 StAX对于多数应用程序员而言,与 Simple API for XML (SAX) 相比, StAX 将更加直观更容易使用。有两个 API 层 可供程序员选择:  
  • 方便的、容易使用的、迭代器风格的 API。
  • 快速的、基于底层指针的 API。
无论使用哪一种,客户应用程序都可以完全控制解析过程和维护事件循环。这是拉式解析器和推式解析器的主要区别,如 SAX 自行组织事件循环并通过回调通知客户应用程序。
使用迭代器风格的 API我们从迭代器风格的 API 开始。         XMLEventReader 实例通过         next() 方法提交         XMLEvent 类型的对象。通过调用适当的 API,您可以确定事件的类型和细节。或者可以使用 Java 语言的         instanceof 操作符确定具体的事件子类型。      
清单 1. 迭代 XML 事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.io.*;
import java.util.Iterator;
import javax.xml.namespace.QName;
import javax.xml.stream.*;
import javax.xml.stream.events.*;
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.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.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 = 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()) {
String text = ((Characters) e).getData();
}
if (e.isStartDocument()) {
String version = ((StartDocument) e).getVersion();
String encoding = ((StartDocument) e).getCharacterEncodingScheme();
boolean isStandAlone = ((StartDocument) e).isStandalone();
}
}
}




XML Information Set 的其他对象类型,如注解、处理指令或者实体,也可以类似地检测和处理。
使用基于指针的 API尽管迭代器风格的 API 非常方便和易于使用,它也带来了一些开销。解析器需要创建事件对象,这些对象在以后被无用单元收集器回收。对于高性能极其重要的应用程序,您可以选择基于指针的 API。         XMLStreamReader 类型的特点是         next() 方法提交一个整数值(而不是事件对象)表示事件类型。客户机应用程序可以查询阅读器获得其他的信息。      
清单 2. 基于指针的 XML 处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import java.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
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
* @param 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;
case XMLStreamConstants.SPACE :
case XMLStreamConstants.CHARACTERS :
int start = xmlr.getTextStart();
int length = xmlr.getTextLength();
String text =
new String(xmlr.getTextCharacters(), start, length);
break;
case XMLStreamConstants.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 = 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.getAttributeNamespace(index);
String localName = xmlr.getAttributeName(index);
String value = xmlr.getAttributeValue(index);
}
}




类似地,您也可以检测和处理其他事件类型,如         CDATA 、         ENTITY_REFERENCE 或         START_DOCUMENT 。根据我使用参考实现的体会,         XMLStreamReader 解析文档比         XMLEventReader 快大约 30%。      
下一步这篇技巧演示了使用 Streaming API for XML (StAX) 的两个不同层次解析 XML 文档。在以后的技巧中,我将介绍 StAX 在具体场景中的应用以及如何通过 StAX 创建 XML 文档。
返回列表