Как для потоковой передачи данных XML с использованием XOM? - PullRequest
4 голосов
/ 09 июня 2009

Скажем, я хочу вывести огромный набор результатов поиска в виде XML в PrintWriter или OutputStream, используя XOM . Полученный XML будет выглядеть так:

<?xml version="1.0" encoding="UTF-8"?>
<resultset>
    <result>
       [child elements and data]
    </result>
    ...
    ...
    [1000s of result elements more]
</resultset>

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

Степень детализации вывода одного <result> за один раз, поэтому я хочу сгенерировать один <result> за другим и записать его в поток. Другими словами, я просто хотел бы сделать что-то вроде этого псевдокода (автоматическая очистка включена, так что не беспокойтесь об этом):

open stream/writer
write declaration
write start tag for <resultset>
while more results:
    write next <result> element
write end tag for <resultset> 
close stream/writer

Я смотрел на Serializer, но необходимые методы writeStartTag(Element), writeEndTag(Element), write(DocType) защищены, а не общедоступны! Нет ли другого способа, кроме как создать подкласс Serializer, чтобы иметь возможность использовать эти методы, или вручную записать начальный и конечный теги непосредственно в поток как строки, минуя XOM вообще? (Последнее не было бы слишком плохо в этом простом примере, но в общем случае это было бы довольно уродливо.)

Я что-то упустил или XOM просто не предназначен для этого?

С dom4j Я мог бы легко это сделать, используя XMLWriter - у него есть конструкторы, которые принимают Writer или OutputStream, и методы writeOpen(Element), writeClose(Element) , writeDocType(DocumentType) и т. Д. Сравните с XOM Serializer, где единственный публичный write метод - это тот, который занимает целое Document.

(Это связано с моим вопросом о лучшей замене dom4j , где XOM является сильным соперником.)

Ответы [ 2 ]

7 голосов
/ 26 сентября 2009

Я столкнулся с той же проблемой, но обнаружил, что довольно просто сделать то, что вы упомянули в качестве опции, и подкласс Serializer следующим образом:

public class StreamSerializer extends Serializer {

    public StreamSerializer(OutputStream out) {
        super(out);
    }

    @Override
    public void write(Element element) throws IOException {
        super.write(element);
    }

    @Override
    public void writeXMLDeclaration() throws IOException {
        super.writeXMLDeclaration();
    }

    @Override
    public void writeEndTag(Element element) throws IOException {
        super.writeEndTag(element);
    }

    @Override
    public void writeStartTag(Element element) throws IOException {
        super.writeStartTag(element);
    }

}

Тогда вы по-прежнему можете использовать различные конфигурации XOM, такие как setIdent и т. Д., Но использовать их следующим образом:

Element rootElement = new Element("resultset");
StreamSerializer serializer = new StreamSerializer(out);
serializer.setIndent(4);
serializer.writeXMLDeclaration();
serializer.writeStartTag(rootElement);
while(hasNextElement()) {
    serializer.write(nextElement());
}
serializer.writeEndTag(rootElement);
serializer.flush();
5 голосов
/ 09 июня 2009

Насколько я знаю, XOM не поддерживает потоковую передачу напрямую.

Я использовал для потоковой передачи своих XML-документов NUX с потоковым XML-сериализатором, аналогичным стандартному классу Serializer в XOM. NUX совместим с XOM. Я скачал исходники NUX, извлек несколько классов NUX (интерфейс StreamingSerializer, StreamingXMLSerializer - который работает для документов XOM, StreamingVerifier и NamespacesInScope), поместил их в мой проект, и он работает как шарм. Жаль, что это не напрямую в XOM: - (

NUX - очень хороший компаньон для XOM: http://acs.lbl.gov/software/nux/, скачать рабочее зеркало: nux-1.6.tar.gz

Ссылка на API: http://acs.lbl.gov/software/nux/api/nux/xom/io/StreamingSerializer.html

Вот пример кода (методы вызываются по порядку: start(), n *nextResult(), finish(), сериализатор - StreamingXMLSerializer из NUX):

void start() {
    serializer.writeXMLDeclaration();

    Element root = new Element("response");
    root.addAttribute(new Attribute("found", Integer.toString(123)));
    root.addAttribute(new Attribute("count", Integer.toString(542)));

    serializer.writeStartTag(root);

    serializer.flush();
}

void nextResult(Result result) {
    Element element = result.createXMLRepresentation();
    serializer.write(element);
    serializer.flush();
}

void finish() {
    serializer.writeEndTag();
    serializer.flush();
}
...