Как использовать xpointer с Xinclude для ссылки на элементы
Я хочу объединить 2 файла XML с одинаковой структурой, чтобы создать один. Например;
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>
и 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>
Создавать
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>
т. е. один XML-файл со всеми элементами каждого из них.
Я нашел полезный вопрос по Stackru и придумал это;
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>
Который я запускаю, делая это (мне нужно использовать xmllint по причинам, связанным с этим)
xmllint -xinclude Merge.xml
Но это не работает, он жалуется на разных thiongs, которые, похоже, относятся к 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>
Если я опущу атрибуты xpointer в Merge.xml, то получу какой-то разумный вывод, но он сделал больше, чем, конечно, включение элементов, которые я хочу.
Может кто-нибудь предложить какой-нибудь совет относительно того, что я делаю неправильно с xpointer, пожалуйста?
Спасибо в ожидании.
3 ответа
Я немного побаловался с этим и нашел в Интернете множество примеров, которые говорят о том, что я делаю правильно. Теперь это рабочая версия...
<?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>
В этом примере используется версия Test1.xml, которая имеет пространства имен, и Test2.xml, которая не имеет.
Вывод теперь выглядит следующим образом....
<?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>
Это, конечно, приемлемо, было бы хорошо, если бы разрывы строк между открытием и закрытием element1 все еще были там
Это работает с и без пространств имен:
<?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>
Также parse="xml"
по умолчанию. Вам не нужно указывать это.
Для тех, кто использует Xerces на Java: он поддерживает только
xpointer="element(...)"
указатели. Это определено на https://www.w3.org/TR/2003/REC-xptr-element-20030325/.
В нем есть пример:
Например, следующая часть указателя идентифицирует элемент с идентификатором (как определено в XPointer Framework) "intro".
но мне не удалось понять, что идентификатор XPointer Framework определен с https://www.w3.org/TR/2003/REC-xptr-framework-20030325/#shorthand
Просматривая https://www.ibiblio.org/xml/books/bible3/chapters/ch18.html
и читая https://xerces.apache.org/xerces2-j/faq-xinclude.html,
я понял, что это возможно чтобы добиться того, о чем вы просили:
<?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="element(/1)" />
<xi:include href="Test2.xml" xpointer="element(/1)" />
</ns:Root>
Хорошо в этом то, что я полагаю, что схема element () поддерживается в большем количестве мест, чем полная схема xpointer().
Примечание: эта схема адресации может быть вложенной, например,
/1/2
означает корень ()
1
элемент st, у которого есть дочерний элемент (
/
) на позиции
2
. Так что он выбрал бы
001.2
из
Test1.xml
.