[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] Ordering of Blocks based on Input/Output


Subject: Re: [xsl] Ordering of Blocks based on Input/Output
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Wed, 9 May 2001 15:09:27 +0100

Hi Francis,

> Quite right about the equivalence, though I don't know if doing
> count() on a node-set held in a variable will take as long as it
> would if gathering the node-set for the first time. Certainly
> "test='$todo'" is safer and better XSLT style.

It probably depends on whether the processor is lazy about evaluating
the variable. But of course a naive processor would still evaluate the
entirety of the $todo node set with that test, it's only an optimised
one that would know it could stop looking after one node. If you want
to 'assume no optimisation' (one of Mike Kay's tips) completely, then
really you should use test="$todo[1]".

Here's my crack at the problem, which is basically the same as yours
except that I'm applying templates and hence stepping through the
blocks one by one.

<!-- key to find the blocks that a block takes inputs from -->
<xsl:key name="inputs"
         match="connect/output/@block"
         use="../../input/@block" />

<xsl:template match="root">
   <order>
      <!-- apply templates to the first block that doesn't have any
           inputs -->
      <xsl:apply-templates
            select="system/block[not(key('inputs', name))][1]" />
   </order>
</xsl:template>

<xsl:template match="block">
   <xsl:param name="left"
              select="/root/system/block[count(.|current()) != 1]" />
   <xsl:copy-of select="." />
   <xsl:variable name="next"
                 select="$left[not(key('inputs', name) =
                                   $left/name)][1]" />
   <xsl:apply-templates select="$next">
      <xsl:with-param name="left"
                      select="$left[count(.|$next) != 1]" />
   </xsl:apply-templates>
</xsl:template>

The two solutions *will* give different results in certain situations
because of the different strategies they use.

I really don't know about the relative performance of the two - Dan,
you'd have to try it out.  My instinct is that going through the nodes
one by one would cause less nodes to be visited overall - it may seem
more efficient to collect and process them all at the same time, but
the collection process involves visiting a lot of nodes that shouldn't
be processed - the more you can cut down on this, the better.

Something that might improve performance is to have a pre-process that
sorts the blocks according to how many inputs they have.

And actually, the templates in both could take advantage of the
set:difference() extension function, which would make clearer what was
going on, and would improve performance if it was implemented
intelligently:

<xsl:template match="block">
   <xsl:param name="left"
              select="set:difference(/root/system/block, .)" />
   <xsl:copy-of select="." />
   <xsl:variable name="next"
                 select="$left[not(key('inputs', name) =
                                   $left/name)][1]" />
   <xsl:apply-templates select="$next">
      <xsl:with-param name="left"
                      select="set:differenct($left, $next)" />
   </xsl:apply-templates>
</xsl:template>

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/



 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



Current Thread
Keywords