Огромный XML-файл: я читаю «страницу» и обрабатываю ее каждый раз? - PullRequest
1 голос
/ 16 декабря 2009

Мне нужно обработать огромный 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
}
});    

Я думал, что обрабатываю огромный файл "page" с помощью "page". Но, похоже, нет, так как у меня всегда была ошибка памяти. Я что-то упустил? Благодарю. Я новичок в процессе XML.

Ответы [ 3 ]

0 голосов
/ 16 декабря 2009

Я думаю, что он читает только все содержимое элемента, как я только что последовал примеру онлайн ...

открытый абстрактный класс DefaultElementHandler extends DefaultHandler { частное логическое начало; приватное String tagName; приватный 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);   
        }   
    }   
}
0 голосов
/ 16 декабря 2009

Ваша реализация DefaultElement выглядит для меня запутанной. Похоже, что все накапливается в sBuilder и никогда не очищается до тех пор, пока не найдет конец корневого элемента или, скорее, не хватит памяти.

Способ чтения текста элемента зависит от того, какой тип xml вам нужно проанализировать. Каждый элемент может иметь текст, и его можно перемежать с дочерними элементами. Как правило, существует вид xml, который вы видите в веб-сервисах и файлах конфигурации, где весь текст элемента находится в конечных элементах, а в некоторых случаях, например XHTML, происходит перемежающаяся вещь.

Если схема вашего xml работает так, что вся текстовая информация находится в конечных элементах, вы можете буферизовать текст, который вы получаете, начиная с startElement, и использовать накопленный текст в endElement, а затем очистить буфер.

Вот хорошая статья о SAX: http://www.javaworld.com/javaworld/jw-08-2000/jw-0804-sax.html

0 голосов
/ 16 декабря 2009

Ну, на самом деле вы не обрабатываете XML страницей, однако если вы расширяете XMLFilterImpl вместо использования DefaultElementHandler (что бы это ни было), вы можете просто обрабатывать элементы XML по мере их поступления. Вы будете осуществлять потоковую передачу, поэтому не будет никакого случая, когда весь документ находится в памяти (на практике).

По сути, вас вызовут для элемента события, в начале элемента, для атрибутов, для текста внутри, а затем в конце элемента (посмотрите на методы в интерфейсе ContentHandler). Основываясь на этих вызовах, вы выполняете свою обработку (вам, вероятно, потребуются некоторые структуры данных, в которых вы накапливаете элементы внутри элемента "page". Также обратите внимание, что нет гарантии, что вы получите только один вызов для текста (это до парсера).

Помогает ли это сделать это более понятным?

...