巨大的XML文件:我是否每次都阅读“页面”并进行处理?

时间:2009-12-16 09:54:45

标签: java xml sax

我需要处理一个巨大的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进程的新手。

3 个答案:

答案 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