根据节点值对XPath查询进行分组?

时间:2013-06-28 00:00:13

标签: xml xslt xpath

我想知道是否有能够根据元素内的文本对XML数据进行分组的事情。

我有一些类似于以下的XML,为简单而愚蠢:

<person>
    <name>Bob</name>
    <food>Apples</food>
</person>
<person>
    <name>Billy</name>
    <food>Bananas</food>
</person>
<person>
    <name>Bob</name>
    <food>Oranges</food>
</person>

我想以下列方式显示上述数据:

Person's Name: Bob
Person's Food: Apples
               Oranges

Person's Name: Billy
Person's Food: Bananas

我尝试了使用所有不同示例的多种方法,但我无法正确使用XPath来实现这一目标。我只是无法绕过能够只显示Bob的第一个实例而且还能够显示Bob的所有食物,这些食物分布在Bob的多个实例中。关于我从哪里开始的任何建议?

2 个答案:

答案 0 :(得分:2)

您可以使用XPath 2(不使用xslt)执行类似操作,使用distinct-values获取所有名称,然后使用每个名称的食物创建字符串。

for $v in distinct-values(/person/name) return concat($v, ": ", string-join(/person[name = $v]/food, ", "))

返回(使用类型信息)

sequence: (string: Bob: Apples, Oranges, string: Billy: Bananas)

或者更类似于您的输出:

for $v in distinct-values(/person/name) return concat(
  "Person's Name: ", $v, "
Person's Food: ", string-join(/person[name = $v]/food, "
               "))

返回

sequence: (string: Person's Name: Bob
Person's Food: Apples
               Oranges, string: Person's Name: Billy
Person's Food: Bananas)

答案 1 :(得分:1)

要使用xslt-1.0执行此操作,您应该查看 Muenchian方法 e.g this

因此请尝试:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes" method="text"/>

    <xsl:key name="kPerson" match="person" use="name"/>
    <xsl:template match="/*">
        <xsl:for-each select="person[count( . | key('kPerson', name)[1]) =1 ]">
            <xsl:variable name="pname" select="name"  />
            <xsl:text>Person's Name: </xsl:text>
            <xsl:value-of select="$pname"/>
            <xsl:text>&#10;</xsl:text>
            <xsl:for-each select="key('kPerson', $pname)" >
                <xsl:choose>
                    <xsl:when test="position()=1">Person's Food: </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>               </xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
                <xsl:value-of select="food"/>
                <xsl:text>&#10;</xsl:text>
            </xsl:for-each>

        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>