[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: Slow XSLT

Subject: Re: Slow XSLT
From: Cleyton Jordan <cleytonjordan@xxxxxxxxxxx>
Date: Fri, 14 Mar 2008 21:42:48 +0000 (GMT)
Re:  Slow XSLT
Hi Manfred,

Thanks again for your assistance. It is really
appreciated.

I will try your sample code and let you know what
happens.

Also, as I mentined before, I am trying to build a
GRID and will send to you a copy of my latest XSLT so
that you can see what I have achieved so far. Slowly I
am getting there :-)

THE GRID

Basically, I use four <DIV> and <TABLE> tags. I have
the Top Left DIV, Top Right DIV, Bottom Left DIV and
Bottom Rght DIV.

Because I use Javascript to align my GRID, I have to
apply templates in a certain order i.e:

1- build the bottom right section first (grdBody)
2- next build the top right section (column headings)
3- Build the bottom left section (row headings)
4- Finaly build the top left section which is just an
empty div with the right hight and width to align with
the rest of the grid.

Please note that I still have to change my XSLT code
to use the sample code you showed me (call template
and tail recursion). I am still using my old key way I
mentioned to you.

I am struggling a bit with some of the suggestions I
have received specially the sample code provided by
David Carlisle. He showed me how to use a technique
that Michael calls vanilla push-processing. 

However, since I have to sort the xml based on some
parameters passed to the stylesheet, I am not sure
where to add the <xsl:sort> command with
<apply-templates>. 

I have to sort 3 sections of the xml. This is how I
used to do:

<xsl:sort select
="Cell[number($sortCell)]/descendant::Msr[number($sortCol)]/@val"
data-type="{$dataType}" order ="{$sortOrder}" />

I have to sort all the rows except for the last one -
the Total row of course :-). That is the reason for
the when test:

OLD REPORT TEMPLATE WITH SORTING

<xsl:template match="Report" >
<!-- grdBdy -->
      <div id="{$id}grdBdy">
        <table id="tblTop" cellpadding="0">          
          <tbody>
            <xsl:choose>
              <xsl:when  test="number($sortCol) != 0">
                <xsl:apply-templates
select="/Reports/Report/Rows//Row" mode="data">   
                  <xsl:sort select
="Cell[number($sortCell)]/descendant::Msr[number($sortCol)]/@val"
data-type="{$dataType}" order ="{$sortOrder}" />
                </xsl:apply-templates>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates
select="/Reports/Report/Rows//Row" mode="data" />     
  
              </xsl:otherwise>
            </xsl:choose>
          </tbody>
        </table>
      </div>
</xsl:template>

I also have to add a sort command to sort the Row
Headings:

OLD REPORT TEMPLATE WITH ROW HEADING SORTING

<xsl:template match="Report" >
<!-- grdLeft -->   
      <div id="{$id}grdLft" style="position: absolute;
top: 12px; left: 0px; width: 150px; height:
{$height}px">
        <table width="100%" class="grdMain" border="0"
cellspacing="1" cellpadding="0">
          <tbody>           
            <xsl:choose>
              <xsl:when  test="number($sortCol) != 0">
                <xsl:apply-templates
select="Rows//Row" mode="heading">
                  <xsl:sort select
="Cell[number($sortCell)]/descendant::Msr[number($sortCol)]/@val"
data-type="{$dataType}" order ="{$sortOrder}" />
                </xsl:apply-templates>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates
select="Rows//Row" mode="heading" />
              </xsl:otherwise>
            </xsl:choose>
          </tbody>
        </table>
      </div>
</xsl:template>

Please note that I used to be able to control all
these sections using the MODE ATTRIBUTE

<xsl:apply-templates select="Rows//Row"
mode="heading">

However, with apply-templates I might not have this
control. What do you think?

The last place I have to sort is in the Cell template.
Please note that I have removed this sort command from
my latest XSLT because I am not sure how to do that
now.  

<xsl:template match="Cell">    
    <xsl:choose>
      <xsl:when test="Msr">
        <xsl:for-each select="Msr">
          <xsl:sort select="@idx" order="ascending"
data-type="number"/>
          <xsl:choose>
.....
....
</xsl:template>
 
