проследить связанный список дочерних узлов по нескольким предкам на основе значений в XPath - PullRequest
0 голосов
/ 27 апреля 2018

Один из наших поставщиков хранит свою информацию в XML-коде почти в стиле связанного списка. Мне было трудно найти способ обойти и соединить все данные. Ниже приведен код XML:

<bibliographic-data>
  <reference>
     <document-id>
       <doc-number>15492293</doc-number>
     </document-id>
  </reference>
</bibliographic-data>


    <related-documents>
            <divider>
                <relation>
                    <parent-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>09861196</doc-number>
                            <date>20010518</date>
                        </document-id>
                        <parent-document>
                            <document-id>
                                <code>UC</code>
                                <doc-number>6514193</doc-number>
                                <date>20030204</date>
                            </document-id>
                        </parent-document>
                    </parent-doc>
                    <child-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>10665793</doc-number>
                        </document-id>
                    </child-doc>
                </relation>
            </divider>      
            <paperback>
                <relation>
                    <parent-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>14711658</doc-number>
                            <date>20150513</date>
                        </document-id>
                        <parent-status>SHELVED</parent-status>
                    </parent-doc>
                    <child-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>15492293</doc-number>
                        </document-id>
                    </child-doc>
                </relation>
            </paperback>
            <paperback>
                <relation>
                    <parent-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>14473159</doc-number>
                            <date>20140829</date>
                        </document-id>
                        <parent-document>
                            <document-id>
                                <code>UC</code>
                                <doc-number>9636401</doc-number>
                                <date>20170502</date>
                            </document-id>
                        </parent-document>
                    </parent-doc>
                    <child-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>14711658</doc-number>
                        </document-id>
                    </child-doc>
                </relation>
            </paperback>

            <paperback>
                <relation>
                    <parent-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>12823700</doc-number>
                            <date>20100625</date>
                        </document-id>
                        <parent-document>
                            <document-id>
                                <code>UC</code>
                                <doc-number>8470294</doc-number>
                                <date>20130625</date>
                            </document-id>
                        </parent-document>
                    </parent-doc>
                    <child-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>13911616</doc-number>
                        </document-id>
                    </child-doc>
                </relation>
            </paperback>
            <paperback>
                <relation>
                    <parent-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>10665793</doc-number>
                            <date>20030919</date>
                        </document-id>
                        <parent-document>
                            <document-id>
                                <code>UC</code>
                                <doc-number>7776310</doc-number>
                                <date>20100817</date>
                            </document-id>
                        </parent-document>
                    </parent-doc>
                    <child-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>12823700</doc-number>
                        </document-id>
                    </child-doc>
                </relation>
            </paperback>
            <hardcover>
                <relation>
                    <parent-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>13911616</doc-number>
                            <date>20130613</date>
                        </document-id>
                        <parent-document>
                            <document-id>
                                <code>UC</code>
                                <doc-number>8821835</doc-number>
                                <date>20140902</date>
                            </document-id>
                        </parent-document>
                    </parent-doc>
                    <child-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>14473159</doc-number>
                        </document-id>
                    </child-doc>
                </relation>
            </hardcover>
            <hardcover>
                <relation>
                    <parent-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>09861326</doc-number>
                            <date>20010518</date>
                        </document-id>
                        <parent-document>
                            <document-id>
                                <code>UC</code>
                                <doc-number>6746661</doc-number>
                                <date>20040608</date>
                            </document-id>
                        </parent-document>
                    </parent-doc>
                    <child-doc>
                        <document-id>
                            <code>UC</code>
                            <doc-number>09861196</doc-number>
                        </document-id>
                    </child-doc>
                </relation>
            </hardcover>
        </related-documents>

Я пытаюсь пройтись по всем узлам, используя дочерние и родительские поля номера документа. это должно соединить 15492293, должно начаться цепь, сопровождаемое 14711658 -> 14473159 -> 13911616 -> 12823700 -> 10665793 -> 09861196 -> 09861326.

Я попытался использовать следующее выражение XPAth: за $ i в (./divider, ./paperback, ./hardcover)
[отношение / дочерний документ / идентификатор документа / номер документа = / библиографические данные / ссылка / идентификатор документа / номер документа] вернуть за $ f в $ i вернуть $ f [отношение / дочерний-документ / идентификатор документа / номер документа = $ я / отношение / родительский-документ / идентификатор документа / номер документа]

Что представляет собой элегантный способ прохождения через узлы с несколькими предками почти связанного стиля списка. Любая помощь будет полезна. Я могу предоставить дополнительные объяснения по запросу.

1 Ответ

0 голосов
/ 28 апреля 2018

Я думаю, что вы можете написать рекурсивную функцию по ссылке, которую лучше всего использовать с помощью клавиши:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs mf"
    version="3.0">

    <xsl:param name="start-id">15492293</xsl:param>

    <xsl:output method="text"/>

    <xsl:key name="parent" match="related-documents/*" use="relation/child-doc/document-id/doc-number"/>

    <xsl:function name="mf:get-ancestor-ids" as="xs:integer*">
        <xsl:param name="item" as="element()"/>
        <xsl:sequence 
            select="let $parent-id := $item/relation/parent-doc/document-id/doc-number,
                        $parent := key('parent', $parent-id, root($item)) 
                        return (xs:integer($parent-id), $parent!mf:get-ancestor-ids(.))"/>
    </xsl:function>

    <xsl:template match="/" name="xsl:initial-template">
        <xsl:value-of select="$start-id, mf:get-ancestor-ids(key('parent', $start-id))" separator=" -> "/>
    </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / eiZQaF1 дает результат

15492293 -> 14711658 -> 14473159 -> 13911616 -> 12823700 -> 10665793 -> 9861196 -> 9861326

В этом примере используются некоторые функции XSLT и XPath 3, например let или !, но вы, конечно, можете переписать это для XSLT и XPath 2.0, используя xsl:variable вместо let и $parent/mf:get-ancestor-ids(.) или if ($parent) then mf:get-ancestor-ids($parent) else () для $parent!mf:get-ancestor-ids(.):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs mf"
    version="2.0">

    <xsl:param name="start-id">15492293</xsl:param>

    <xsl:output method="text"/>

    <xsl:key name="parent" match="related-documents/*" use="relation/child-doc/document-id/doc-number"/>

    <xsl:function name="mf:get-ancestor-ids" as="xs:integer*">
        <xsl:param name="item" as="element()"/>
        <xsl:variable name="parent-id"
          select="$item/relation/parent-doc/document-id/doc-number"/>
        <xsl:variable name="parent"
          select="key('parent', $parent-id, root($item))"/>
        <xsl:sequence 
            select="xs:integer($parent-id), $parent/mf:get-ancestor-ids(.)"/>
    </xsl:function>

    <xsl:template match="/">
        <xsl:value-of select="$start-id, mf:get-ancestor-ids(key('parent', $start-id))" separator=" -> "/>
    </xsl:template>

</xsl:stylesheet>

http://xsltransform.net/93nvfd2

...