0

我正在寻找一种可重用的方法来从 xml 文档中获取所有节点,这些节点是从给定节点的后代引用(通过 id),但不是给定节点本身的后代。例如:

<root>
  <somenode>
     <a id="a1"/>
     <aref ref="a1"/>
  </somenode>
  <somenode>
     <a id="a2"/>
     <aref ref="a1"/>
     <aref ref="a2"/>
  </somenode>
</root>

如果给定节点是 /root/somenode[1],则结果节点集应该是空的。每个引用的 a 都是 /root/somenode[1] 的子节点。另一方面,如果给定的节点是 /root/somenode[2],则生成的节点集应该包含 /root/somenode[1]/a[1] 而没有其他内容。

重要的是生成的节点集始终以相同的方式排序。此外,解决方案应该只使用 xslt-1.0 并且 exlst 扩展构建到 xsltproc 中(库的确切版本:“使用 libxml 20708、libxslt 10126 和 libexslt 815”)

在此先感谢, 约斯特

4

2 回答 2

1

根据http://www.exslt.org/set/functions/difference/index.html,libxslt 支持该功能

<xsl:key name="el-by-id" match="*" use="id"/>

<xsl:variable name="refs" select="set:difference(key('el-by-id', descendant::*/@ref), descendant::*)"/>

应该在您的节点作为上下文节点的模板中执行 (with xmlns:set="http://exslt.org/sets")。

于 2012-07-27T14:35:08.420 回答
1

此处提供的解决方案不使用任何扩展功能,并且在任何 XSLT 处理器上都是 100% 可移植的。

使用 xslt 函数generate-id()

//*[@id = /*/somenode[1]/aref/@ref 
  and 
    not(generate-id(ancestor::somenode) = generate-id(/*/somenode[1]))
   ]

使用密钥可能会带来更高的效率,

这也可以使用节点集交集的 Kayessian 公式表示为单个 XPath 1.0 表达式:

$ns1[count(.|$ns2) = count($ns2)]

在纯 XPath 2.0 中,将使用is运算符而不是generate-id().

这是一个完整的演示

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  "<xsl:copy-of select=
   "//*[@id = /*/somenode[1]/aref/@ref
      and
        not(generate-id(ancestor::somenode) = generate-id(/*/somenode[1]))
       ]"/>"
============
  "<xsl:copy-of select=
   "//*[@id = /*/somenode[2]/aref/@ref
      and
        not(generate-id(ancestor::somenode) = generate-id(/*/somenode[2]))
        ]"/>"
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<root>
  <somenode>
     <a id="a1"/>
     <aref ref="a1"/>
  </somenode>
  <somenode>
     <a id="a2"/>
     <aref ref="a1"/>
     <aref ref="a2"/>
  </somenode>
</root>

计算 XPath 表达式并将所选节点复制到输出:

  ""
============
  "<a id="a1" />"
于 2012-07-27T14:33:06.783 回答