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

时间:2015-09-08 14:23:44

标签: xml xpath xpath-2.0

我有以下XML:

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

我想从XPath获得以下输出:

e1: foo, e2: bar, ...

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

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

2 个答案:

答案 0 :(得分:3)

  

我尝试使用字符串连接,但它没有用。 XPath可以做到这一点的任何想法?甚至可能吗?
  [...]我不认为这是可能的)

为什么不可能?...

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

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,使用text-value-templates(TVT&#39; s)编写模板:

    <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 functionspdf)在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,只需忽略模板方法,就可以坚持上述功能。

答案 1 :(得分:0)

如果您不想使用优雅的scala> iter[Int](_ + 1, 1).iterator.drop(100 * 100 * 100).take(10).toList res1: List[Int] = List(1000002, 1000003, 1000004, 1000005, 1000006, 1000007, 1000008, 1000009, 1000010, 1000011) 表达式

string-join()

你仍然可以使用这个更长的表达

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

或者,您可以使用此XSLT 2.0单行(当然,它需要包含在适当的模板中,例如匹配 /*/*/concat(@key, ': ', @value, if(following-sibling::*[1]) then ', ' else () ) ):

'/'