Subject: Re: [xsl] Finding the maximun number of nodes From: Dimitre Novatchev <dnovatchev@xxxxxxxxx> Date: Fri, 5 Jan 2001 03:43:05 -0800 (PST) |
Thanks to Jeni and Mike for pointing out the error in my "solution". Now here's what seems to be still the simplest of the proposed so far solutions (and at last it works... :o) ): <xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' > <xsl:output method="text"/> <xsl:template match="/"> <xsl:variable name="maxNumbers"> <xsl:for-each select="//table[@ID='2']/tr"> <xsl:if test="count(//table[@ID='2']/tr[count(td) > count(current()/td)]) = 0"> <xsl:value-of select="count(td)"/>: </xsl:if> </xsl:for-each> </xsl:variable> <xsl:value-of select="substring-before($maxNumbers,':')"/> </xsl:template> </xsl:stylesheet> Dimitre. Jeni Tennison wrote: Dimitre wrote: > Michael Lee wrote: >> 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. > > Use: > > <xsl:key name="numCells" match="tr" use="count(td)"/> > > <xsl:template name="maxCols"> > <xsl:for-each select="//tr[not(key('numCells', count(td) + 1))]"> > <xsl:value-of select="count(td)"/> > </xsl:for-each> > </xsl:template> This only works if there are now rows that have more than one cell more than any other. In these cases, the key won't return any nodes for some of the shorter rows, and therefore the number of cells in these rows will be given. For example: <table> <tr><td>(1,1)</td></tr> <tr><td>(2,1)</td><td>(2,2)</td><td>(2,3)</td></tr> <tr><td>(3,1)</td><td>(3,2)</td></tr> <tr><td>(4,1)</td><td>(4,2)</td><td>(4,3)</td><td>(4,4)</td><td>(4,5)</td></tr> </table> means that the maxCols template returns '35' - a '3' from the length of the second row, and a '5' from the length of the fourth. Better is: <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 sorts all the rows by the number of cells they have in them, in descending order, then selects the first from that list (the one with the most cells) and tells you how many cells there are in it. Alternatively you can step through the rows recursively. This is more efficient if the table is a long one. There are lots of ways to step through recursively. Here's one that applies templates to the first row in a 'maxCols' mode. Within the template, if a row finds a following row that has more cells in it, then it applies templates to that row in 'maxCols' mode. If it can't find one with more cells in, then it knows its the maximum, and tells you how many cells its got. <xsl:template name="maxCols"> <xsl:apply-templates select="//tr[1]" mode="maxCols" /> </xsl:template> <xsl:template match="tr" mode="maxCols"> <xsl:variable name="next" select="following-sibling::tr[count(td) > 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> In this version, again the templates are applied to only the first row in the table. Each row works out the maximum of the rest of the rows by applying templates to the next row in the table. If this maximum is more than the number of cells in it, then it tells you the maximum from the rest of the rows; if it has more cells itself, then it tells you how many cells it has. <xsl:template name="maxCols"> <xsl:apply-templates select="//tr[1]" mode="maxCols" /> </xsl:template> <xsl:template match="tr" mode="maxCols"> <xsl:variable name="max"> <xsl:apply-templates select="following-sibling::tr[1]" mode="maxCols" /> </xsl:variable> <xsl:choose> <xsl:when test="$max > count(td)"> <xsl:value-of select="$max" /> </xsl:when> <xsl:otherwise><xsl:value-of select="count(td)" /></xsl:otherwise> </xsl:choose> </xsl:template> This version uses a parameter to store the rows that have to be looked at. This is set to all the rows at the beginning. If there's only one row, it tells you how many cells there are in that row. If there are more, it works out the maximum number of cells in all the rows aside from the first one (by calling itself with a parameter with all the rows aside from the first), and then compares that number with the number of cells in the first row in the list. If the first row in the list has more cells, it tells you that number. If the maximum from the rest of the rows was more, it tells you that. <xsl:template name="maxCols"> <xsl:param name="rows" select="//tr" /> <xsl:choose> <xsl:when test="count($rows) = 1"> <xsl:value-of select="count(td)" /> </xsl:when> <xsl:otherwise> <xsl:variable name="max"> <xsl:call-template name="maxCols"> <xsl:with-param name="rows" select="$rows[position() > 1]" /> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$max > count($rows[1]/td)"> <xsl:value-of select="$max" /> </xsl:when> <xsl:otherwise> <xsl:value-of select="count($rows[1]/td)" /> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:template> Which of these is best depends quite a lot on the optimisations that are built into your XSLT processor. I hope that helps, Jeni --- Jeni Tennison http://www.jenitennison.com/ __________________________________________________ Do You Yahoo!? Yahoo! Photos - Share your holiday photos online! http://photos.yahoo.com/ XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: [xsl] Finding the maximun numbe, Kay Michael | Thread | Re: [xsl] Finding the maximun numbe, David Carlisle |
RE: [xsl] sorting, Krithiga Subramanian | Date | RE: [xsl] Re: topological sort, Kay Michael |
Month |