views:

1134

answers:

2

Hi,

Given the following 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>

I would like to produce this 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>

I can't think how to do this in XSL mainly because i'm wanting to Group by the numbericfield.. All i can come up with is this:

<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>

However this doesn't produce the nice grouped list instead i get this:

<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>

If someone can stear me in the right direction.. That would be great?

Thanks

+3  A: 

To do this in XSLT 1.0, you will have to use a technique called "meunchian grouping". First create a key of the nodes on which you wish to group

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

Next, you iterate it through all the nodes, but only selecting the ones that happen to be first in the relevant group

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

Next, you can iterate use the key to iterate over all nodes in the group

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

Putting this all together gives

<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>

In your example, 'intfield' becomes 'numberfield' though. I have kept the name as 'intfield' in the above example.

Tim C
You the man.. cheers.. just tried it and it works a treat. I'll have to look up this "meunchian grouping" thing as at the moment it all seems like voodoo
CraftyFella
One question... Is there a way to limit the int fields that it creates.. as there is another list of int's else where and it's bringing those into the intfield key? Hope that makes sense
CraftyFella
Yep, in the 'match' attribute of xsl:key you can enter any full Xpath expression to be more precise about what nodes you require. For example <xsl:key name="intfield" match="results/int[substring(@name, 1, 8) = 'intfield']" use="substring-before(@name, ':')"/>
Tim C
Cool bananna.. thanks.. all sorted again.. and works like a charm.. My users will be very happy..
CraftyFella
+1  A: 

Muenchian grouping is a work of genius. It's not easy to understand, but see: http://www.jenitennison.com/xslt/grouping/muenchian.html

To simplify the process the W3C specifically supported grouping in XSLT2.0. See, for example: http://www.xml.com/pub/a/2003/11/05/tr.html

However not all environments support XSLT2.0

peter.murray.rust
Using MS .NET so only XSL 1.0 for me.. you are correct though.. it is a work of genius.. I'll give that link a read. thanks
CraftyFella