Re: [xsl] Slow XSLT

Subject: Re: [xsl] Slow XSLT
From: Cleyton Jordan <cleytonjordan@xxxxxxxxxxx>
Date: Fri, 29 Feb 2008 16:13:32 +0000 (GMT)
Hi David,

Thanks for your reply.

This is what you said:
"
Without knowing your input or problem it's hard to
give specific
 advice,
except the advice that // should normally be avoided,
either by using
explict paths or by the use of keys.
"

My input is the XML I have shown in my previous post.
Please see below.

Please note that the reason I am using //ColGrp
is because I do not know how many ColGrp elements I
will have. It could be two, three or more. So I need
to know how many ancestor ColGrp elements I have based
on the $depth value which normally starts from 1

//ColGrp[count(ancestor::ColGrp)=$depth

//ColGrp[count(ancestor::ColGrp)= 1

<Columns>
    <ColGrp heading="Quarter">
      <ColGrp heading="2003">
        <ColGrp heading="Name">
         <Col heading="Quarter 1" />
         <Col heading="Quarter 2" />
        </ColGrp>
      </ColGrp>
    </ColGrp>
</Columns>

Please could you provide an example of how I could use
a key to speed up the process?

This is a sample of the desired output using only the
2003 ColGrp column not the 2004 

                   2003                
    Quarter 1        Quarter 2        Quarter 3 
Total Pages Cost Total Pages Cost Total Pages Cost 

Also, you said:

"for the inner loop you are searching the document for
Col elements then
each time searching the document again for measures
elements (this
search returns the same nodes each time, so it may be
worth saving this
in  variable before the Col loop
"

You are right. So, are you suggesting that I should
use something like this:

<xsl:variable name="msrsNodeSet"
select="Reports/Report/Measures/Measure"/>

The reason why I need to apply template to every
Measure elements is because each Measure element is
the headin of the inner most <td>s.


(ColGrp)           Quarter 1        
(Measure)        Total Pages Cost  

I would appreciate if you could show me some examples
of how I could improve this XSLT.

Cheers

C
===
------------------------------

Date: Fri, 29 Feb 2008 00:02:27 GMT
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
From: David Carlisle <davidc@xxxxxxxxx>
Subject: Re: [xsl] Slow XSLT
Message-Id:
<200802290002.m1T02RPh001273@xxxxxxxxxxxxxxxxxxx>

It's not surprising that it is slow. // is an
expensive operation it
means search every node in the document, and you are
doing it in a
nested fashion, so unless your system rewrites your
stylesheet if your
time at least the square (or cube ?) of the number of
nodes in your
document which can get slow...

Without knowing your input or problem it's hard to
give specific
 advice,
except the advice that // should normally be avoided,
either by using
explict paths or by the use of keys.

for the outer //ColGrp, if you know where they are
then using 
/a/b/c/ColGrp
is likely to be quicke, as it saves searching the
entire document for
them.

for the inner loop you are searching the document for
Col elements then
each time searching the document again for measures
elements (this
search returns the same nodes each time, so it may be
worth saving this
in  variable before the Col loop, although your xslt
system may be able
to do that rewrite automatically,
do you really need to apply templates to every
Measures eleemnt in the
document, for every Col in the document? this seems
unlikely but as I
don't know what the transform is I can't suggest any
changes.

David

====

Date: Thu, 28 Feb 2008 22:59:48 +0000 (GMT)
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
From: Cleyton Jordan <cleytonjordan@xxxxxxxxxxx>
Subject: Slow XSLT
Message-ID:
<323507.70372.qm@xxxxxxxxxxxxxxxxxxxxxxxxxxx>

Hi,

I am using XSLT 1.0 and IE6

I have written the XSLT below and it works fine.
However, when the XML has lots of RowGrp elements then
it becomes quite slow to transform.

The difficulty that I am having is to find a way to
speed it up. I think there could be two problems with
my XSLT:

1 - Recursion in the ColGrp Template mode="header"  

<xsl:for-each
select="//ColGrp[count(ancestor::ColGrp)=$depth]">

2 - Also, when I am in the Col Template I have to go
back to the measures element for each Col

<xsl:for-each select="//Col">
  <xsl:apply-templates select="//Measures">
    <xsl:with-param name="pos" select="position()" />
  </xsl:apply-templates>
</xsl:for-each>

I would appreciate if someone could sched some light.
I have read Jeni's XSLT pages (key and grouping) but
have not found any posts or example similar to mine.

Cheers

C
===========================
XML
<Reports>
<Report xmlns="">
  <Measures>
    <Measure idx="1" heading="Total Pages" />
    <Measure idx="2" heading="Cost" />
  </Measures>
  <Columns>
    <ColGrp heading="Quarter">
      <ColGrp heading="2003">
        <Col heading="Quarter 1" />
        <Col heading="Quarter 2" />
        <Col heading="Quarter 3" />
        <Col heading="Quarter 4" />
      </ColGrp>
      <ColGrp heading="2004">
        <Col heading="Quarter 1" />
        <Col heading="Quarter 2" />
        <Col heading="Quarter 3" />
        <Col heading="Quarter 4" />
      </ColGrp>
    </ColGrp>
    <!--===TOTALS====-->
    <ColGrp>
      <ColGrp>
        <Col heading="Total" />
      </ColGrp>
    </ColGrp>
  </Columns>
</Report>
</Reports>

==============================

XSLT

<xsl:param name="axisHeads" select="'false'" />

  <xsl:variable name="msrs">
    <xsl:choose>
      <xsl:when test="//Measure">
        <xsl:value-of select="count(//Measure)"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="1"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

 <xsl:template match="Reports">
    <xsl:apply-templates
select="Report"></xsl:apply-templates>
  </xsl:template>
  
  <xsl:template match="Report" >
      <!-- Top -->
      <div id="g1" style="position: absolute; top:
0px; left: 0px; width: 400px; height: 12px">
        <table class="grdTop" border="0"
cellspacing="1" cellpadding="0">
          <tbody>
            <xsl:apply-templates select="Columns" />
          </tbody>
        </table>
      </div>
   </xsl:template>

  <xsl:template match="Columns">
    <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]">
          <td colspan="{count(.//Col)*$msrs}"
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="ancestor::Columns//Col">
        <td colspan="{$msrs}" valign="top"
align="center" style="overflow:none">
          <nobr>
            <!-- 2003/2004 -->
            <div>
              <xsl:value-of select="@heading"/>
            </div>
          </nobr>
        </td>
      </xsl:for-each>
    </tr>
    <tr valign="bottom">
      <xsl:for-each select="//Col">
        <xsl:apply-templates select="//Measures">
          <xsl:with-param name="pos"
select="position()" />
        </xsl:apply-templates>
      </xsl:for-each>
    </tr>
  </xsl:template>

  <xsl:template match="//Measures">
    <xsl:param name="pos" />
    <xsl:for-each select="Measure">
      <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>

     
___________________________________________________________

Rise to the challenge for Sport Relief with Yahoo! For
Good  

http://uk.promotions.yahoo.com/forgood/




		
___________________________________________________________ 
Yahoo! Photos  NEW, now offering a quality print service from just 8p a photo http://uk.photos.yahoo.com

Current Thread