Re: [xsl] Grouping problem

Subject: Re: [xsl] Grouping problem
From: Andrew Franz <afranz0@xxxxxxxxxxxxxxxx>
Date: Tue, 02 Aug 2005 23:44:55 +1000
Sorry, my mistake - you need to construct a new document that is amenable to processing.

There are a number of ways of doing this, e.g. by creating a result-tree - not strictly standard, I know but it illustrates the method:

<xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
   xmlns:ms="urn:schemas-microsoft-com:xslt">
....
<xsl:variable name="g">
<xsl:for-each select="*">
   <group name="{local-name()}" />
</xsl:for-each>
</xsl:variable>

<xsl:apply-templates select="ms:node-set($g)/group">
   <xsl:sort select="@name" />
</xsl:apply-templates>

<xsl:template match="group[(@name = preceding-sibling::group/@name)]" priority="+1" />
<xsl:template match="group">
<group name="{@name}" />
</xsl:template>


.....

Alternatives:
1. use a multi-stage pipeline such as Apache Cocoon
2. nested translation in JSP
3. change the input format if you can


Michael Kay wrote:


These seem to be solutions to a different problem. The original XML has no
@name attributes.

Michael Kay
http://www.saxonica.com/




-----Original Message-----
From: Andrew Franz [mailto:afranz0@xxxxxxxxxxxxxxxx] Sent: 01 August 2005 22:11
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] Grouping problem


Mukul Gandhi wrote:



Thanks Mike for the XSLT 2.0 way to solve the problem. But it was
surprising for me that the problem cannot be solved in XSLT 1.0 using
preceding-sibling axis.

Regards,
Mukul




Solution #1:
<xsl:template match="groups">
   <xsl:for-each select="group">
   <xsl:sort select="@name" />
   <xsl:if test="not(@name = preceding-sibling::group/@name)">
       <group name="{@name}" />
   </xsl:if>
   </xsl:for-each>
</xsl:template>

Solution #2:
<xsl:template match="groups">
   <xsl:for-each select="group">
   <xsl:sort select="@name" />
       <xsl:apply-templates select="." />
   </xsl:for-each>
</xsl:template>

<xsl:template match="group[(@name = preceding-sibling::group/@name)]" priority="+1" />
<xsl:template match="group">
<group name="{@name}" />
</xsl:template>


Solution #3:
<xsl:key name="k2" match="group" use="@name" />

<xsl:template match="groups">
   <xsl:for-each select="group">
   <xsl:sort select="@name" />
       <xsl:apply-templates select="." />
   </xsl:for-each>
</xsl:template>

<xsl:template match="group" priority="-1" />
<xsl:template match="group[generate-id() = generate-id(key('k2', @name)[1])]">
group[<xsl:value-of select="@id" />]=<xsl:value-of select="@name" /><br/>
</xsl:template>






On 8/1/05, Michael Kay <mike@xxxxxxxxxxxx> wrote:




When comparing two node-sets,

X = Y

means "some $x in X equals some $y in Y"

But when you do

name(X) = name(Y)

you are comparing two strings, not two node-sets. If X is a

node-set, then


name(X) is the name of the first node in X, and name(Y) is

the name of the


first node in Y. (In XSLT 2.0, with version="2.0", you

would get an error


trying to apply name() to a node-set containing more than

one node. The


change has been made to catch this common mistake.)

In 2.0 you can write

select="*[not(name() = preceding-sibling::*/name())]"

but of course it would be more efficient to use xsl:for-each-group.

Michael Kay
http://www.saxonica.com/






-----Original Message-----
From: Mukul Gandhi [mailto:gandhi.mukul@xxxxxxxxx]
Sent: 01 August 2005 07:57
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: [xsl] Grouping problem

I have the following XML file -
<?xml version="1.0" encoding="UTF-8"?>
<root>
 <a>1</a>
 <b>2</b>
 <d>3</d>
 <d>4</d>
 <b>5</b>
 <b>6</b>
 <c>7</c>
 <c>8</c>
 <a>9</a>
</root>

I am trying to do grouping operation with the following XSL -
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

    <xsl:output method="xml" version="1.0" encoding="UTF-8"
indent="yes"/>

    <xsl:template match="/root">
       <groups>
         <xsl:for-each select="*[not(name() =
name(preceding-sibling::*))]">
          <group name="{name()}" />
         </xsl:for-each>
       </groups>
    </xsl:template>

</xsl:stylesheet>

I am expecting output -
<groups>
 <group name="a" />
 <group name="b" />
 <group name="c" />
 <group name="d" />
</groups>

But I get output -
<?xml version="1.0" encoding="UTF-8"?>
<groups>
<group name="a"/>
<group name="b"/>
<group name="d"/>
<group name="d"/>
<group name="b"/>
<group name="b"/>
<group name="c"/>
<group name="c"/>
</groups>

Where is the problem?

This is tested with Xalan-J 2.6.0 and Saxon 8.4

Regards,
Mukul

Current Thread