对于 XSLT 1.0,这很棘手,因为它不支持将日期作为第一类值,也不支持字符串的字典比较。而且它(根据规范)不支持在临时变量中构造节点集,然后从该集中提取单个节点。尽管如此,通过一些技巧可以实现您想要的。
您将日期设置为 YYYY-MM-DD 的事实意味着,如果您去掉连字符并将生成的字符串视为数字,则按数字顺序对这些数字进行排序与按时间顺序对原始日期进行排序的结果相同。尽管 XSLT 没有可更新的变量,但是您可以通过使用一个模板来获得类似的效果,该模板递归地将自身应用于兄弟节点,并在模板参数中向下传递状态。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="targetDate" select="20080101" />
<xsl:template match="foo">
<!-- find the first "candidate" bar whose date is before the target date -->
<xsl:apply-templates select="(bar[translate(@date, '-', '') < $targetDate])[1]" />
</xsl:template>
<xsl:template match="bar">
<xsl:param name="closest" select="." />
<!-- find the next candidate bar whose date is before the target date -->
<xsl:variable name="nextCandidate"
select="(following-sibling::bar[translate(@date, '-', '') < $targetDate])[1]" />
<xsl:choose>
<xsl:when test="$nextCandidate">
<xsl:choose>
<xsl:when test="translate($nextCandidate/@date, '-', '') > translate($closest/@date, '-', '')">
<!-- $nextCandidate is closer to the target than the current $closest -->
<xsl:apply-templates select="$nextCandidate">
<xsl:with-param name="closest" select="$nextCandidate" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<!-- current $closest is still the closest -->
<xsl:apply-templates select="$nextCandidate">
<xsl:with-param name="closest" select="$closest" />
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<!-- no more candidates, so $closest is the node we require -->
<xsl:copy-of select="$closest" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>