I would appreciate your suggestion about the sorting
issues I mentioned above and also any other
improvement you may find possible.

Just one last note, I still have to figure out the
best way to deal with the ROW HEADINGS. Still using
old code like <xsl:if
test="preceding-sibling::Row=false() or
number($sortCol) != 0">
        <xsl:apply-templates select="parent::RowGrp"
mode="heading" />. 

How difficult do you think it would be to change my
approach of using 4 DIVs and 4 Tables to build the
grid and instead creating just one table? 

However, I would have to make sure I get my rowspan
and colspan right for the first TD in the first <tr>.

Cheers

C


XSLT
____

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" version="1.0"
encoding="iso-8859-1" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <!--<xsl:decimal-format name="fd1"
decimal-separator="." grouping-separator=","
NaN=" \"/>-->
  <xsl:param name="axisHeads" select="'false'"/>
  <xsl:param name="sortCol" select="'0'"/>
  <xsl:param name="sortCell" select="'0'"/>
  <xsl:param name="dataType" select="'number'"/>
  <xsl:param name="sortOrder" select="'descending'"/>
  <xsl:param name="ltCurFormat"
select="'$##,###.00'"/>
  <xsl:param name="ltNumFormat"
select="'###,.00'"/>
  <xsl:param name="heading"/>
  <xsl:param name="height" select="'500'"/>
  <xsl:param name="width" select="'880'"/>
  <xsl:param name="id" select="'audit'"/>

  <xsl:variable name="nrmr"
select="count(/Report/Measures/Measure)"/>
  <xsl:variable name="msrs"
select="/Report/Measures/Measure"/>
  <xsl:variable name="colSet"
select="/Report/Columns/ColGrp/descendant::Col"/>

  <xsl:key name="c" match="ColGrp"
use="count(ancestor::ColGrp)"/>

  <xsl:template match="Report">

    <!-- outer div to contain all four grid elements
-->
    <div id="{$id}dvGrid" class="grdVP"
style="position: relative; height: {$height}px; width:
{$width}px; overflow: hidden; clip: rect(0px,
{$width}px, {$height}px, 0px);">

      <!-- grdBdy -->
      <div id="{$id}grdBdy" style="position: relative;
width: {$width}px; height: {$height}px; overflow:auto"
onscroll="scrollFullGrid(this)">
        <table class="grdMain" id="tblTop" border="0"
cellspacing="1" cellpadding="0">
          <tbody>
            <xsl:choose>
              <xsl:when  test="number($sortCol) != 0">
                <xsl:apply-templates>
                  <xsl:sort select
="Cell[number($sortCell)]/descendant::Msr[number($sortCol)]/@val"
data-type="{$dataType}" order ="{$sortOrder}" />
                </xsl:apply-templates>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates/>
              </xsl:otherwise>
            </xsl:choose>
          </tbody>
        </table>
      </div>

      <div id="{$id}grdTop" style="position: absolute;
top: 0px; left: 0px; width: {$width}px; height: 12px">
        <table class="grdTop" border="0"
cellspacing="1" cellpadding="0">
          <tbody>
            <xsl:apply-templates select="Columns"
mode="Column"/>
          </tbody>
        </table>
      </div>

      <!-- grdLeft -->
      <div id="{$id}grdLft" style="position: absolute;
top: 12px; left: 0px; width: 150px; height:
{$height}px">
        <table width="100%" class="grdMain" border="0"
cellspacing="1" cellpadding="0">
          <tbody>
            <xsl:choose>
              <xsl:when  test="number($sortCol) != 0">
                <xsl:apply-templates
select="Rows//Row" mode="heading">
                  <xsl:sort select
="Cell[number($sortCell)]/descendant::Msr[number($sortCol)]/@val"
data-type="{$dataType}" order ="{$sortOrder}" />
                </xsl:apply-templates>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates
select="Rows//Row" mode="heading" />
              </xsl:otherwise>
            </xsl:choose>
          </tbody>
        </table>
      </div>

      <!-- grdTL the filler space - formerly the td
with colspan and rowspan -->

      <div id="{$id}grdTL" class="grdTL"
