XSL:基于属性存在性在for-each中递增计数求助
解决XSLT中仅统计有指定属性节点的序号问题
没问题,我明白你的需求啦——你想要的是只给带有@a属性的<entry>节点按顺序编号,而不是用它们在原节点列表里的位置。原来的代码里用position()会把所有<entry>都算进去,包括那个没有@a的,所以才会出现序号跳变的情况。
这里有几种简单的解决方法:
方法1:先筛选符合条件的节点再遍历(最直观)
先只选择带有@a的<entry>节点,再对这个筛选后的列表用position(),这样序号自然就是连续的了:
<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="/"> <posts> <!-- 先筛选出有@a属性的entry,再遍历 --> <xsl:for-each select="data/posts/entry[@a]"> <xsl:variable name="i" select="position()" /> <xsl:copy> <xsl:value-of select="concat('$i = ', $i)"/> </xsl:copy> </xsl:for-each> </posts> </xsl:template> </xsl:stylesheet>
方法2:用preceding-sibling统计符合条件的前置节点
如果你不想改变原有的遍历范围,可以修改变量$i的计算方式:统计当前节点之前所有带有@a属性的<entry>数量,再加1就是当前符合条件节点的序号:
<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="/"> <posts> <xsl:for-each select="data/posts/entry"> <xsl:if test="@a"> <xsl:variable name="i" select="count(preceding-sibling::entry[@a]) + 1" /> <xsl:copy> <xsl:value-of select="concat('$i = ', $i)"/> </xsl:copy> </xsl:if> </xsl:for-each> </posts> </xsl:template> </xsl:stylesheet>
方法3:用xsl:number元素(更简洁的模板匹配方式)
如果你习惯用模板匹配的写法,xsl:number可以直接帮你统计符合条件的节点序号:
<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="/"> <posts> <xsl:apply-templates select="data/posts/entry[@a]"/> </posts> </xsl:template> <xsl:template match="entry[@a]"> <xsl:copy> <!-- count属性指定只统计带有@a的entry --> <xsl:value-of select="concat('$i = ', xsl:number(count='entry[@a]'))"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
以上三种方法运行后,都会得到你想要的输出:
<posts> <entry>$i = 1</entry> <entry>$i = 2</entry> <entry>$i = 3</entry> <entry>$i = 4</entry> <entry>$i = 5</entry> </posts>
内容的提问来源于stack exchange,提问作者Shravan
相关产品推荐
相关产品推荐

