Как объединить два XMLs в Java
Я пытаюсь объединить два xmls в Java. Я использую Stax API для написания этих XMLs. Я много искал в интернете о том, как объединить xmls, но никто не кажется таким прямым, как C#. Есть ли прямой способ сделать это в Java с помощью StAX? Вероятно, xslt не будет правильным решением, так как размер файла может быть большим.
File1.в XML
<TestCaseBlock>
<TestCase TestCaseID="1">
<Step ExecutionTime="2011-03-29 12:08:31 EST">
<Status>Passed</Status>
<Description>foo</Description>
<Expected>foo should pass</Expected>
<Actual>foo passed</Actual>
</Step>
</TestCase>
</TestCaseBlock>
File2.в XML
<TestCaseBlock>
<TestCase TestCaseID="2">
<Step ExecutionTime="2011-03-29 12:08:32 EST">
<Status>Failed</Status>
<Description>test something</Description>
<Expected>something expected</Expected>
<Actual>not as expected</Actual>
</Step>
</TestCase>
</TestCaseBlock>
слился.в XML
<TestCaseBlock>
<TestCase TestCaseID="1">
<Step ExecutionTime="2011-03-29 12:08:33 EST">
<Status>Passed</Status>
<Description>foo</Description>
<Expected>foo should pass</Expected>
<Actual>foo passed</Actual>
</Step>
</TestCase>
<TestCase TestCaseID="2">
<Step ExecutionTime="2011-03-29 12:08:34 EST">
<Status>Failed</Status>
<Description>test something</Description>
<Expected>something expected</Expected>
<Actual>not as expected</Actual>
</Step>
</TestCase>
</TestCaseBlock>
5 ответов
У меня есть решение, которое работает для меня. Теперь эксперты, пожалуйста, сообщите, если это путь.
спасибо, -Nilesh
XMLEventWriter eventWriter;
XMLEventFactory eventFactory;
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
eventWriter = outputFactory.createXMLEventWriter(new FileOutputStream("testMerge1.xml"));
eventFactory = XMLEventFactory.newInstance();
XMLEvent newLine = eventFactory.createDTD("\n");
// Create and write Start Tag
StartDocument startDocument = eventFactory.createStartDocument();
eventWriter.add(startDocument);
eventWriter.add(newLine);
StartElement configStartElement = eventFactory.createStartElement("","","TestCaseBlock");
eventWriter.add(configStartElement);
eventWriter.add(newLine);
String[] filenames = new String[]{"test1.xml", "test2.xml","test3.xml"};
for(String filename:filenames){
XMLEventReader test = inputFactory.createXMLEventReader(filename,
new FileInputStream(filename));
while(test.hasNext()){
XMLEvent event= test.nextEvent();
//avoiding start(<?xml version="1.0"?>) and end of the documents;
if (event.getEventType()!= XMLEvent.START_DOCUMENT && event.getEventType() != XMLEvent.END_DOCUMENT)
eventWriter.add(event);
eventWriter.add(newLine);
test.close();
}
eventWriter.add(eventFactory.createEndElement("", "", "TestCaseBlock"));
eventWriter.add(newLine);
eventWriter.add(eventFactory.createEndDocument());
eventWriter.close();
общим решением по-прежнему будет XSLT, но сначала вам нужно объединить два файла в один большой XML с элементом оболочки (XSLT работает с одним источником ввода).
<root>
<TestCaseBlock>
<TestCase TestCaseID="1">
...
</TestCase>
</TestCaseBlock>
<TestCaseBlock>
<TestCase TestCaseID="2">
...
</TestCase>
</TestCaseBlock>
</root>
затем просто сделайте XSLT для match= "/ / TestCase " и сбросьте все тестовые случаи, игнорируя, к какому блоку тестового случая они принадлежат.
и не беспокойтесь о производительности, пока не попытаетесь. XML-API в JAva становятся намного лучше, чем в 2003 году.
это шаблоны нужно:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<TestCaseBlock>
<xsl:apply-templates/>
</TestCaseBlock>
</xsl:template>
<xsl:template match="//TestCase">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
проверено, все работает.
кстати, этот XSLT был скомпилирован и выполнен на этом (небольшом) примере в 1ms.
Если структура достаточно регулярна, чтобы вы могли использовать привязку данных, я бы фактически рассмотрел привязку XML из обоих файлов в объекты с помощью JAXB, а затем слияние объектов, сериализацию обратно как XML. Если размеры файлов большие, вы также можете просто привязать под-деревья; для этого вы используете XMLStreamReader (от Stax api, javax.XML.stream) чтобы выполнить итерацию к элементу, который является корнем, свяжите этот элемент (и его дочерние элементы) с объектом, который вы хотите, выполните итерацию к следующему корневому элементу.
Регистрация XmlCombiner который является библиотекой Java, которая реализует слияние XML именно таким образом. Он основан на аналогичной функциональности, предоставляемой сплетение-utils библиотека.
в вашем случае теги также должны быть сопоставлены на основе значения атрибута 'TestCaseID'. Вот полный пример:
import org.atteo.xmlcombiner.XmlCombiner;
// create combiner
XmlCombiner combiner = new XmlCombiner("TestCaseID");
// combine files
combiner.combine(firstFile);
combiner.combine(secondFile);
// store the result
combiner.buildDocument(resultFile);
отказ от ответственности: я автор библиотеки.
Я думаю, что XSLT и SAX могут быть решением.
Если вы будете работать с потоком, который STaX является решением, я читаю Sun tutorial, я думаю, очень полезно: Sun Tutorail на STaX
тю