BizTalk Utilities CV ,   Jobs ,   Code library
 
Home Page


Add/Edit your code items
Search the code library
Browse for the code library


XSLT
Format XML/XSL for Documentation
Find all xsl:variables that are in scope?
Binary Search in XSLT
Get the newest 5 articles out of hundreds -- a super efficient sort in XSLT
Dynamically change the encoding of your XSLT stylesheet
Identifying an attribute or a namespace node
Build a XPath expression for a node
Avoiding an XSLT Processor crash due to deep recursive processing
Conditional generation of a string in a single XPath expression
Re: Re: ABS function implemented as a single XPath expression
Re: ABS function implemented as a single XPath expression
ABS function implemented as a single XPath expression
XML to HTML text editor
Dynamically Selecting Which Element To Sort On Using Parameters
Avoid NaN in XPath sum() function
JScript Super Class To Handle XML Transformations
Test if a bit is on
Web Methodology (Layout Management)
Grouping an XML Node by First Letter
Dependent ComboBox in HTML build with XSLT


 
 

<< XQuery.NET and XML >>


By Dimitre Novatchev
First Posted 02/28/2001
Times viewed 479

In case you need a ""break"" from an xsl:for-each loop


Summary This is an example of a coding technique, necessary to simulate in XSLT the "break" (out of loop) statement of traditional programming languages.

Imagine you're inside an xsl:for-each loop and the node-list to be processed is very long (hundreds or thousands of nodes).   At the same time you know that during some point of the processing you'll be able to determine that all output generation has been already performed and there's absolutely no need to repeat the loop for the rest of the nodes.

This could happen even when we have processed just the first node from the node-list.   In conventional programming languages there's the C-like break; statement, which terminates and jumps out of the loop immediately.   

The question everybody seems to ask is:
What is the XSLT element, which is equivalent to the C 'break;' statement?. 

The answer is a discouraging:
None

This snippet presents a way to simulate break; functionality in XSLT.   

Let's start with a simple problem (submitted by Michael Lee in Januaryin the xslt-list http://sources.redhat.com/ml/xsl-list/2001-01/msg00151.html):   

I am writing a XSLT stylesheet to transform a simple table from HTML to WML. However, the columns attribute is required for the table element in the latter format.  Therefore, I must be able to determine the maximum number of cells in the rows and use it as the value for the columns attribute.   A simple approach is to sort all rows according to the descending number of their cells and then take the first node in the sorted nodelist -- its number of cells is the value of the columns attribute.   

The following code does exactly this:
<xsl:template name=maxCols>
  <xsl:for-each select=//tr>
    <xsl:sort select=count(td) order=descending />
    <xsl:if test=position() = 1>
      <xsl:value-of select=. />
    </xsl:if>
  </xsl:for-each>
</xsl:template>

This is a classical case where a break statement would be very useful -- the repeated processing produces the necessary result on the very first iteration -- then the time for the rest is just wasted.   Because there isn't a xsl:break element in XSLT, we will have to simulate it.   

The solution, as originally described by Jeni Tennison, is not to use an xsl:for-each construct at all, but to replace it with a (recursively applied) template:
<
xsl:template name=maxCols>
  <
xsl:apply-templates select=//tr[1] mode=maxCols />
</
xsl:template>

<
xsl:template match=tr mode=maxCols>
  <
xsl:variablename=next
    select=following-sibling::tr[count(td) &gt;count(current()/td)][1] />
  <xsl:choose>
    <xsl:when test=$next>
      <xsl:apply-templates select=$next mode=maxCols />
    </xsl:when>
    <xsl:otherwise><xsl:value-of select=count(td) /></xsl:otherwise>
  </xsl:choose>
</xsl:template>

What is the underlying logic here?  

 The template with mode=maxCols is applied initially only on the first tr element in the xml document. It constructs $next -- a node-set of all remaining tr elements that still have a greater number of td children than the current node.   The (same) template is re-applied only in case $next is not empty and there really is still work to be done.   In case there are no tr elements with greater number of td children, then the result is immediately output and this is the end of processing.   Exactly like break, isn't it?

Additional information


Rate this article on a scale of 1 to 10 (0 votes, average 0)

Your vote :  

<< XQuery.NET and XML >>





Leave a comment for this article
Your name
Your email (optional)
Your comment
Optional: Upload an attachment
Enter the code shown:

 
 

    Email TopXML