如何使用XSLT / XPath生成以逗号分隔的列表?

时间:2009-03-20 15:16:54

标签: xml xslt xpath

鉴于此XML数据:

<root>
  <item>apple</item>
  <item>orange</item>
  <item>banana</item>
</root>

我可以使用这个XSLT标记:

...
<xsl:for-each select="root/item">
  <xsl:value-of select="."/>,
</xsl:for-each>
...

得到这个结果:

  苹果,橘子,香蕉,

但是如何生成最后一个逗号不存在的列表?我认为可以按照以下方式做一些事情:

...
<xsl:for-each select="root/item">
  <xsl:value-of select="."/>
  <xsl:if test="...">,</xsl:if>
</xsl:for-each>
...

但测试表达式应该是什么?

我需要一些方法来确定列表的长度以及我当前在列表中的位置,或者,如果我当前正在处理列表中的最后一个元素(这意味着我不在乎它有多长时间)是或当前的位置是什么。)

7 个答案:

答案 0 :(得分:52)

这是一种非常常见的模式:

<xsl:for-each select="*">
   <xsl:value-of select="."/>
   <xsl:if test="position() != last()">
      <xsl:text>,</xsl:text>
   </xsl:if>
</xsl:for-each>

答案 1 :(得分:25)

查看position()count()last()函数;例如,test="position() &lt; last()"

答案 2 :(得分:11)

对于XSLT 2.0选项,您可以使用separator上的xsl:value-of属性。

xsl:value-of

<xsl:value-of select="/root/item" separator=", "/>

会产生这个输出:

apple, orange, banana

您还可以使用多个逗号作为分隔符。例如,这个:

<xsl:text>'</xsl:text>
<xsl:value-of select="/root/item" separator="', '"/>
<xsl:text>'</xsl:text>

会产生以下输出:

'apple', 'orange', 'banana'

另一个XSLT 2.0选项是string-join() ...

<xsl:value-of select="string-join(/*/item,', ')"/>

答案 3 :(得分:9)

<xsl:if test="following-sibling::*">,</xsl:if>

或(也许效率更高,但你必须测试):

<xsl:for-each select="*[1]">
   <xsl:value-of select="."/>
   <xsl:for-each select="following-sibling::*">
       <xsl:value-of select="concat(',',.)"/>
   </xsl:for-each>
</xsl:for-each>

答案 4 :(得分:7)

一个简单的XPath 1.0单行

<强> concat(., substring(',', 2 - (position() != last())))

将其纳入此转型:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

    <xsl:template match="/*">
      <xsl:for-each select="*">
        <xsl:value-of select=
         "concat(., substring(',', 2 - (position() != last())))"
         />
      </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

并将其应用于XML文档

<root>
    <item>apple</item>
    <item>orange</item>
    <item>banana</item>
</root>

获得想要的结果:

apple,orange,banana

修改

以下是罗伯特·罗斯尼对此答案的评论:

  

对于人来说,这是非常不透明的代码   阅读。它需要你知道两个   关于XSLT的非显而易见的事情:1)什么   如果它的子串函数   索引超出范围,2)   逻辑值可以隐式   转换为数字。

,这是我的回答

伙计们,从不羞于学习新事物。实际上这是Stack Overflow的全部内容,不是吗? :)

答案 5 :(得分:7)

罗伯特给了法语not(position() = last())答案。这要求您处理整个当前节点列表以获取上下文大小,而在大型输入文档中,这可能会使转换消耗更多内存。因此,我通常将测试反转为第一件事

<xsl:for-each select="*">
  <xsl:if test="not(position() = 1)>, </xsl:if>
  <xsl:value-of select="."/>   
</xsl:for-each>

答案 6 :(得分:2)

这是我让它为我工作的方式。 我在你的清单上对此进行了测试:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />

<xsl:template match="root">
    <xsl:call-template name="comma-join"><xsl:with-param name="list" select="item"/></xsl:call-template>
</xsl:template>

<xsl:template name="comma-join">
    <xsl:param name="list" />
    <xsl:for-each select="$list">
        <xsl:value-of select="." />
        <xsl:if test="position() != last()">
            <xsl:text>, </xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:template> 
</xsl:stylesheet>