Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old February 18th, 2009, 12:22 PM
Authorized User
 
Join Date: May 2006
Posts: 46
Thanks: 0
Thanked 0 Times in 0 Posts
Default Help with grouping

I have to create a nested table when there are more than one record in the same group.
The first cell must stay in the first cell and the next cells must go into the cells in the nested table. I have been searching for a way to group records based on a group attribute but can't seem the get it right could someone help me with this.

the source and target looks like this:
Source



<rows>
<row group="1">
<cell>X</cell>
<cell>B</cell>
<cell>C</cell>
</row>
<row group="2">
<cell>Y</cell>
<cell>B1</cell>
<cell>C1</cell>
</row>
<row group="2">
<cell>Y</cell>
<cell>B2</cell>
<cell>C2</cell>
</row>
</rows>

Target structure

<table >
<tr>
<td>X</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td >Y</td>


<td colspan="2">
<table>
<tr>
<td>B1</td>
<td>C1</td>
</tr>
<tr>
<td>B2</td>
<td>C2</td>
</tr>
</table>
</td>
</tr>
</table>
 
Old February 18th, 2009, 12:30 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Do you want to use XSLT 2.0 or 1.0?
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old February 18th, 2009, 12:44 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Here is an XSLT 2.0 solution:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">
  
  <xsl:output indent="yes"/>
  
  <xsl:template match="rows">
    <table>
      <xsl:for-each-group select="row" group-by="@group">
        <tr>
          <td>
            <xsl:value-of select="cell[1]"/>
          </td>
          <xsl:choose>
            <xsl:when test="current-group()[2]">
              <td colspan="2">
                <table>
                  <xsl:apply-templates select="current-group()" mode="row"/>
                </table>
              </td>
            </xsl:when>
            <xsl:otherwise>
              <xsl:apply-templates select="current-group()/cell[position() gt 1]"/>
            </xsl:otherwise>
          </xsl:choose>
        </tr>
      </xsl:for-each-group>
    </table>
  </xsl:template>
  
  <xsl:template match="row" mode="row">
    <tr>
      <xsl:apply-templates select="cell[position() gt 1]"/>
    </tr>
  </xsl:template>
  
  <xsl:template match="cell">
    <td>
      <xsl:value-of select="."/>
    </td>
  </xsl:template>

</xsl:stylesheet>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old February 19th, 2009, 06:03 AM
Authorized User
 
Join Date: May 2006
Posts: 46
Thanks: 0
Thanked 0 Times in 0 Posts
Smile this was the solution

Thanx Martin for the quick reply this is the solution. Did not think about using
current-group()[2]
I use this for XSLT-FO like this:
INPUT XML
Code:
<report>
     <body>
  <table>
   <caption>Table caption</caption>
   <definition>
    <column/>
    <column/>
    <column/>
    <column/>
   </definition>
   <header>
    <cell>User</cell>
    <cell>Status</cell>
    <cell>Start</cell>
    <cell>End</cell>
   </header>
   <rows>
    <row group="user1">
     <cell>Henkes, T. </cell>
     <cell>inactive</cell>
     <cell>31 Mar 2008</cell>
     <cell/>
    </row>
    <row group="user2">
     <cell>Houkes, G.</cell>
     <cell>active</cell>
     <cell>31 Mar 2008</cell>
     <cell>30 Jun 2008</cell>
    </row>
    <row group="user2">
     <cell>Houkes, G.</cell>
     <cell>inactive</cell>
     <cell>1 Jul 2008</cell>
     <cell>1 Aug 2008</cell>
    </row>
    <row group="user2">
     <cell>Houkes, G.</cell>
     <cell>active</cell>
     <cell>2 Aug 2008</cell>
     <cell/>
    </row>
    <row group="user3">
     <cell>Kruijff, P.</cell>
     <cell>inactive</cell>
     <cell>31 Mar 2008</cell>
     <cell/>
    </row>
   </rows>
   <footer>
    <cell colspan="2">Aantal actieve gebruikers: 1</cell>
    <cell colspan="2">Aantal inactieve gebruikers: 2</cell>
   </footer>
  </table>
    </body>
