如何在排序后的xsl:for-each循环中获取前后元素的@id属性
解决XSLT排序后获取前后元素@id的问题
这个问题的核心在于你混淆了原始文档节点顺序和排序后的序列顺序——这也是很多XSLT新手容易踩的坑。让我给你拆解问题并给出解决方案:
为什么之前的方法无效?
preceding-sibling::和following-sibling::轴是基于XML文档的原始结构顺序工作的,完全不受xsl:sort的影响,所以你拿不到排序后的前后元素。- 你尝试的
(//chapter)[($current_pos - 1)]/@id,这里的//chapter是原文档顺序的节点集合,所以取到的是原序列里的第N个元素,不是排序后的结果。
正确的解决方案(XSLT 3.0兼容)
我们可以先把排序后的chapter节点存入变量,然后在遍历这个排序后的序列时,通过当前位置索引来获取前后元素:
<?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" exclude-result-prefixes="xs" version="3.0"> <xsl:template match="/root"> <!-- 预先生成排序后的章节节点序列并存储 --> <xsl:variable name="sorted_chapters" select="chapter"> <xsl:sort select="@id"/> </xsl:variable> <!-- 遍历排序后的序列 --> <xsl:for-each select="$sorted_chapters"> <xsl:variable name="current_pos" select="position()"/> <xsl:variable name="total_count" select="count($sorted_chapters)"/> Chapter id: <xsl:value-of select="@id"/> Sorted position: <xsl:value-of select="$current_pos"/> <!-- 处理前驱元素:如果不是第一个元素,取排序序列中前一个节点的@id,否则输出none --> Sorted predecessor chapter id: <xsl:value-of select="if ($current_pos > 1) then $sorted_chapters[$current_pos - 1]/@id else 'none'"/> <!-- 处理后继元素:如果不是最后一个元素,取排序序列中后一个节点的@id,否则输出none --> Sorted follower chapter id: <xsl:value-of select="if ($current_pos < $total_count) then $sorted_chapters[$current_pos + 1]/@id else 'none'"/> <xsl:text>
</xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>
运行结果
这段样式表处理你的示例XML后,会输出你期望的结果:
Chapter id: a23 Sorted position: 1 Sorted predecessor chapter id: none Sorted follower chapter id: c-0 Chapter id: c-0 Sorted position: 2 Sorted predecessor chapter id: a23 Sorted follower chapter id: c-1 Chapter id: c-1 Sorted position: 3 Sorted predecessor chapter id: c-0 Sorted follower chapter id: d42 Chapter id: d42 Sorted position: 4 Sorted predecessor chapter id: c-1 Sorted follower chapter id: t19 Chapter id: t19 Sorted position: 5 Sorted predecessor chapter id: d42 Sorted follower chapter id: none
额外说明
如果你使用的是XSLT 2.0+(你的样式表已经指定了3.0,完全兼容),这种预先存储排序序列的方法是最直观且高效的。另外,也可以用index-of($sorted_chapters, current())来获取当前元素在序列中的位置,但position()在xsl:for-each遍历中已经直接对应排序后的位置,用起来更简洁。
内容的提问来源于stack exchange,提问作者Martin Hinze
相关产品推荐
相关产品推荐