style="position: absolute; width:150px;height:12px">
        <div></div>
      </div>
    
    </div>

  </xsl:template>


  <!--== ROW DATA   ==-->

  <xsl:template match="Row">
    <tr>
      <xsl:apply-templates/>
    </tr>
  </xsl:template>

  <xsl:template match="Msr">
    <xsl:variable name="numberVal" select="@val"/>
    <xsl:choose>
      <!--<xsl:when test="string(number(@val))
='NaN'">-->
      <xsl:when test="not(number($numberVal))">
        <td align="left" style="overflow:none">
          <nobr>
            <div style="width:80px;overflow:none">
              <xsl:value-of select="$numberVal"/>
            </div>
          </nobr>
        </td>
      </xsl:when>
      <xsl:otherwise>
        <td align="right" style="overflow:none">
          <nobr>
            <div style="width:80px;overflow:none">
              <!--<xsl:variable name="numberVal"
select="@val"/>-->
              <xsl:variable name="style"
select="@class"/>
              <xsl:if test="$numberVal != ''">
                <xsl:choose>
                  <xsl:when test="$style='num1'">
                    <xsl:value-of
select="format-number($numberVal,'###,')"/>
                  </xsl:when>
                  <xsl:when test="$style='cur1'">
                    <xsl:value-of
select="format-number($numberVal,$ltCurFormat)"/>
                  </xsl:when>
                  <!--<xsl:when test="$numberVal =
'-1' or $numberVal = '0'">
                    <xsl:text
xml:space="preserve">-</xsl:text>
                  </xsl:when>-->
                  <xsl:when test="$numberVal = '-1' or
$numberVal = '0'">
                    <xsl:text
xml:space="preserve">-</xsl:text>
                  </xsl:when>
                  <xsl:when test="$style='percent'">
                    <xsl:value-of
select="format-number($numberVal * 100,'0.00')"/>
                    <xsl:text>%</xsl:text>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of
select="format-number($numberVal,$ltNumFormat)"/>
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:if>
              <xsl:if test="$numberVal = ''">
                <xsl:text
xml:space="preserve">-</xsl:text>
              </xsl:if>
            </div>
          </nobr>
        </td>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="Cell[not(*)]">
    <xsl:for-each select="$msrs">
      <td align="right" style="overflow:none">
        <nobr>
          <div style="width:80px">

          </div>
        </nobr>
      </td>
      <!--<td>&#xa0;</td>-->
    </xsl:for-each>
  </xsl:template>


  <!--== ROW DATA   ==-->


  <!--== Columns  ==-->
  <xsl:template match="Columns" mode="Column">
    <xsl:apply-templates select="ColGrp[1]"
mode="Header">
      <!-- 0 for top level heading, 1 to cut it out
-->
      <xsl:with-param name="depth">
        <xsl:choose>
          <xsl:when test="$axisHeads='true'">
            <xsl:value-of select="0"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="1"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="ColGrp" mode="Header">
    <xsl:param name="depth" />
    <tr>
      <!-- the very first row needs a padding cell -->
      <!--<xsl:for-each
select="//ColGrp[count(ancestor::ColGrp)=$depth]">-->
      <xsl:for-each select="key('c', $depth)">
        <!--<td colspan="{count(.//Col)*$msrs}"
align="center" style="overflow:none">-->
        <td colspan="{count(.//Col)*$nrmr}"
align="center" style="overflow:none">
          <nobr>
            <div>
              <xsl:value-of select="@heading"/>
            </div>
          </nobr>
        </td>
      </xsl:for-each>
    </tr>
    <xsl:choose>
      <xsl:when test="ColGrp">
        <xsl:apply-templates select="ColGrp[1]"
mode="Header">
          <xsl:with-param name="depth"
select="$depth+1" />
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="Col[1]"
mode="colHead" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="Col" mode="colHead">
    <tr>
      <xsl:for-each select="$colSet">
        <td colspan="{$nrmr}" valign="top"
align="center" style="overflow:none">
          <nobr>
            <div>
              <xsl:value-of select="@heading"/>
            </div>
          </nobr>
        </td>
      </xsl:for-each>
    </tr>
    <tr valign="bottom">
      <xsl:for-each select="$colSet">
        <xsl:apply-templates select="/Report/Measures"
mode ="ColumnMeasure">
          <xsl:with-param name="pos"
