xslt - XSL recursive traverse based on variable -


i'm trying head around xsl recursion. need build html table based on xml using xslt cell tags position mapped string attribute called name formatted "row.column".

i'm trying recursively start last cell , count first cell ( 0.0 ) , start building table. reason cells may span several cell positions. use in html cannot process cells in for-each loop. last cell identified table attributes; bodyrowcount , columncount.

the xml looks this

<table headerrowcount="0" footerrowcount="0" bodyrowcount="4" columncount="2" >  	<cell self="ucd8iceei0" name="0:0" rowspan="1" columnspan="1">  		<content>1</content>  	</cell>  	<cell self="ucd8iceei1" name="1:0" rowspan="1" columnspan="1">  		<content>2</content>  	</cell>  	<cell self="ucd8iceei2" name="2:0" rowspan="1" columnspan="2>  		<content>3</content>  	</cell>  	<cell self="ucd8iceei3" name="3:0" rowspan="1" columnspan="1">  		<content>4</content>  	</cell>  	<cell self="ucd8iceei4" name="0:1" rowspan="1" columnspan="1">  		<content>5</content>  	</cell>  	<cell self="ucd8iceei6" name="2:1" rowspan="1" columnspan="1">  		<content>7</content>  	</cell>  	<cell self="ucd8iceei7" name="3:1" rowspan="1" columnspan="1">  		<content>8</content>  	</cell>  </table>

the result should

<table>  	<tr>   		<td>1</td> 	<td>5</td>   	</tr>  	<tr>   		<td> colspan="2">2</td>  	</tr>  	<tr>   		<td>3</td> <td>7</td>   	</tr>  	<tr>   		<td>4</td> 	<td>8</td>   	</tr>  </table>

the xls in pseudo format below. tried pass arguments start in case @ cell name 4.2 seems illigal pass argument based on attributes, surely must possible?

<xsl:template match="table"> 	  	<table>  		<xsl:apply-templates select="cell[@name = concat(@bodyrowcount,':',columncount)']"/>  	</table>  </xsl:template>    <xsl:template name="cell[@name='0.0">  found first cell, start first row in table  <tr><td colspan=<xsl:value-of select=(concat(3&quot,@columnspan,3&quot))   rowspan=<xsl:value-of select=(concat(3&quot,@rowspan,3&quot))> row content here  </td></tr>  </xsl:template>    <xsl:template name="cell[@name='0.*">  	call template 'row-1, column max  	<xsl:apply-templates select="cell[@name = 'row-1:maxcolumn']">   	 new row goes here  	 <tr><td colspan=<xsl:value-of select=(concat(3&quot,@columnspan,3&quot))   rowspan=<xsl:value-of select=(concat(3&quot,@rowspan,3&quot))> row content here  </td></tr>  </xsl:template>    <xsl:template name="cell[@name='*.*">  	call template 1 column before  	<xsl:apply-templates select="cell[@name = same row:column-1']">   	<td colspan=<xsl:value-of select=(concat(3&quot,@columnspan,3&quot))   rowspan=<xsl:value-of select=(concat(3&quot,@rowspan,3&quot))> row content here  </td>  </xsl:template>

i looking on how start recursive loop in 4.2 go 0.0, build table traversing positions , inserting cell value if 1 exist ?

you don't need recursion this. xslt (1.0) way like:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform">     <xsl:key name="rows" match="cell" use="substring(@name,1,1)"/>     <xsl:template match="table">         <table border="1">             <xsl:apply-templates select="cell[generate-id() = generate-id(key('rows',substring(@name,1,1)))]" mode="row">                 <xsl:sort select="@name"/>             </xsl:apply-templates>         </table>     </xsl:template>     <xsl:template match="cell" mode="row">         <xsl:variable name="row" select="substring(@name,1,1)"/>         <tr>             <td>                 <xsl:if test="not(following-sibling::cell[substring(@name,1,1) = $row])">                     <xsl:attribute name="colspan">2</xsl:attribute>                 </xsl:if>                 <xsl:value-of select="."/>             </td>             <xsl:apply-templates select="following-sibling::cell[substring(@name,1,1) = $row]" mode="secondcell"/>         </tr>     </xsl:template>     <xsl:template match="cell" mode="secondcell">         <td>             <xsl:value-of select="."/>         </td>     </xsl:template> </xsl:stylesheet> 

how done?
- building key on rows information (first character of name attribute)
- apply template rows on found cells
- save first character of name attribute in variable
- check if following sibling same first character exists
- if not, add colspan (no need information xml, used)
- if so, apply template second cell

instead of <xsl:value-of select="."/> can use <xsl:apply-templates/>. thats not obvious beginners more straight xslt. purists demand on it.

edit @christian: key uses first character of attribute "name", returns 1 "cell" element each first character found. 1 each row, can figure out rows without having information explicit in xml tree. additional cells in row detected, if there following cells same first character.

edit @christian: xslt 2.0 solution ever shorter , doesn't need key:

<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform" xmlns:xs="http://www.w3.org/2001/xmlschema" xmlns:fn="http://www.w3.org/2005/xpath-functions">     <xsl:template match="table">         <table border="1">             <xsl:for-each-group select="cell" group-by="substring(@name,1,1)">                 <tr>                     <xsl:for-each select="current-group()">                         <td>                             <xsl:if test="count(current-group())=1">                                 <xsl:attribute name="colspan">2</xsl:attribute>                             </xsl:if>                             <xsl:value-of select="."/>                         </td>                     </xsl:for-each>                 </tr>             </xsl:for-each-group>         </table>     </xsl:template> </xsl:stylesheet>   

Comments

Popular posts from this blog

java - Date formats difference between yyyy-MM-dd'T'HH:mm:ss and yyyy-MM-dd'T'HH:mm:ssXXX -

c# - Get rid of xmlns attribute when adding node to existing xml -