我试图找到一种方法来索引包含特定类型的子节点的节点,并将它们从1开始索引,并根据找到的每个子节点增加1。我尝试使用count(),但这显示了我的代码中节点的位置,而不是找到的子节点的索引。在其他语言中,我会使用变量,但在XSLT中不允许这样做。
我已经阅读了一些使用模板进行递归计数的示例,但是我对XSLT不够熟悉,无法将其集成到现有代码中。
<?xml version="1.0" encoding="UTF-8"?>
<entry>
<node>
<subnodeA>test_subnodeA1</subnodeA>
<subnodeB>test_subnodeB1</subnodeB>
</node>
<node>
<subnodeA>test_subnodeA2</subnodeA>
<subnodeB>test_subnodeB2</subnodeB>
</node>
<node>
<subnodeA>test_subnodeA3</subnodeA>
</node>
<node>
<subnodeA>test_subnodeA4</subnodeA>
<subnodeB>test_subnodeB3</subnodeB>
</node>
</entry>
XSLT <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<!-- Initial usage -->
<xsl:for-each select="node">
<xsl:value-of select="subnodeA"/>
<xsl:if test="subnodeB != ''">
<xsl:value-of select="position()"/>
</xsl:if>
</xsl:for-each>
<!-- Second usage -->
<xsl:for-each select="node">
<xsl:if test="subnodeB != ''">
<xsl:value-of select="position()"/>.
<xsl:value-of select="subnodeB"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
我想显示像
这样的内容test_subnodeA1 1
test_subnodeA2 2
test_subnodeA3
test_subnodeA4 3
1 test_subnodeB1
2 test_subnodeB2
3 test_subnodeB3
但是使用我的方法我只能得到
test_subnodeA1 1
test_subnodeA2 2
test_subnodeA3
test_subnodeA4 4
1 test_subnodeB1
2 test_subnodeB2
4 test_subnodeB3
一些条目有几个节点没有subnodeB,然后有一个节点,所以我的列表从3,4或5开始。
在第一种情况下,您可以通过计算前面的兄弟节点来获得位置
<xsl:value-of select="count(preceding-sibling::node[subnodeA and subnodeB]) + 1" />
在第二种情况下,您只希望节点元素具有subnodeB
<xsl:for-each select="node[subnodeA and subnodeB]">
下面是XSLT示例。注意,我已经从使用xsl:for-each切换到使用xsl:apply-templates
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/entry">
<xsl:apply-templates select="node" mode="initial" />
<xsl:apply-templates select="node[subnodeB]" mode="second" />
</xsl:template>
<xsl:template match="node" mode="initial">
<xsl:value-of select="subnodeA" />
<xsl:if test="subnodeB != ''">
<xsl:text> - </xsl:text><xsl:value-of select="count(preceding-sibling::node[subnodeA and subnodeB]) + 1" />
</xsl:if>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="node" mode="second">
<xsl:value-of select="position()" /> - <xsl:value-of select="subnodeB" />
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
生成以下文本输出
test_subnodeA1 - 1
test_subnodeA2 - 2
test_subnodeA3
test_subnodeA4 - 3
1 - test_subnodeB1
2 - test_subnodeB2
3 - test_subnodeB3
我们也可以使用count直接在感兴趣的节点上应用模板:
给定subnodeA为当前节点:
-
count(preceding::subnodeB[not(../subnodeA)])
不包含子节点a的所有前节点计数(当前移位) -
count(preceding::subnodeA[../subnodeB])
对所有具有subnodeB(相对位置- 1)的节点计数
让我们看看它如何使用重复(仅subnodeA,因为subnodeB是微不足道的):
<xsl:template match="entry">
<xsl:for-each select="node/subnodeA">
<xsl:value-of select="."/>
<xsl:if test="../subnodeB">
<xsl:value-of select="
count(preceding::subnodeB[not(../subnodeA)])
+ count(preceding::subnodeA[../subnodeB])
+ 1 "/>
</xsl:if>
<xsl:if test="position()!=last()">
<xsl:value-of select="'
'"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
和apply模板:
<xsl:template match="entry">
<xsl:apply-templates select="node/subnodeA"/>
</xsl:template>
<xsl:template match="node/subnodeA">
<xsl:value-of select="."/>
<xsl:if test="../subnodeB">
<xsl:value-of select="
count(preceding::subnodeB[not(../subnodeA)])
+ count(preceding::subnodeA[../subnodeB])
+ 1 "/>
</xsl:if>
<xsl:if test="position()!=last()">
<xsl:value-of select="'
'"/>
</xsl:if>
</xsl:template>
这是最简单的解决方案之一——没有xsl:for-each
,没有count()
,没有特殊轴,根本没有显式条件逻辑:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="*/node/subnodeA"/>
<xsl:apply-templates select="*/node/subnodeB"/>
</xsl:template>
<xsl:template match="*[subnodeB]/subnodeA">
<xsl:value-of select="concat(., ' ')"/>
<xsl:number level="any" count="*[subnodeB]/subnodeA"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="subnodeB">
<xsl:value-of select="concat(position(), ' ', ., '
' )"/>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="concat(., '
')"/>
</xsl:template>
</xsl:stylesheet>
当应用于提供的XML文档时:
<entry>
<node>
<subnodeA>test_subnodeA1</subnodeA>
<subnodeB>test_subnodeB1</subnodeB>
</node>
<node>
<subnodeA>test_subnodeA2</subnodeA>
<subnodeB>test_subnodeB2</subnodeB>
</node>
<node>
<subnodeA>test_subnodeA3</subnodeA>
</node>
<node>
<subnodeA>test_subnodeA4</subnodeA>
<subnodeB>test_subnodeB3</subnodeB>
</node>
</entry>
生成所需的正确结果:
test_subnodeA1 1
test_subnodeA2 2
test_subnodeA3
test_subnodeA4 3
1 test_subnodeB1
2 test_subnodeB2
3 test_subnodeB3