Выполнение запроса «Группировать по» в XPath XSL - PullRequest
5 голосов
/ 18 декабря 2009

С учетом следующего 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 ]

12 голосов
/ 18 декабря 2009

Чтобы сделать это в XSLT 1.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' в приведенном выше примере.

  • исправлена ​​опечатка.
3 голосов
/ 20 декабря 2009

мюнхенская группировка - гениальная работа. Это не легко понять, но посмотри: http://www.jenitennison.com/xslt/grouping/muenchian.html

Для упрощения процесса W3C специально поддерживает группировку в XSLT2.0. Смотрите, например: http://www.xml.com/pub/a/2003/11/05/tr.html

Однако не все среды поддерживают XSLT2.0

...