Я написал тестовую Java-программу, которая использует StAX для перемещения по простому файлу input.xml
и возвращает фрагменты как DOM DocumentFragments
, а затем выводят в новый файл (output.xml
). Проблема, которую я получаю в более поздних версиях сервера, - это NullPointerException
для функции преобразования внутри моего кода. Понятия не имею почему.Невозможно преобразовать вход StAX в DOM DocumentFragment
Ошибка заключается в следующем:
java.lang.NullPointerException
at net.sf.saxon.dom.DOMWriter.characters(DOMWriter.java:218)
at net.sf.saxon.event.TreeReceiver.characters(TreeReceiver.java:277)
at net.sf.saxon.pull.PullPushTee.copyEvent(PullPushTee.java:117)
at net.sf.saxon.pull.PullPushTee.next(PullPushTee.java:72)
at net.sf.saxon.pull.PullConsumer.consume(PullConsumer.java:42)
at net.sf.saxon.pull.PullPushCopier.copy(PullPushCopier.java:44)
at net.sf.saxon.event.Sender.sendPullSource(Sender.java:542)
at net.sf.saxon.event.Sender.send(Sender.java:204)
at net.sf.saxon.jaxp.IdentityTransformer.transform(IdentityTransformer.java:366)
at XMLTest.getNextElement(XMLTest.java:66)
at XMLTest.main(XMLTest.java:45)
Код для моей тестовой программы в полном объеме (который можно скомпилировать) следующим образом (75 строк):
import java.io.*;
import java.nio.file.*;
import javax.xml.parsers.*;
import javax.xml.stream.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;
public class XMLTest {
static XMLStreamWriter writer;
static XMLStreamReader reader;
static Document doc;
static Transformer transformer;
//main method
public static void main(String[] args) {
System.out.println("XML Test");
System.out.println("========");
try {
//create reader
XMLInputFactory inFactory = XMLInputFactory.newInstance();
BufferedReader input = new BufferedReader(new InputStreamReader(Files.newInputStream(Paths.get("./input.xml"))));
reader = inFactory.createXMLStreamReader(input);
//create writer
XMLOutputFactory outFactory = XMLOutputFactory.newInstance();
BufferedWriter output = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(Paths.get("./output.xml"))));
writer = outFactory.createXMLStreamWriter(output);
writer.writeStartDocument();
writer.writeStartElement("documents");
writer.writeCharacters("\n");
//create document and transformer
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
//loop through input.xml
for (int i=0; i<3; i++) {
//call method to get <doc> element
DocumentFragment docElement = getNextElement("doc");
//transform retreived <doc> xmlfragment into output.xml
transformer.transform(new DOMSource(docElement), new StreamResult(output)); //USING STREAMRESULT AS StAXResult WILL IGNORE TRANSFORMER PROPERTY
System.out.println(docElement);
}
}
catch (Exception e) { e.printStackTrace(); }
}
//method to retreive a fragment of xml identified by the elementTag passed to it, e.g. getNextElement("doc") should return a DocumentFragment <doc>....</doc>
static DocumentFragment getNextElement(String elementTag) {
try {
DocumentFragment frag = doc.createDocumentFragment();
while (reader.hasNext()) {
if (reader.getEventType() == XMLStreamReader.START_ELEMENT && reader.getLocalName().equals(elementTag)) {
System.out.println("Found: " + elementTag);
transformer.transform(new StAXSource(reader), new DOMResult(frag));
return frag;
}
reader.next();
}
System.out.println("Returned empty fragment");
return frag;
}
catch (Exception e) { e.printStackTrace(); }
return null;
}
}
Мой образец input.xml
файл выглядит следующим образом:
<?xml version="1.0" ?>
<add>
<doc>
<field name="UID">0000001</field>
<field name="company">New York Corp</field>
<field name="datetime">2000-01-01T07:00:00Z</field>
<field name="title">Research Update</field>
<field name="url">www.green.com</field>
<field name="notice">example notice example notice</field>
</doc>
<doc>
<field name="UID">0000002</field>
<field name="company">London Limited</field>
<field name="datetime">2001-01-01T07:00:00Z</field>
<field name="title">Warning</field>
<field name="url">www.purple.com</field>
<field name="notice">test 123</field>
</doc>
<doc>
<field name="UID">0000003</field>
<field name="company">Tokyo PLC</field>
<field name="datetime">2004-01-01T07:00:00Z</field>
<field name="title">Results</field>
<field name="url">www.red.com</field>
<field name="notice">These reults</field>
</doc>
</add>
Кстати, результат отличается на разных mac Hines. В Debian Wheezy (7.8), используя java-версию «1.8.0_45», результат будет таким, как ожидалось. То есть, вход захватывается в куски и подается в выходной файл.
В Debian Jessie (8.5), используя java-версию «1.8.0_101», я получаю указанное выше исключение NullPointerException каждый раз, когда происходит итеративный перенос. Если я скомпилирую и запускаю на Java 1.8.0_45 на том же компьютере, он останется сломанным. Похоже, что это проблема Java, а не зависящая от ОС, учитывая тип ошибки. Но мои попытки отладки не дают мне никуда.
Я не нахожу это интуитивное а скорее загадочным. Кроме того, по внешнему виду это, кажется, анализирует весь документ в дереве DOM (с учетом ap.selectXPath (...)). Возможно, это не вариант больших данных. –