</report>
XSLT
Code:
    <xsl:template match="rows">
        <fo:table-body xsl:use-attribute-sets="inside-table">
            <xsl:choose>
                <!-- row with grouping -->
                <xsl:when test="./row[@group]">
                    <xsl:for-each-group select="row" group-by="@group">
                        <fo:table-row>
                            <fo:table-cell padding="0pt" margin="0pt" border="1px solid silver">
                                <fo:block padding="2pt" margin="0pt">
                                    <xsl:value-of select="cell[1]"/>
                                </fo:block>
                            </fo:table-cell>
                            <xsl:choose>
                                <xsl:when test="current-group()[2]">
                                    <fo:table-cell padding="0pt" margin="0pt"
                                        number-columns-spanned="3" border="1px solid silver">
                                        <fo:block padding="2pt" margin="0pt">
                                            <fo:table table-layout="fixed"
                                                border-collapse="collapse" width="100%"
                                                padding="0pt" margin="0pt">
                                                <fo:table-body text-align="left">
                                                  <xsl:apply-templates select="current-group()"
                                                  mode="grouprow"/>
                                                </fo:table-body>
                                            </fo:table>
                                        </fo:block>
                                    </fo:table-cell>
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:apply-templates
                                        select="current-group()/cell[position() gt 1]"/>
                                </xsl:otherwise>
                            </xsl:choose>
                        </fo:table-row>
                    </xsl:for-each-group>
                </xsl:when>
                <!-- normal row -->
                <xsl:otherwise>
                    <xsl:apply-templates select="row"/>
                </xsl:otherwise>
            </xsl:choose>
        </fo:table-body>
    </xsl:template>
 
    <!-- handle a table row where the first column must be omitted-->
    <xsl:template match="row" mode="grouprow">
        <fo:table-row>
            <!-- handle the cells  -->
            <xsl:apply-templates select="cell[position() gt 1]"/>
        </fo:table-row>
    </xsl:template>
 
    <!-- handle a table row -->
    <xsl:template match="row">
        <fo:table-row>
            <!-- handle the cells  -->
            <xsl:apply-templates/>
        </fo:table-row>
    </xsl:template>
 
    <!-- handle a table body cells -->
    <xsl:template match="table/rows/row/cell">
        <!-- get style of column of table header position doesnt work here because of generated textnodes-->
        <xsl:variable name="index">
            <xsl:value-of select="count(preceding-sibling::node()[name()='cell'])+1"/>
        </xsl:variable>
        <xsl:variable name="style">
            <xsl:value-of select="ancestor::node()/definition/column[position()=$index]/@style"/>
        </xsl:variable>
        <fo:table-cell padding="0pt" margin="0pt" border="1px solid silver">
            <xsl:if test="@colspan">
                <xsl:attribute name="number-columns-spanned">
                    <xsl:value-of select="@colspan"/>
                </xsl:attribute>
            </xsl:if>
            <fo:block padding="2pt" margin="0pt">
                <xsl:if test="$style !=''">
                    <xsl:call-template name="set_style">
                        <xsl:with-param name="style" select="$style"/>
                    </xsl:call-template>
                </xsl:if>
                <xsl:apply-templates/>
                <!-- <xsl:value-of select="."/>-->
            </fo:block>
        </fo:table-cell>
    </xsl:template>
 
<!-- set the style of the font and alignment -->
    <xsl:template name="set_style">
        <xsl:param name="style"/>
        <xsl:choose>
            <xsl:when test="contains($style,'numeric emphasize')">
                <xsl:attribute name="text-align">right</xsl:attribute>
                <xsl:attribute name="padding-right">
                    <xsl:value-of select="$paddingright"/>
                    <xsl:text>cm</xsl:text>
                </xsl:attribute>
                <xsl:attribute name="font-weight">bold</xsl:attribute>
            </xsl:when>
            <xsl:when test="contains($style,'numeric')">
                <xsl:attribute name="text-align">right</xsl:attribute>
                <xsl:attribute name="padding-right">
                    <xsl:value-of select="$paddingright"/>
                    <xsl:text>cm</xsl:text>
                </xsl:attribute>
            </xsl:when>
            <xsl:when test="contains($style,'right')">
                <xsl:attribute name="text-align">right</xsl:attribute>
                <xsl:attribute name="padding-right">
                    <xsl:value-of select="$paddingright"/>
                    <xsl:text>cm</xsl:text>
                </xsl:attribute>
            </xsl:when>
            <xsl:when test="contains($style,'emphasize')">
                <xsl:attribute name="font-weight">bold</xsl:attribute>
            </xsl:when>
            <xsl:when test="contains($style,'left')">
                <xsl:attribute name="text-align">left</xsl:attribute>
            </xsl:when>
        </xsl:choose>
    </xsl:template>
 
