我需要处理一个巨大的XML文件4G。我使用了dom4j SAX,但编写了自己的DefaultElementHandler。代码框架如下:
SAXParserFactory sf = SAXParserFactory.newInstance();
SAXParser sax = sf.newSAXParser();
sax.parse("english.xml", new DefaultElementHandler("page"){
public void processElement(Element element) {
// process the element
}
});
我以为我正在通过“页面”处理巨大的文件“页面”。但似乎没有,因为我总是有内存错误。我错过了什么重要的事吗?谢谢。我是XML进程的新手。
答案 0 :(得分:0)
你没有真正按页面处理XML,但是如果扩展XMLFilterImpl而不是使用DefaultElementHandler(无论是什么),那么你可以简单地处理XML元素。您将流式传输,因此当整个文档在内存中时(例如,实际问题)将不会出现这种情况。
你将基本上在元素的开头,属性,文本内部,然后在元素的末尾调用event元素(查看ContentHandler接口中的方法)。根据这些调用,你可以进行处理(你可能需要有一些数据结构来累积你的“page”元素中的元素。另请注意,不能保证你只能获得一次文本调用(它是直到解析器)。
这有助于使其更清晰吗?
答案 1 :(得分:0)
我认为它只读取了元素中的所有内容,因为我只是在网上跟踪了一个例子......
公共抽象类DefaultElementHandler扩展DefaultHandler { private boolean begin; private String tagName; private StringBuilder sBuilder;
public DefaultElementHandler(String tagName) {
this.tagName = tagName;
this.begin = false;
this.sBuilder = new StringBuilder();
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals(tagName)||begin){
sBuilder.append("<");
sBuilder.append(qName);
sBuilder.append(" ");
int attrCount = attributes.getLength();
for (int i=0; i<attrCount; i++) {
sBuilder.append(attributes.getQName(i));
sBuilder.append("=\"");
sBuilder.append(attributes.getValue(i));
sBuilder.append("\" ");
}
sBuilder.append(">");
begin = true;
}
}
public void characters(char[] ch, int start, int length) throws SAXException{
StringBuilder sb = new StringBuilder();
for(int i=0; i < length; i++) {
sb.append(convertSpecialChar(ch[start+i]));
}
String text = sb.toString().trim();
//String text = new String(convertSpecialChar(ch), start, length);
if (text.trim().equals("")) return;
if (begin) sBuilder.append(text);
}
public void endElement(String uri, String localName, String qName) throws SAXException {
String stag = "</" + tagName + ">";
String ntag = "</" + qName + ">";
if (stag.equals(ntag) || begin) {
sBuilder.append(ntag);
if (stag.equals(ntag)) {
begin = false;
try {
Document doc = DocumentHelper.parseText(sBuilder.toString());
Element element = doc.getRootElement();
this.processElement(element);
} catch (DocumentException e) {
e.printStackTrace();
System.exit(1);
}
sBuilder.setLength(0);
}
}
}
答案 2 :(得分:0)
您的DefaultElement实现看起来很困惑。看起来所有东西都堆积在sBuilder中,它永远不会被清除,直到找到根元素的结尾,或者更可能是内存耗尽。
如何读取元素文本取决于您需要解析的xml类型。每个元素都可以包含文本,并且可以穿插子元素。通常,您会在Web服务和配置文件中看到一种xml,其中所有元素文本都在叶元素中,然后有一些情况,比如XHTML,其中散布的东西正在进行中。
如果xml架构的工作方式是所有文本信息都在叶元素中,那么您可以缓冲从startElement开始的文本,并使用endElement中的累积文本,然后清除缓冲区。 / p>
这是一篇关于SAX的好文章:http://www.javaworld.com/javaworld/jw-08-2000/jw-0804-sax.html