xsl-list
[Top] [All Lists]

Re: [xsl] Slow XSLT

2008-02-29 16:15:12
Hi Manfred,

Thanks for your reply.

I think I can now understand what David poited out
i.e. that when using // can be very costly. 

However, I thought that by using // followed by a
predicate ( //ColGrp[count(ancestor::ColGrp)=$depth]
), I would go straight to only those inner most ColGrp
elements parent of the Col elements.

There is one problem with your approach though. You
are assuming that there will always be only two ColGrp
like this:

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

<ColGrp heading="Quarter">
   <ColGrp heading="2003">
     <Col heading="Quarter 1" />
     <Col heading="Quarter 2" />
     <Col heading="Quarter 3" />
     <Col heading="Quarter 4" />
   </ColGrp>
</ColGrp>

But That is not the case. The xml can have as many
nested ColGrp as necessary. For instance:

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

or

<ColGrp heading="Quarter">
   <ColGrp heading="2003">
     <ColGrp heading="Name">
       <ColGrp heading="Charity Report IO">
          <Col heading="Quarter 1" />
          <Col heading="Quarter 2" />
          <Col heading="Quarter 3" />
          <Col heading="Quarter 4" />
       </ColGrp>
    </ColGrp>
   </ColGrp>
</ColGrp>

As you can see, there can be many ColGroup levels
nested inside each other. Therefore, we need an
approach that is dynamic i.e. no matter how many
nested ColGrp there are, it will produce the right
output.





As David has pointed out the // operator is very
costly. So I have
replaced them by explicit xpath expressions and
would be interested
about the performance now. However I could not
resist to replace
  count(.//Col)*$msrs
by
  count(Col)*$msrs
Most of the rest I have l left unchanged. I also
noticed the
depreciated <nobr>, which should be replaced by css
white-space:
nowrap.

Manfred

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
<xsl:param name="axisHeads" select="'false'" />
<!--
java -jar D:\Programme\Saxon6\saxon.jar slow.xml
slow.xsl
-->
<xsl:output indent="yes"/>

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

 <xsl:template match="Reports">
 <html>
 <body>
   <xsl:apply-templates/>
 </body>
 </html>
 </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="/Reports/Report/Columns/ColGrp/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/ColGrp/ColGrp/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="/Reports/Report/Columns/ColGrp/ColGrp/Col">
       <xsl:apply-templates
select="/Reports/Report/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}, '{(_at_)class}')">
           <xsl:value-of select="@heading"/>
         </div>
       </nobr>
     </td>
   </xsl:for-each>
 </xsl:template>

</xsl:stylesheet>

On 29/02/2008, Cleyton Jordan
<cleytonjordan(_at_)yahoo(_dot_)co(_dot_)uk> wrote:
Hi David,



 >without following in detail what processing you
are
 >doing it's hard to
 > say

sorry got to dash, perhaps someone else can say
more!

 >David



I need to build a nested heading Rows/Columns (<TR>
 and <TD>). The output should look like this for the
 2003 heading:


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

Total Pages  Cost


 <ColGrp heading="Quarter">
  <ColGrp heading="2003">
    <Col heading="Quarter 1" />
    <Col heading="Quarter 2" />
    <Col heading="Quarter 3" />
    <Col heading="Quarter 4" />
  </ColGrp>
 </ColGrp>


I use the xpath below to get me to the inner most
 ColGrp (parent of Col elements).

 Normally $depth = 1

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


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

 So, I go to the ancestor:ColGrp whose depth = 1

 This will produce the first <TD>s

 2003      2004

 Then all the Col elements will produce the second
row
 with all the <TD>s

 Quarter 1   Quarter 2      Quarter 3       Quarter
4

 And lastly, for each Col element I have to go back
to
 the Measure elements to produce the final Row which
 will be the same for all the Col elements


 Total Pages Cost Total Pages Cost Total Pages Cost

Total Pages Cost

 Therefore, this is the output I get with my XSLT
but
 it is too slow for big xml docs.

                         2003
 Quarter 1     Quarter 2    Quarter 3        Quarter
4

Total Pages Cost Total Pages Cost Total Pages Cost


Cheers

 C





      __________________________________________________________
Sent from Yahoo! Mail.
A Smarter Inbox. http://uk.docs.yahoo.com/nowyoucan.html

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>