Old February 23rd, 2009, 12:00 PM
Authorized User
 
Join Date: May 2006
Posts: 46
Thanks: 0
Thanked 0 Times in 0 Posts
Default version 1.0?

Somehow this goes wrong in Saxon version 8.0 it works fine in Saxon 9.0. In version 8.0 we always get the error that there is an empty table:
Code:
>> SEVERE: Exception
>> javax.xml.transform.TransformerException:
>> org.apache.fop.fo.ValidationException: Error(Unknown location):
>> fo:table-body is missing child elements.
>> Required Content Model: marker* (table-row+|table-cell+)
But when I generate the FO with 9.0 there's nothing wrong with the output. ( I don't have the possibility to generate this in the 8.0 version) Now probably I have to take my change with version 1.0 xslt. But can't get it right.
In the rows template i have to check the row group because i need to add extra tags around the rows. somehow the grouping with the help of keys doesn't get right.
I have more than one table and the groupname is unique only within this table.
this is what I tried but somewhere I make a mistake (or more). Can somebody help me with this so i can get the grouping right in version 1.0 when we only can use the saxon 8 or lower.
Code:
   <xsl:template match="rows">
        <xsl:param name="header"/>
        <fo:table-body xsl:use-attribute-sets="inside-table">
            <xsl:choose>
                <!-- row with grouping -->
                <xsl:when test="./row[@group]">
                    <!-- group the records by groupname and select the first entry -->
                    <xsl:for-each select="./row[generate-id()=generate-id(../row[key('usergroup',@group)][1])]">
                        <fo:table-row>
                            <fo:table-cell padding="0pt" margin="0pt" border="1px solid silver">
                                <fo:block padding="2pt" margin="0pt">
                                    <xsl:value-of select="cell[1]"/>
                                </fo:block>
                            </fo:table-cell>
                            <xsl:choose>
                                <!-- test if there are more rows in this parent with the same groupname and repeat over these entries-->
                                <xsl:when test="../row[@group=current()/@group][2]">
                                    <xsl:for-each select="../row[@group=current()/@group]">
                                        <fo:table-cell padding="0pt" margin="0pt"
                                            number-columns-spanned="3" border="1px solid silver">
                                            <fo:block padding="2pt" margin="0pt">
                                                <fo:table table-layout="fixed"
                                                    border-collapse="collapse" width="100%"
                                                    padding="0pt" margin="0pt">
                                                    <fo:table-body text-align="left">
                                                        <!-- select only the cells greater than 1 -->
                                                        <xsl:apply-templates select="." mode="grouprow"/>
                                                    </fo:table-body>
                                                </fo:table>
                                            </fo:block>
                                        </fo:table-cell>
                                    </xsl:for-each>
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:apply-templates  select="."/>
                                </xsl:otherwise>
                            </xsl:choose>
                        </fo:table-row>
                    </xsl:for-each>
                    
<!--    code for version 2.0           
                    <xsl:for-each-group select="row" group-by="@group">
                        <fo:table-row>
                            <fo:table-cell padding="0pt" margin="0pt" border="1px solid silver">
                                <fo:block padding="2pt" margin="0pt">
                                    <xsl:value-of select="cell[1]"/>
                                </fo:block>
                            </fo:table-cell>
                            <xsl:choose>
                                <xsl:when test="current-group()[2]">
                                    <fo:table-cell padding="0pt" margin="0pt"
                                        number-columns-spanned="3" border="1px solid silver">
                                        <fo:block padding="2pt" margin="0pt">
                                            <fo:table table-layout="fixed"
                                                border-collapse="collapse" width="100%"
                                                padding="0pt" margin="0pt">
                                                <fo:table-body text-align="left">
                                                  <xsl:apply-templates select="current-group()"
                                                  mode="grouprow"/>
                                                </fo:table-body>
                                            </fo:table>
                                        </fo:block>
                                    </fo:table-cell>
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:apply-templates
                                        select="current-group()/cell[position() gt 1]"/>
                                </xsl:otherwise>
                            </xsl:choose>
                        </fo:table-row>
                        </xsl:for-each-group>-->

                </xsl:when>
                <!-- normal row -->
                <xsl:otherwise>
                    <xsl:apply-templates select="row"/>
                </xsl:otherwise>
            </xsl:choose>
        </fo:table-body>
    </xsl:template>
 
Old February 23rd, 2009, 01:25 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

