如何在单个 XPath 函数中连接每个元素的两个属性?

How can I concatenate two attributes per element in a single XPath function?

我有以下 XML:

<xml>
    <entry key="e1" value="foo"/>
    <entry key="e2" value="bar"/>
    ...
</xml>

我想从 XPath 获得以下输出:

e1: foo, e2: bar, ...

我尝试使用 string-join 但它没有用。任何想法哪个版本的 XPath 可以做到这一点?有可能吗?

(注意:我更喜欢 XPath 1.0 查询,但是,我认为这是不可能的)

I tried to use string-join but it didn't work. Any ideas on which XPath could do this? Is it even possible?
[...] I don't think it is possible)

为什么不可能?...

无论如何,正如评论中所暗示的那样,只需使用

concat(
    entry[1]@key, ': ', 
    entry[1]@value, ', ', 
    entry[2]@key, ': ', 
    entry[2]@value) 

其他方式:

  • XPath 2.0: string-join( (expr1, expr2, ...), '')
  • XSLT 2.0:<xsl:value-of select="expr1, expr2, ..." separator="" />
  • XPath 3.0: expr1 || expr2 || ... 使用字符串连接运算符
  • 任何XSLT版本,为防止重复,使用模板匹配:

    <xsl:template match="xml/entry">
        <xsl:value-of select="@key" />
        <xsl:text>: </xsl:text>
        <xsl:value-of select="@value" />
        <xsl:if test="position() != last()">,</xsl:if>
    </xsl:template>
    
  • 或更通用,在属性节点上应用模板并匹配如下:

    <xsl:template match="@key | @value">
        <xsl:value-of select="." />
        <xsl:text>: </xsl:text>
    </xsl:template>
    
    <xsl:template match="@value">
        <xsl:value-of select="@value" />
        <xsl:text>, </xsl:text>
    </xsl:template>
    
  • XSLT 3.0,使用文本值模板 (TVT) 编写模板:

    <xsl:template match="xml/entry" expand-text="yes">{
        @key}: {
        @value,
        if(position() != last()) then ',' else ()
    }</xsl:template>
    
  • XPath 2.0,更通用的方法:

    string-join(
        for $i in xml/item 
        return concat($i/@key, ': ', $i/@value),
        ', ')
    

    或更短:

    string-join(xml/item/concat($i/@key, ': ', $i/@value, ', ')
    
  • ... 或使用 higher-order functions (pdf) 在 XPath 3.0 中获得乐趣和更轻松(?)阅读:

    let $combine = concat(?, ': ', ?)
    return string-join(
        for $i in xml/item 
        return $combine($i/@key, $i/@value),
        ', ')
    

    甚至:

    string-join(
        for-each-pair(
            xml/item/@key,       (: combine this :)
            xml/item/@value,     (: with this :)
            concat(?, ': ', ?)), (: using this, in order :)
        ', ')                    (: then join :)
    

注意:如果您不使用 XSLT,只需忽略模板方法,您可以坚持提到的功能。

如果不想使用优雅的string-join()表达式:

string-join(/*/*/concat(@key, ': ', @value), 
            ', ')

您仍然可以使用这个稍微长一点的表达式:

 /*/*/concat(@key, ': ', 
             @value, 
             if(following-sibling::*[1])
                then ', '
                else ()
             )

或者,您可以使用这个 XSLT 2.0 one-liner(当然它需要包含在适当的模板中,例如一个匹配 '/'):

<xsl:value-of select="/*/*/concat(@key, ': ', @value)" separator="', '"/>