我有一个XML:
<ast>
<group>
<Set>
<location line="1" column="22" offset="22"/>
<group>
<Id value="foo">
<location line="1" column="31" offset="31"/>
</Id>
</group>
<group>
<Function>
<location line="1" column="22" offset="22"/>
<end-location line="1" column="49" offset="49"/>
<group>
<Id value="a">
<location line="1" column="35" offset="35"/>
</Id>
<Id value="b">
<location line="1" column="37" offset="37"/>
</Id>
</group>
<group>
<Return>
<location line="1" column="40" offset="40"/>
<Number value="0">
<location line="1" column="47" offset="47"/>
</Number>
</Return>
</group>
</Function>
</group>
</Set>
...
</group>
</ast>
我使用此模板处理:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="text()" /><!-- remove blanks -->
<xsl:template match="Set[group[position()=1]/Id][group[position()=2]/Function]">
<function-def>
<xsl:attribute name="name">
<xsl:value-of select="group[position()=1]/Id/@value" />
<xsl:text>(</xsl:text>
<xsl:apply-templates select="group[position()=2]/Function" />
<xsl:text>)</xsl:text>
</xsl:attribute>
<xsl:copy-of select="group/Function/location" />
<xsl:copy-of select="group/Function/end-location" />
</function-def>
</xsl:template>
<xsl:template match="Function/group[position()=1]/Id">
<xsl:value-of select="@value" />
<xsl:if test="position() != last()"><xsl:text>,</xsl:text></xsl:if>
</xsl:template>
</xsl:stylesheet>
但是最后一个模板上的条件position() != last()
不起作用。为什么呢?
输出呈现为:
<?xml version="1.0"?>
<function-def name="foo(a,b,)">...
虽然它应该是:
<?xml version="1.0"?>
<function-def name="foo(a,b)">...
答案 0 :(得分:2)
这是有效的,但不是你想的那样......
在第一个模板中,您有xsl:apply-templates
<xsl:apply-templates select="group[position()=2]/Function" />
但是你没有匹配Function
的模板,所以XSLT的built-in template rules开始了,这就是......
<xsl:template match="*|/">
<xsl:apply-templates/>
</xsl:template>
这将选择Group
元素,而且没有模板。现在,当它<xsl:apply-templates/>
时,它将选择所有子节点,其中包括用于缩进XML的空文本节点。
问题在于,当您测试position() = last()
时,您正在测试已选择的所有子节点集合中元素的位置,其中包括文本节点。在最后一个id
之后有一个空文本节点,因此id
可能是最后一个id
元素,但它不是最后一个子节点。
一个解决方案是告诉XSLT剥离空文本节点,以便id
成为最后一个子节点
<xsl:strip-space elements="*" />
或者,您可以添加与group
匹配的模板,并仅显式选择id
个节点
<xsl:template match="Function/group[position()=1]">
<xsl:apply-templates select="Id" />
</xsl:template>