I would strongly suggest to move to the latest Saxon version which is 9.1 I think.
If you really want to use XSLT 1.0 and Muenchian grouping then here is an untested attempt to translate your earlier XSLT 2.0 template using xsl:for-each-group into XSLT 1.0 and Muenchian grouping:
Code:
   <xsl:key name="by-group" match="row" use="@group"/>
   
   <xsl:template match="rows">
        <fo:table-body xsl:use-attribute-sets="inside-table">
            <xsl:choose>
                <!-- row with grouping -->
                <xsl:when test="./row[@group]">
                   <!-- <xsl:for-each-group select="row" group-by="@group"> -->
                    <xsl:for-each select="row[generate-id() = generate-id(key('by-group', @group)[1])]">
                        <xsl:variable name="cg" select="key('by-group', @group)"/>
                        <fo:table-row>
                            <fo:table-cell padding="0pt" margin="0pt" border="1px solid silver">
                                <fo:block padding="2pt" margin="0pt">
                                    <xsl:value-of select="cell[1]"/>
                                </fo:block>
                            </fo:table-cell>
                            <xsl:choose>
                               <!-- <xsl:when test="current-group()[2]"> -->
                                <xsl:when test="$cg[2]">
                                    <fo:table-cell padding="0pt" margin="0pt"
                                        number-columns-spanned="3" border="1px solid silver">
                                        <fo:block padding="2pt" margin="0pt">
                                            <fo:table table-layout="fixed"
                                                border-collapse="collapse" width="100%"
                                                padding="0pt" margin="0pt">
                                                <fo:table-body text-align="left">
                                                 <!--  <xsl:apply-templates select="current-group()"
                                                  mode="grouprow"/> -->
                                                  <xsl:apply-templates select="$cg" mode="grouprow"/>
                                                </fo:table-body>
                                            </fo:table>
                                        </fo:block>
                                    </fo:table-cell>
                                </xsl:when>
                                <xsl:otherwise>
                                   <!--  <xsl:apply-templates
                                        select="current-group()/cell[position() gt 1]"/> -->
                                    <xsl:apply-templates select="$cg/cell[position() &gt; 1]"/>
                                </xsl:otherwise>
                            </xsl:choose>
                        </fo:table-row>
                    </xsl:for-each-group>
                </xsl:when>
                <!-- normal row -->
                <xsl:otherwise>
                    <xsl:apply-templates select="row"/>
                </xsl:otherwise>
            </xsl:choose>
        </fo:table-body>
    </xsl:template>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old February 23rd, 2009, 01:33 PM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Saxon 8.0 is a very old release and was produced before the XSLT 2.0 spec was finished. (There were releases 8.1, 8.2, etc all the way up to 8.9, 9.0, and the current release is 9.1)
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
 
Old February 24th, 2009, 06:30 AM
Authorized User
 
Join Date: May 2006
Posts: 46
Thanks: 0
Thanked 0 Times in 0 Posts
Default Issue with WebSphere using debug mode

Thanx for the replies great to get this help.

Found also the error why the 8.0 saxon did give the errors in the development environment from websphere. It seams that IBM uses its own saxon debuggable xslt processor when testing in debug mode (which is an 1.0 version)
to resolve this you can disable this processor:
see: http://download.boulder.ibm.com/ibmd...en/readme.html

Workaround:
Disable the DebugTransformer in your server by setting a JVM system property in the WebSphere Administrative Console:
  • Log in to the WebSphere Administrative Console.
  • Navigate to Servers -> Application Servers and select your server.
  • In the Additional Properties section, select Debugging Service.
  • Add the following parameter to your JVM debug arguments: -Dcom.ibm.debug.attach.agent.xslt.enabled=false
 
Old February 24th, 2009, 06:58 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

What makes you think that IBM APAR (IBM-speak for a bug) has anything to do with Saxon? The description of it is all to do with Xalan.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference





Similar Threads
Thread Thread Starter Forum Replies Last Post
Protect cells and allow grouping/un-grouping sfreuden Excel VBA 4 December 14th, 2006 08:01 AM
Grouping List chemi XSLT 1 October 20th, 2005 09:36 AM
Grouping Records banarieo XSLT 1 September 28th, 2005 10:39 AM
Grouping problem aware Access 11 August 4th, 2005 11:00 AM
grouping / totaling happyslug BOOK: Professional Crystal Reports for VS.NET 1 July 12th, 2005 05:07 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.