首页 文章

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

提问于
浏览
29

鉴于此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 回答

  • 11

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

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

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

  • 2

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

    <xsl:for-each select="*">
      <xsl:if test="not(position() = 1)>, </xsl:if>
      <xsl:value-of select="."/>   
    </xsl:for-each>
    
  • 52
    <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>
    
  • 9

    A simple XPath 1.0 one-liner

    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>
    

    and apply it to the XML document

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

    to get the wanted result:

    apple,orange,banana

    EDIT:

    以下是Robert Rossney对此答案的评论:

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

    and here is my answer

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

  • 7

    这是我让它为我工作的方式 . 我在你的清单上测试了这个:

    <?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>
    
  • 25

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

    这个 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,', ')"/>
    

相关问题