Как для потоковой передачи данных XML с использованием XOM?
Скажем, я хочу вывести огромный набор результатов поиска в виде 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 ответа
Я столкнулся с той же проблемой, но обнаружил, что довольно просто сделать то, что вы упомянули в качестве опции и подкласс 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();
Насколько я знаю, XOM не поддерживает потоковую передачу напрямую.
То, что я использовал для потоковой передачи своих XML-документов, было NUX с потоковым XML Serializer, похожим на стандартный класс Serializer в XOM. NUX совместим с XOM. Я загрузил источники NUX, извлек несколько классов NUX (интерфейс StreamingSerializer, Streaming XML Serializer - который работает для документов 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()
, сериализатором является Streaming XML Serializer от 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();
}