平时我们用解析Xml 文档有几种常用的方法SAX 的event 方式, DOM 的方式。 这个SAX 是基于事件模式效率性能方面还是不错的, 最大的缺陷是作为事件方式客户端没有太大控制权都是被回调EventHandler;
DOM 的方式在处理小XML文件的时候是很方便的可以方便的读写, 最大的问题是内存cpu 的资源占用方面太夸张了。 动不动outofmessage 实在是伤不起。
现在由于有需求不想采用SAX 事件方式, 我想的是在client 端有最大的控制权限,采用跟BufferReader 的方式readline类似的接口 比如 提供 hasNext(), getNext() 去获取一个XML 元素。 这个元素是基于XPath来指定。 通过反复的google,找到点线索, 在2004年 通过了一个 JSR 173 关于StAX 的东东。 The primary goal of the StAX API is to give "parsing control to the programmer by exposing a simple iterator based API. 这个不就是俺想要的东东么。
我们可以通过StAX 提供的几个接口来遍历xml stream 有两个接口可以干这个事情:
XMLStreamReader
XMLEventReader
比如XMLStreamReader 的用法可以如下:
XMLInputFactory f = XMLInputFactory.newInstance();
XMLStreamReader r = f.createXMLStreamReader( ... );
while(r.hasNext()) {
r.next();
}
XMLEventReader 的用法
while(stream.hasNext()) {
XMLEvent event = stream.nextEvent();
System.out.print(event);
}
我们可以通过这种方式来遍历xml 文档, 通过返回的XMLEvent 来决定是否StartElement ,EndElement 来决定当前的Element 是否我们想要的。 下面是我写的一个XMLMessageSource 类
1, 它接受 fileName xml 文档
2, path XPath 我们需要的元素的XPath
它实现了 hasNext, getNextMessage 方法来访问下一个满足条件的Element 的String 内容
package com.bwang.messagefeeder.messagesource;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
@SuppressWarnings("restriction")
public class XmlMessageSource implements IMessageSource {
private static final Logger LOGGER = Logger
.getLogger(XmlMessageSource.class);
private final String fileName;
private final String xmlPathPattern;
private final String[] patternArray;
private XMLEventReader eventReader;
private final Stack<String> elementNames;
public XmlMessageSource(FileEntry fileEntry, String xmlPathPattern) {
this.fileName = fileEntry.getFileName();
this.xmlPathPattern = xmlPathPattern;
patternArray = makePatternArray();
if (patternArray == null || patternArray.length ==0) {
throw new RuntimeException("pattern is not set");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(patternArray);
}
elementNames = new Stack<String>();
try {
XMLInputFactory xif = XMLInputFactory.newInstance();
eventReader = xif.createXMLEventReader(new FileReader(this.fileName));
} catch (Exception e) {
LOGGER.error("fail to create event reader", e);
}
}
private String[] makePatternArray() {
String[] tempArray = this.xmlPathPattern.split("/");
List<String> patternStrings = new ArrayList<String>();
for (int i=0; i< tempArray.length; i++) {
if (!StringUtils.isEmpty(tempArray[i])) {
patternStrings.add(tempArray[i]);
}
}
return patternStrings.toArray(new String[0]);
}
public boolean hasNext() {
try {
while (eventReader.hasNext()) {
XMLEvent xmlEvent = eventReader.peek();
if (xmlEvent.isStartElement()) {
StartElement elem = xmlEvent.asStartElement();
String name = elem.getName().getLocalPart();
elementNames.push(name);
}
if (match()) {
elementNames.pop();
return true;
}
else if (xmlEvent.isEndElement()) {
elementNames.pop();
}
xmlEvent = eventReader.nextEvent();
}
} catch (Exception e) {
}
return false;
}
private boolean match() {
if (elementNames.size() != patternArray.length) {
return false;
}
for(int i=0; i< elementNames.size(); i++) {
if (!elementNames.get(i).equalsIgnoreCase(patternArray[i])) {
return false;
}
}
return true;
}
public String getNextMessage() {
try {
return readElementBody(eventReader);
} catch (Exception e) {
LOGGER.error("fail to get message", e);
return null;
}
}
public static String readElementBody(XMLEventReader eventReader)
throws XMLStreamException {
StringWriter buf = new StringWriter(1024);
int depth = 0;
do {
// peek event
XMLEvent xmlEvent = eventReader.peek();
if (xmlEvent.isStartElement()) {
++depth;
} else if (xmlEvent.isEndElement()) {
--depth;
}
// consume event
xmlEvent = eventReader.nextEvent();
// print out event
xmlEvent.writeAsEncodedUnicode(buf);
} while (depth > 0 && eventReader.hasNext());
return buf.getBuffer().toString();
}
public void dispose() {
if (eventReader != null) {
try {
eventReader.close();
}catch(XMLStreamException e) {
}
}
}
}
hasNext 会将eventReader 的游标停留在满足条件的Element 的StartElement 处。
调用方法是:
IMessageSource ms = new XmlMessageSource(new fileentry(), "/DOCS/Message");
while(ms.hasNext()) {
System.out.println(ms.getNextMessage());
}
ms.dispose();
通过一个大约200多M 的测试文档结构N轮的测试下来
SAX Event 方式 大约 240 秒
这个实现 大约 20秒钟不到。
DOM 实现就表提了,直接内存爆掉。
终于找到一种性能秒杀SAX 的实现, 比较这个实现在测试的过程中内存占用文档在 30M 不到。
分享到:
相关推荐
总的来说,使用Pull解析器读取和生成XML文件是一种高效且灵活的方法,尤其适合处理大型XML文档。通过掌握这一技术,开发者可以更好地处理XML数据,提高程序的性能和稳定性。在进行XML操作时,还需注意数据的正确性和...
标题中的“pull parser”是DOM4J支持的一种解析XML文档的方式,即拉式解析器(Pull Parsing)。Pull Parsing是一种事件驱动的解析模型,允许开发人员按需处理XML事件,而不是一次性加载整个文档到内存中,这在处理...
3. **解析XML**:你可以通过`Element`接口来访问XML文档的元素。例如,获取根元素: ```java Element rootElement = document.getRootElement(); ``` 然后,可以遍历元素的子元素,或者查找特定的元素: ```java ...
在 Android 中,DOM 解析同样适用,但需要注意的是,由于 Android 的内存限制,通常推荐使用更轻量级的解析器,如 SAX 或者 Android 提供的 PullParser。然而,对于小型 XML 文件,DOM 仍然是一个可行的选择。 在 ...
Java中的XML解析技术主要包括DOM(Document Object Model)、...Pull Parser进一步简化了StAX的使用,让XML解析更加直观。在选择XML解析技术时,应根据具体应用需求,如内存限制、解析速度和代码复杂性等因素进行权衡。
它支持XPath表达式,可以方便地查找和操作XML节点,还支持SAX和StAX解析器,适用于处理大型XML文档,避免内存消耗过大。例如,你可以使用`Document document = DocumentHelper.parseText(xmlString)`来解析XML文本,...
此“parserXML.7z”压缩包可能包含一系列与解析XML相关的资源、代码示例或教程,帮助开发者了解如何在Android平台上处理XML数据。 XML解析在Android中的重要性在于,它允许应用程序从XML文件或网络服务中提取数据,...
1. **DOM解析**:Document Object Model (DOM) 提供了一种将整个XML文档加载到内存并创建树形结构的方法。你可以通过遍历这棵树来访问任何节点。这种方法适合小规模的XML文件,因为内存消耗大,不适合大型文件。 2....
SAX是一种事件驱动的解析器,它以流式的方式读取XML文档,逐个处理元素、属性等信息。SAX解析器适用于处理大型XML文件,因为它占用内存较少,不会一次性加载整个文档到内存中。在Android中,可以使用`org.xml.sax`...
Android提供了一种高效且轻量级的解析XML的方式,即Pull解析(PullParser)。本篇文章将详细介绍如何在Android中使用Pull解析器来解析XML文件。 首先,我们需要理解XML Pull解析的工作原理。与SAX解析器类似,Pull...
1. **DOM解析**:DOM(Document Object Model)是将XML文档转换为树形结构的一种方法,允许开发者通过节点操作访问和修改XML数据。它的优点是方便处理整个文档,但缺点是内存消耗大,对于大型XML文件可能导致性能...
4. Pull ParserPull Parser(也称为 StAX,Streaming API for XML)是一种基于拉取(pull-based)的解析器,它允许应用程序按需请求解析事件,而不是等待解析器推送事件。这种方式更加灵活,内存占用少,适用于处理...
Pull parser或STAX是另外一种技术,其对XML处理的API不再使用SAX一样使人不舒服的事件响应机制,可以按次序访问XML文档,这也是称之为Pull的原因。其基本思想和SAX类似,也不在内存中形成XML映像。这使得其特别适用...
Pull解析器是一种事件驱动的解析方式,它不会一次性加载整个XML文档到内存,而是逐行或逐事件处理,这样既节省内存,又提高了效率。使用步骤如下: 1. **初始化解析器**:通过`XmlPullParserFactory`创建一个`...
Stax2 API是标准 API(“用于Xml处理的STandard Api”)的扩展,它是JDK 6中添加的JDK的pull-parser API。 地位 支持 Stax2 API通过以下Stax XML实现来本地实现: (面向性能,也是非阻塞/异步的) (Java平台上...
为了更好地处理XML文件,Java提供了多种解析技术,包括DOM (Document Object Model),SAX (Simple API for XML),StAX (Streaming API for XML) 和Pull Parser等。本文主要探讨四种主流的XML解析方法:DOM,SAX,...
Pull based(pull模式),OM基于StAX--标准的pull parser API 。 pull模式 Axiom采用pull解析方式,基于StAX(JSR173)。 SAX和DOM 都是基于push的解析方式,也就是说解析控制在parser本身。 Axiom和StAX紧密...
3. **XPP3**: XPP3(XML Pull Parser Version 3)是一个轻量级的XML解析器,适用于内存有限的环境。Spring可能使用它来解析XML输入流,尤其是在移动或嵌入式设备上运行的应用程序。 4. **JFree**: JFree库,尤其是...
DOM4J-1.6是一款在Java环境中广泛使用的XML处理库,它提供了一种高效、灵活的方式来操作XML文档,包括读取、写入、修改以及遍历XML结构。DOM4J不仅实现了DOM API,还引入了强大的SAX和StAX支持,使其在处理大型XML...
它允许开发者以拉(pull)的方式处理XML,即在解析过程中,开发者可以按需获取XML文档的事件(如开始元素、结束元素、文本等)。这种方式对内存使用友好,适用于资源有限的环境或者需要高效处理大型XML文档的情况。 ...