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

Re: [xsl] Column Heads and Column Data problem ??


Subject: Re: [xsl] Column Heads and Column Data problem ??
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Fri, 22 Aug 2003 13:26:39 -0400

Dipesh,

As Markus said, since XSLT doesn't do "loops" in the commonly understood sense, you can't perform a loop to find a maximum.

Ordinarily, in XSLT, if a problem appears which can *only* be solved by looping, we use a recursive template (a template that calls itself) to perform the loop.

There are other ways to find maxima, however, including a couple of tricks. In your case, one of these is easy enough to use. Here's a way of using a sorting instruction to assign to a variable a copy of the node in the document with the most attributes (or rather, the first node of the set of nodes with the most attributes):

<xsl:variable name="mostattributes">
  <xsl:for-each select="/descendant::node()">
    <xsl:sort select="count(attribute::*)"
         order="descending" data-type="number"/>
    <xsl:if test="position()=1">
      <xsl:copy-of select="."/>
    </xsl:if>
  </xsl:for-each>
</xsl:variable>

Once we've done this, however, we run into another wrinkle (another reason your problem is tough): we need to process this node. This introduces another level of complexity, since XSLT 1.0 was designed not to allow compound processing in this way (that is, processing not a node from the input, but a node that has been generated by the stylesheet).

In such a case, one could consider "stretching" XSLT 1.0 by using an extension function to convert the result-tree-fragment generated by this routine (remember, it's a *copy* of the node in our source tree) into an XSLT node set, which we could then process. Here, however, there's another trick we can use to retrieve the actual node itself. Instead of copying the node into our variable, we can simply assign to the variable a value that identifies that node uniquely ... using this identifier to find our node. An XSLT processor can assign and use a unique identifier to any node in the input using the generate-id() function. So if we say, instead,

<xsl:variable name="mostattributes">
  <xsl:for-each select="/descendant::node()">
    <xsl:sort select="count(attribute::*)"
         order="descending" data-type="number"/>
    <xsl:if test="position()=1">
      <xsl:value-of select="generate-id()"/><!-- this line has changed! -->
    </xsl:if>
  </xsl:for-each>
</xsl:variable>

we can then retrieve the actual node we are interested by querying the document again, with an XPath predicate expression using our unique ID:

<xsl:variable name="mostattributes-node" select="//node()[generate-id() = $mostattributes]"/>

I know this is a very roundabout way of getting what ought to be a simple thing. It may comfort you to know (or maybe not) that this business of finding minima and maxima and so forth is recognized as a weak area in XSLT 1.0 -- this is why you will find it addressed in the EXSLT set of extension functions (see exslt.org), another thing you may want to investigate as you become more expert in this technology.

I hope this helps --
Wendell

At 10:22 PM 8/21/2003, you wrote:
Thanks a lot for replying and corroborating that the problem is tough....



====================================================================== Wendell Piez mailto:wapiez@xxxxxxxxxxxxxxxx Mulberry Technologies, Inc. http://www.mulberrytech.com 17 West Jefferson Street Direct Phone: 301/315-9635 Suite 207 Phone: 301/315-9631 Rockville, MD 20850 Fax: 301/315-8285 ---------------------------------------------------------------------- Mulberry Technologies: A Consultancy Specializing in SGML and XML ======================================================================


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




Current Thread
Keywords