根据 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>
我们的一个供应商将他们的信息存储在 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>