XPath最后一次出现的每个元素

JJo*_*s56 5 xml xslt xpath

我喜欢XML

<root>
    <a>One</a>
    <a>Two</a>
    <b>Three</b>
    <c>Four</c>
    <a>Five</a>
    <b>
        <a>Six</a>
    </b>
</root>
Run Code Online (Sandbox Code Playgroud)

并且需要选择root中任何子节点名称的最后一次出现.在这种情况下,所需的结果列表将是:

<c>Four</c>
<a>Five</a>
<b>
    <a>Six</a>
</b>
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏!

Dim*_*hev 6

XPath 2.0解决方案和当前接受的答案都是非常低效的(O(N ^ 2)).

此解决方案具有次线性复杂性:

<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:key name="kElemsByName" match="/*/*"
  use="name()"/>

 <xsl:template match="/">
  <xsl:copy-of select=
    "/*/*[generate-id()
         =
          generate-id(key('kElemsByName', name())[last()])
         ]"/>
 </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

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

<root>
    <a>One</a>
    <a>Two</a>
    <b>Three</b>
    <c>Four</c>
    <a>Five</a>
    <b>
        <a>Six</a>
    </b>
</root>
Run Code Online (Sandbox Code Playgroud)

产生了想要的正确结果:

<c>Four</c>
<a>Five</a>
<b>
   <a>Six</a>
</b>
Run Code Online (Sandbox Code Playgroud)

说明:这是Muenchian分组的修改变体- 所以不是第一个.但是处理了每个组中的最后一个节点.

II XPath 2.0 one-liner:

使用:

/*/*[index-of(/*/*/name(), name())[last()]]
Run Code Online (Sandbox Code Playgroud)

使用XSLT 2.0作为XPath 2.0主机进行验证:

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

 <xsl:template match="/">
  <xsl:sequence select=
    "/*/*[index-of(/*/*/name(), name())[last()]]"/>
 </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

当此转换应用于同一XML文档(前面提供)时,会生成相同的正确结果:

<c>Four</c>
<a>Five</a>
<b>
    <a>Six</a>
</b>
Run Code Online (Sandbox Code Playgroud)

  • @empo:单独在XSLT中进行时间测量是不可能的.用于不同时间和当前日期时间的标准XPath 2.0函数在同一转换期间引用时始终产生相同的结果.这是因为它们是稳定的函数 - 因为函数式语言的所有函数都必须是.当然,在应用程序中调用XSLT转换很容易进行时间测量. (2认同)

Grz*_*ski 3

基于 XSLT 的解决方案:

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

    <xsl:template match="root/*">
        <xsl:variable name="n" select="name()"/>
        <xsl:copy-of
            select=".[not(following-sibling::node()[name()=$n])]"/>
    </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

产生的输出:

<c>Four</c>
<a>Five</a>
<b>
   <a>Six</a>
</b>
Run Code Online (Sandbox Code Playgroud)

第二种解决方案(您可以将其用作单个 XPath 表达式):

<xsl:template match="/root">
    <xsl:copy-of select="a[not(./following-sibling::a)]
        | b[not(./following-sibling::b)]
        | c[not(./following-sibling::c)]"/>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)