虽然您自己的解决方案STATUS[TYPE/@VALUE = '2'][not(//STATUSLIST/STATUS[TYPE/@VALUE = '2']/DATE > DATE)]
可行,但对于大量条目来说并不是特别有效,因为您将每个条目STATUS
与其他条目进行比较STATUS
,因此 O(N 2 )。更有效的方法是将其实现为尾递归函数(如您所说的使用 XSLT 2.0),如下所示:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:local="urn:local" exclude-result-prefixes="local">
<xsl:function name="local:latestByDate" as="item()*">
<xsl:param name="seq" as="item()*"/>
<xsl:sequence select="local:latestByDate($seq, ())" />
</xsl:function>
<xsl:function name="local:latestByDate" as="item()*">
<xsl:param name="seq" as="item()*" />
<xsl:param name="maxSoFar" as="item()*" />
<xsl:choose>
<xsl:when test="$seq">
<!-- calculate the new maxSoFar, comparing the current max with
the first item in $seq. Note the use of not(x<=y) instead of
x>y, so the test is true if $maxSoFar is the empty sequence -->
<xsl:variable name="newMax"
select="if(not($seq[1]/DATE <= $maxSoFar/DATE))
then $seq[1] else $maxSoFar"/>
<xsl:sequence select="local:latestByDate(
$seq[position() gt 1], $newMax)" />
</xsl:when>
<xsl:otherwise>
<!-- we have reached the end of $seq, return the max -->
<xsl:sequence select="$maxSoFar" />
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- example of how to call the function -->
<xsl:template match="/*">
<xsl:copy-of select="local:latestByDate(STATUS[TYPE/@VALUE='2'])" />
</xsl:template>
</xsl:stylesheet>
此函数对节点列表进行单次传递(因此 O(N)),跟踪输入序列中哪个元素具有最新的每一步DATE
。