Re: Ordering of Blocks based on Input/Output
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". 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))]" /> </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)]" /> <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)]" /> <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
PURCHASE STYLUS STUDIO ONLINE TODAY!
Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!
Download The World's Best XML IDE!
Accelerate XML development with our award-winning XML IDE - Download a free trial today!
Subscribe in XML format