select="position()" />
        </xsl:apply-templates>
      </xsl:for-each>
    </tr>
  </xsl:template>

  <xsl:template match="Measures" mode="ColumnMeasure">
    <xsl:param name="pos" />
    <xsl:for-each select="$msrs">
      <xsl:variable name="mPos">
        <xsl:value-of select="position()" />
      </xsl:variable>
      <td align="center">
        <nobr>
          <div class="action" style="width:90px;
overflow:none"  onclick="sortFullGrid({$mPos}, {$pos},
'{@class}')">
            <xsl:value-of select="@heading"/>
          </div>
        </nobr>
      </td>
    </xsl:for-each>
  </xsl:template>

  <!--== Columns  ==-->


  <!--== ROW MODE HEADING  ==-->

  <xsl:template match="Row" mode="heading">
    <tr>
      <xsl:if test="preceding-sibling::Row=false() or
number($sortCol) != 0">
        <xsl:apply-templates select="parent::RowGrp"
mode="heading" />
      </xsl:if>
      <xsl:variable name="theHeading">
        <xsl:call-template name="js-escapeAmp">
          <xsl:with-param name="string">
            <xsl:call-template name="js-escapeApos">
              <xsl:with-param name="string"
select="@heading" />
            </xsl:call-template>
          </xsl:with-param>
        </xsl:call-template>
      </xsl:variable>    
      <td title="{$theHeading}" style="overflow:none">
        <nobr>
          <div>           
            <xsl:value-of select="$theHeading"/>
          </div>
        </nobr>
      </td>
    </tr>
  </xsl:template>
  
  
  <xsl:template match="RowGrp" mode="heading">
    <xsl:if test="preceding-sibling::RowGrp=false() or
number($sortCol) != 0">
      <xsl:apply-templates select="parent::RowGrp"
mode="heading" />
    </xsl:if>
    <xsl:if test="parent::Rows=false() or
$axisHeads='true'">
      <td style="overflow:none; vertical-align:top"
title="{@heading}" valign="top">
        <xsl:if test="number($sortCol) = 0">
          <xsl:attribute name="rowspan">
            <xsl:value-of select="count(.//Row)"/>
          </xsl:attribute>
        </xsl:if>
        <nobr>
          <div>
            <xsl:value-of select="@heading"/>
          </div>
        </nobr>
      </td>
    </xsl:if>
  </xsl:template>



  <xsl:template name="js-escapeApos">
    <xsl:param name="string" />
    <xsl:call-template name="substitute">
      <xsl:with-param name="string"
select="normalize-space($string)" />
      <xsl:with-param name="find"
select='"&amp;apos;"' />
      <xsl:with-param name="replace" select='"&apos;"'
/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="js-escapeAmp">
    <xsl:param name="string" />
    <xsl:call-template name="substitute">
      <xsl:with-param name="string"
select="normalize-space($string)" />
      <xsl:with-param name="find" select='"&amp;amp;"'
/>
      <xsl:with-param name="replace" select='"&amp;"'
/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="substitute">
    <xsl:param name="string" />
    <xsl:param name="find" />
    <xsl:param name="replace" />
    <xsl:choose>
      <xsl:when test="$find and $string and
contains($string, $find)">
        <xsl:value-of
select="substring-before($string, $find)" />
        <xsl:value-of select="$replace" />
        <xsl:call-template name="substitute">
          <xsl:with-param name="string"
select="substring-after($string,$find)" />
          <xsl:with-param name="find" select="$find"
/>
          <xsl:with-param name="replace"
select="$replace" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$string" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


</xsl:stylesheet>





--- Manfred Staudinger <manfred.staudinger@xxxxxxxxx>
wrote:

> On 14/03/2008, Michael Kay <mike@xxxxxxxxxxxx>
> wrote:
> > > A lot has already been said and many suggestions
> have already
> >  > been made in this thread to speed up the
> processing of your
> >  > stylesheet, but since your stylesheet is rather
> >  > straightforward I doubt if any of the
> suggestions really



		
___________________________________________________________ 
Win a BlackBerry device from O2 with Yahoo!. Enter now. http://www.yahoo.co.uk/blackberry

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2011 All Rights Reserved.