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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/666584/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 12:24:56  来源:igfitidea点击:

How do I generate a comma-separated list with XSLT/XPath?

xmlxsltxpath

提问by Anders Sandvig

Given this XML data:

鉴于此 XML 数据:

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

I can use this XSLT markup:

我可以使用这个 XSLT 标记:

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

to get this result:

得到这个结果:

apple, orange, banana,
苹果、橙子、香蕉、

but how do I produce a list where the last comma is not present? I assume it can be done doing something along the lines of:

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

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

but what should the test expression be?

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

I need some way to figure out how long the list is and where I currently am in the list, or, alternatively, if I am currently processing the last element in the list (which means I don't care how long it is or what the current position is).

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

采纳答案by Anders Sandvig

Take a look at the position(), count()and last()functions; e.g., test="position() &lt; last()".

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

回答by Robert Rossney

This is a pretty common pattern:

这是一个很常见的模式:

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

回答by Daniel Haley

For an XSLT 2.0 option, you can use the separatorattribute on xsl:value-of.

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

This xsl:value-of:

xsl:value-of

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

would produce this output:

会产生这个输出:

apple, orange, banana

You could also use more than just a comma for a separator. For example, this:

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

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

Would produce the following output:

将产生以下输出:

'apple', 'orange', 'banana'

Another XSLT 2.0 option is string-join()...

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

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

回答by Marc Gravell

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

or (perhaps more efficient, but you'd have to test):

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

<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>

回答by Dimitre Novatchev

A simple XPath 1.0 one-liner:

一个简单的 XPath 1.0 单行

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

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

Put it into this transformation:

把它放到这个转换中:

<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:

并将其应用于 XML 文档

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

to get the wanted result:

得到想要的结果:

apple,orange,banana

apple,orange,banana

EDIT:

编辑:

Here is a comment from Robert Rossney to this answer:

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

That's pretty opaque code for a human to read. It requires you to know two non-obvious things about XSLT: 1) what the substring function does if its index is out of range and 2) that logical values can be implicitly converted to numerical ones.

对于人类来说,这是非常不透明的代码。它要求您了解有关 XSLT 的两件不明显的事情:1) 如果子字符串函数的索引超出范围,它会做什么,以及 2) 逻辑值可以隐式转换为数字值。

and here is my answer:

这是我的答案

Guys, never shy from learning something new. In fact this is all Stack Overflow is about, isn't it? :)

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

回答by jelovirt

Robert gave the classis not(position() = last())answer. This requires you to process the whole current node list to get context size, and in large input documents this might make the conversion consume more memory. Therefore, I normally invert the test to be the first thing

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

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

回答by Louise Rogow Howard

This is the way I got it working for me. I tested this against your list:

这就是我让它对我来说有效的方式。我根据您的列表对此进行了测试:

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