代码之家  ›  专栏  ›  技术社区  ›  CraftyFella

在xpath xsl中执行“group by”查询

  •  5
  • CraftyFella  · 技术社区  · 15 年前

    给定以下XML:

    <results name="queryResults">
      <int name="intfield1:[* TO 10]">11</int> 
      <int name="intfield2:[10 TO 20]">9</int> 
      <int name="intfield1:[10 TO 20]">12</int> 
    </results>
    

    我希望生成此XML:

    <results>
        <field name="numberfield1">
            <value name="[* TO 10]">11</value>
            <value name="[10 TO 10]">12</value>
        </field>
        <field name="numberfield2">
            <value name="[10 TO 20]">9</value>
        </field>
    </results>
    

    我不知道如何在XSL中这样做,主要是因为我想按数字字段分组。我能想到的就是:

    <xsl:if test="count(results/int) &gt; 0">
        <results>
        <xsl:for-each select="results/int">
            <field>
                <xsl:attribute name="name">
                    <xsl:value-of select="substring-before(@name, ':')"/></xsl:attribute>
                <value>
                    <xsl:attribute name="name">
                        <xsl:value-of select="substring-after(@name, ':') "/>
                    </xsl:attribute>
                    <xsl:value-of select="."/>
                </value>
            </field>
        </xsl:for-each>
        </results>
    </xsl:if>
    

    然而,这并不能产生好的分组列表,相反,我得到了:

    <results>
        <field name="numberfield1">
            <value name="[* TO 10]">11</value>
        </field>
        <field name="numberfield2">
            <value name="[10 TO 20]">9</value>
        </field>
        <field name="numberfield1">
            <value name="[10 TO 10]">12</value>
        </field>
    </results>
    

    如果有人能告诉我正确的方向……那太好了?

    谢谢

    2 回复  |  直到 11 年前
        1
  •  12
  •   Community CDub    11 年前

    要在XSLT1.0中执行此操作,必须使用名为 "muenchian grouping" .首先创建要分组的节点的键

    <xsl:key name="intfield" match="int" use="substring-before(@name, ':')" />
    

    接下来,您将遍历所有节点,但只选择恰好位于相关组中第一个节点的节点。

    <xsl:for-each select="int[generate-id() = generate-id(key('intfield', substring-before(@name, ':'))[1])]">
    

    接下来,可以迭代使用键迭代组中的所有节点。

    <xsl:variable name="intfieldname" select="substring-before(@name, ':')"/>
    <xsl:for-each select="key('intfield', $intfieldname)">
    

    把这些放在一起

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
       <xsl:output method="xml"/>
       <xsl:key name="intfield" match="int" use="substring-before(@name, ':')"/>
       <xsl:template match="/results">
          <results>
             <xsl:for-each select="int[generate-id() = generate-id(key('intfield', substring-before(@name, ':'))[1])]">
                <xsl:variable name="intfieldname" select="substring-before(@name, ':')"/>
                <field>
                   <xsl:attribute name="name">
                      <xsl:value-of select="$intfieldname"/>
                   </xsl:attribute>
                   <xsl:for-each select="key('intfield', $intfieldname)">
                      <value>
                         <xsl:attribute name="name">
                            <xsl:value-of select="substring-after(@name, ':')"/>
                         </xsl:attribute>
                         <xsl:value-of select="."/>
                      </value>
                   </xsl:for-each>
                </field>
             </xsl:for-each>
          </results>
       </xsl:template>
    </xsl:stylesheet>
    

    在您的示例中,“Intfield”变为“NumberField”。在上面的示例中,我将名称保留为“Intfield”。

    • 固定键入
        2
  •  3
  •   peter.murray.rust    15 年前

    穆恩西亚的分组是一件天才的作品。这不容易理解,但请看: http://www.jenitennison.com/xslt/grouping/muenchian.html

    为了简化这个过程,W3C在XSLT2.0中特别支持分组。例如,请参见: http://www.xml.com/pub/a/2003/11/05/tr.html

    但并非所有环境都支持XSLT2.0