根据 XPath 中的值遍历跨多个祖先的子节点链表

traverse linked list of child nodes across multiple ancestors based on values in XPath

我们的一个供应商将他们的信息存储在 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 in (./divider, ./paperback, ./hardcover)
[relation/child-doc/document-id/doc-number = /bibliographic-data/reference/document-id/doc-number] return 对于 $f 在 $i return $f[relation/child-doc/document-id/doc-number = $i/relation/parent-doc/document-id/doc-number]

遍历具有多个祖先的节点的优雅方式几乎是链表样式。任何帮助都会有所帮助。我可以根据要求提供进一步的解释。

我认为你可以按照参考编写递归函数,最好使用键来完成:

<?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!,但您当然可以使用 xsl:variable 而不是 [=13] 为 XSLT 和 XPath 2.0 重写它=] 和 $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