I want to merge 2 XML files with the same structure to make one. For example;
Test1.xml
<?xml version="1.0" encoding="UTF-8"?>
<ns:Root
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns="urn:TestNamespace"
xsi:schemaLocation="urn:Test.Namespace Test1.xsd"
>
<ns:element1 id="001">
<ns:element2 id="001.1" order="1">
<ns:element3 id="001.1.1" />
</ns:element2>
<ns:element2 id="001.2" order="2">
<ns:element3 id="001.1.2" />
</ns:element2>
</ns:element1>
</ns:Root>
and Test2.xml
<?xml version="1.0" encoding="UTF-8"?>
<ns:Root
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns="urn:TestNamespace"
xsi:schemaLocation="urn:Test.Namespace Test1.xsd"
>
<ns:element1 id="999">
<ns:element2 id="999.1" order="1">
<ns:element3 id="999.1.1" />
</ns:element2>
</ns:element1>
</ns:Root>
To create
TestOutput.xml
<?xml version="1.0" encoding="UTF-8"?>
<ns:Root
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns="urn:TestNamespace"
xsi:schemaLocation="urn:Test.Namespace Test1.xsd"
>
<ns:element1 id="001">
<ns:element2 id="001.1" order="1">
<ns:element3 id="001.1.1" />
</ns:element2>
<ns:element2 id="001.2" order="2">
<ns:element3 id="001.1.2" />
</ns:element2>
</ns:element1>
<ns:element1 id="999">
<ns:element2 id="999.1" order="1">
<ns:element3 id="999.1.1" />
</ns:element2>
</ns:element1>
</ns:Root>
ie one XML file with all the elements from each included.
I found a useful question on StackOverflow, and came up with this;
Merge.xml
<?xml version="1.0"?>
<ns:Root xmlns:xi="http://www.w3.org/2003/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns="urn:TestNamespace">
<xi:include href="Test1.xml" parse="xml" xpointer="element(//ns:Root/ns:element1)" />
<xi:include href="Test2.xml" parse="xml" xpointer="element(//ns:Root/ns:element1)" />
</ns:Root>
Which I run by doing this (I need to use xmllint for reasons to involved to go into)
xmllint -xinclude Merge.xml
But this does not work, it complains about various thiongs, which seem to relate to xpointer.
parser error : warning: ChildSeq not starting by /1
Merge.xml:7: element include: XInclude error : XPointer evaluation failed: #element(//ns:Root/ns:element1)
Merge.xml:7: element include: XInclude error : could not load Test1.xml, and no fallback was found
parser error : warning: ChildSeq not starting by /1
Merge.xml:9: element include: XInclude error : XPointer evaluation failed: #element(//ns:Root/ns:element1)
Merge.xml:9: element include: XInclude error : could not load Test2.xml, and no fallback was found
<?xml version="1.0"?>
<ns:Root xmlns:xi="http://www.w3.org/2003/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns="urn:TestNamespace">
<xi:include href="Test1.xml" parse="xml" xpointer="element(//ns:Root/ns:element1)"/>
<xi:include href="Test2.xml" parse="xml" xpointer="element(//ns:Root/ns:element1)"/>
</ns:Root>
If I omit the xpointer attributes in Merge.xml then I get some sensible output, but it has done more than include the elements I want of course.
Can someone offer some advice as to what I am doing wrong with xpointer please?
Thanks in antcipation.
I have dabbled with this a bit more, and found plenty of examples on the web that suggest what I am doing is correct.This is now a working version...
<?xml version="1.0"?>
<Root xmlns:xi="http://www.w3.org/2003/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns="http://testurl.com/now">
<xi:include href="Test1.xml" xpointer="xmlns(ns=http://testurl.com/now)xpointer(/ns:Root/ns:element1)" parse="xml" />
<xi:include href="Test2.xml" xpointer="xpointer(//Root/element1)" parse="xml" />
</Root>
This example uses a version of Test1.xml which has namespaces, and Test2.xml which does not.
The output now looks like this....
<?xml version="1.0"?>
<Root xmlns:xi="http://www.w3.org/2003/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns="http://testurl.com/now">
<ns:element1 xmlns:ns="http://testurl.com/now" id="001">
<ns:element2 id="001.1" order="1">
<ns:element3 id="001.1.1"/>
</ns:element2>
<ns:element2 id="001.2" order="2">
<ns:element3 id="001.1.2"/>
</ns:element2>
</ns:element1><ns:element1 xmlns:ns="http://testurl.com/now" id="003">
<ns:element2 id="007.0" order="1">
<ns:element3 id="007.1.1"/>
</ns:element2>
</ns:element1><ns:element1 xmlns:ns="http://testurl.com/now" id="002">
<ns:element2 id="002.1" order="3">
<ns:element3 id="002.1.1"/>
</ns:element2>
<ns:element2 id="002.2" order="4">
<ns:element3 id="002.1.2"/>
</ns:element2>
</ns:element1>
<element1 id="999">
<element2 id="999.1" order="1">
<element3 id="999.1.1"/>
</element2>
</element1>
</Root>
This is of course acceptable, it would be nice if the line breaks between the open and close of element1 were still there
This works with and without namespaces:
<?xml version="1.0"?>
<ns:Root xmlns:xi="http://www.w3.org/2003/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns="urn:TestNamespace">
<xi:include href="Test1.xml" xpointer="xpointer(*/*)" />
<xi:include href="Test2.xml" xpointer="xpointer(*/*)" />
</ns:Root>
Also parse="xml"
is default. You don't need to specify it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With