Как использовать 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.

Другие вопросы по тегам