Using XSLT, how can I create a table with elements at the node attribute position?

Given the following XML:

<items> <item> <name>A</name> <address>0</address> <start>0</start> <size>2</size> </item> <item> <name>B</name> <address>1</address> <start>2</start> <size>4</size> </item> <item> <name>C</name> <address>2</address> <start>5</start> <size>2</size> </item> </items> 

I want to generate the following output, including colspan

 +---------+------+------+------+------+------+------+------+------+ | Address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +---------+------+------+------+------+------+------+------+------+ | 0 | | | | | | | A | +---------+------+------+------+------+------+------+------+------+ | 1 | | | B | | | +---------+------+------+------+------+------+------+------+------+ | 2 | | C | | | | | | +---------+------+------+------+------+------+------+------+------+ | 3 | | | | | | | | | +---------+------+------+------+------+------+------+------+------+ 

I think I could accomplish this with the xslt mutable variable, but alas, there is no such thing.

Is it possible? How?

Edit:

Two more requirements:

  • It should also be possible for two elements to exist at the same address.
  • Empty addresses can exist and must be generated at the output

For instance:

 <items> <item> <name>D</name> <address>0</address> <start>0</start> <size>2</size> </item> <item> <name>E</name> <address>0</address> <start>3</start> <size>4</size> </item> <item> <name>F</name> <address>7</address> <start>5</start> <size>2</size> </item> </items> 

Must issue:

 +---------+------+------+------+------+------+------+------+------+ | Address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +---------+------+------+------+------+------+------+------+------+ | 0 | | E | | D | +---------+------+------+------+------+------+------+------+------+ | 1 | | | | | | | | | +---------+------+------+------+------+------+------+------+------+ | 2 | | | | | | | | | +---------+------+------+------+------+------+------+------+------+ | 3 | | | | | | | | | +---------+------+------+------+------+------+------+------+------+ | 4 | | | | | | | | | +---------+------+------+------+------+------+------+------+------+ | 5 | | | | | | | | | +---------+------+------+------+------+------+------+------+------+ | 6 | | | | | | | | | +---------+------+------+------+------+------+------+------+------+ | 7 | | F | | | | | | +---------+------+------+------+------+------+------+------+------+ 

The output format (text / html) does not matter.

+4
source share
6 answers

Here is the new XSLT 2.0 stylesheet for the revised question. In my opinion, this is disgusting, but it should do the job:

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xsd" version="2.0"> <xsl:output method="html" indent="yes"/> <xsl:variable name="cols" as="xsd:integer*" select="reverse(0 to (max(/items/item/xsd:integer((start + size - 1))) + 1))"/> <xsl:variable name="addresses" as="xsd:integer*" select="0 to max(/items/item/xsd:integer(address))"/> <xsl:template match="/"> <html lang="en"> <head> <title>Example</title> </head> <body> <xsl:apply-templates/> </body> </html> </xsl:template> <xsl:template match="items"> <table border="1"> <thead> <tr> <th>Address</th> <xsl:for-each select="$cols"> <th width="100"> <xsl:value-of select="."/> </th> </xsl:for-each> </tr> </thead> <tbody> <xsl:variable name="items" as="element(item)*" select="item"/> <xsl:for-each select="$addresses"> <tr> <th> <xsl:value-of select="."/> </th> <xsl:variable name="cells" as="element(cell)*"> <xsl:for-each select="$items[address = current()]"> <xsl:sort select="xsd:integer(start) + xsd:integer(size)" order="descending"/> <cell> <xsl:copy-of select="name"/> <start><xsl:value-of select="start + size - 1"/></start> <colspan><xsl:value-of select="size"/></colspan> </cell> </xsl:for-each> </xsl:variable> <xsl:for-each select="$cols"> <xsl:variable name="cell" select="$cells[start = current()]"/> <xsl:choose> <xsl:when test="$cell"> <td colspan="{$cell/colspan}"> <xsl:value-of select="$cell/name"/> </td> </xsl:when> <xsl:when test="$cells[current() &lt; start and current() &gt;= (start - colspan + 1)]"></xsl:when> <xsl:otherwise> <td>&#160;</td> </xsl:otherwise> </xsl:choose> </xsl:for-each> </tr> </xsl:for-each> </tbody> </table> </xsl:template> </xsl:stylesheet> 

When applied from Saxon 9 to the last XML input, the result is as follows:

 <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Example</title> </head> <body> <table border="1"> <thead> <tr> <th>Address</th> <th width="100">7</th> <th width="100">6</th> <th width="100">5</th> <th width="100">4</th> <th width="100">3</th> <th width="100">2</th> <th width="100">1</th> <th width="100">0</th> </tr> </thead> <tbody> <tr> <th>0</th> <td>&nbsp;</td> <td colspan="4">E</td> <td>&nbsp;</td> <td colspan="2">D</td> </tr> <tr> <th>1</th> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <th>2</th> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <th>3</th> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <th>4</th> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <th>5</th> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <th>6</th> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <th>7</th> <td>&nbsp;</td> <td colspan="2">F</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr> </tbody> </table> </body> </html> 
+1
source

Here is the XSLT 2.0 style sheet:

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xsd" version="2.0"> <xsl:output method="html" indent="yes"/> <xsl:variable name="cols" as="xsd:integer*" select="reverse(0 to (max(/items/item/xsd:integer((start + size - 1))) + 1))"/> <xsl:template match="/"> <html lang="en"> <head> <title>Example</title> </head> <body> <xsl:apply-templates/> </body> </html> </xsl:template> <xsl:template match="items"> <table border="1"> <thead> <tr> <th>Address</th> <xsl:for-each select="$cols"> <th> <xsl:value-of select="."/> </th> </xsl:for-each> </tr> </thead> <tbody> <xsl:apply-templates/> </tbody> </table> </xsl:template> <xsl:template match="item"> <xsl:variable name="item" as="element(item)" select="."/> <tr> <td> <xsl:value-of select="address"/> </td> <xsl:for-each select="$cols[. > $item/(start + size - 1)]"> <td>&#160;</td> </xsl:for-each> <td colspan="{size}"> <xsl:value-of select="name"/> </td> <xsl:for-each select="$cols[. &lt; $item/start]"> <td>&#160;</td> </xsl:for-each> </tr> </xsl:template> </xsl:stylesheet> 

You can run XSLT 2.0 styles with Saxon 9 or with AltovaXML tools.

[edit] If you need an XSLT 1.0 solution, but you can use exsl: node -set, find below an attempt to translate the XSLT 2.0 approach back into the XSLT 1.0 stylesheet:

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="exsl" version="1.0"> <xsl:output method="html" indent="yes"/> <xsl:variable name="adds-rtf"> <xsl:for-each select="/items/item"> <add> <xsl:value-of select="start + size - 1"/> </add> </xsl:for-each> </xsl:variable> <xsl:variable name="max"> <xsl:for-each select="exsl:node-set($adds-rtf)/add"> <xsl:sort select="." data-type="number" order="descending"/> <xsl:if test="position() = 1"> <xsl:value-of select="."/> </xsl:if> </xsl:for-each> </xsl:variable> <xsl:variable name="cols-rtf"> <xsl:call-template name="make-columns"> <xsl:with-param name="max" select="$max + 1"/> </xsl:call-template> </xsl:variable> <xsl:template name="make-columns"> <xsl:param name="max"/> <xsl:if test="$max > -1"> <col> <xsl:value-of select="$max"/> </col> <xsl:call-template name="make-columns"> <xsl:with-param name="max" select="$max - 1"/> </xsl:call-template> </xsl:if> </xsl:template> <xsl:variable name="cols" select="exsl:node-set($cols-rtf)/col"/> <xsl:template match="/"> <html lang="en"> <head> <title>Example</title> </head> <body> <xsl:apply-templates/> </body> </html> </xsl:template> <xsl:template match="items"> <table border="1"> <thead> <tr> <th>Address</th> <xsl:for-each select="$cols"> <th> <xsl:value-of select="."/> </th> </xsl:for-each> </tr> </thead> <tbody> <xsl:apply-templates/> </tbody> </table> </xsl:template> <xsl:template match="item"> <xsl:variable name="item" select="."/> <tr> <td> <xsl:value-of select="address"/> </td> <xsl:for-each select="$cols[. > ($item/start + $item/size - 1)]"> <td>&#160;</td> </xsl:for-each> <td colspan="{size}"> <xsl:value-of select="name"/> </td> <xsl:for-each select="$cols[. &lt; $item/start]"> <td>&#160;</td> </xsl:for-each> </tr> </xsl:template> </xsl:stylesheet> 
+3
source

Just as simple:

I. XSLT 2.0 Solution :

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"> <xsl:output omit-xml-declaration="yes" method="html" indent="yes" encoding="utf-8"/> <xsl:variable name="vMaxCols" select= "xs:integer(max(/*/*/(start + size)))+1 "/> <xsl:template match="/*"> <html> <table border="1"> <thead> <tr> <th>Address</th> <xsl:for-each select="1 to $vMaxCols"> <th> <xsl:value-of select="$vMaxCols -."/> </th> </xsl:for-each> </tr> </thead> <tbody> <xsl:apply-templates/> </tbody> </table> </html> </xsl:template> <xsl:template match="item"> <tr> <td width="100"><xsl:sequence select="address"/></td> <xsl:for-each select="1 to $vMaxCols - xs:integer(start+size)"> <td width="100">&#xA0;</td> </xsl:for-each> <td width="100" colspan="{size}"> <xsl:value-of select="name"/> </td> <xsl:for-each select="1 to start"> <td width="100">&#xA0;</td> </xsl:for-each> </tr> </xsl:template> </xsl:stylesheet> 

II. XSLT 1.0 solution using FXSL :

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common" xmlns:f="http://fxsl.sf.net/" xmlns:myFun="f:myFun" exclude-result-prefixes="ext f myFun" > <xsl:import href="maximum.xsl"/> <xsl:import href="iter.xsl"/> <xsl:output method="html" indent="yes" encoding="utf-8"/> <xsl:variable name="vrtfEndCols"> <xsl:for-each select="/*/*"> <ec><xsl:value-of select="start+size+1"/></ec> </xsl:for-each> </xsl:variable> <xsl:variable name="vEndCols" select="ext:node-set($vrtfEndCols)/*"/> <xsl:variable name="vMaxCols"> <xsl:call-template name="maximum"> <xsl:with-param name="pList" select="$vEndCols"/> </xsl:call-template> </xsl:variable> <myFun:printTh/> <myFun:printEmpty/> <myFun:header><x></x></myFun:header> <xsl:variable name="vFunPrintTh" select= "document('')/*/myFun:printTh[1]"/> <xsl:variable name="vFunPrintEmpty" select= "document('')/*/myFun:printEmpty[1]"/> <xsl:variable name="vIterHeader" select="document('')/*/myFun:header[1]"/> <xsl:variable name="vrtfHeader"> <xsl:call-template name="iter"> <xsl:with-param name="pTimes" select="$vMaxCols"/> <xsl:with-param name="pFun" select="$vFunPrintTh"/> <xsl:with-param name="pX" select="$vIterHeader"/> </xsl:call-template> </xsl:variable> <xsl:template match="/*"> <html> <head /> <table border="1"> <thead> <tr> <th>Address</th> <xsl:copy-of select= "ext:node-set($vrtfHeader)/* [position() > 1] "/> </tr> </thead> <tbody> <xsl:apply-templates/> </tbody> </table> </html> </xsl:template> <xsl:template match="item"> <tr> <td width="100"><xsl:value-of select="address"/></td> <xsl:variable name="vrtfLeftBlank"> <xsl:call-template name="iter"> <xsl:with-param name="pTimes" select="$vMaxCols -(start+size)"/> <xsl:with-param name="pFun" select="$vFunPrintEmpty"/> <xsl:with-param name="pX" select="$vIterHeader"/> </xsl:call-template> </xsl:variable> <xsl:copy-of select= "ext:node-set($vrtfLeftBlank)/* [position() > 1] "/> <td width="100" colspan="{size}"> <xsl:value-of select="name"/> </td> <xsl:variable name="vrtfRightBlank"> <xsl:call-template name="iter"> <xsl:with-param name="pTimes" select="start"/> <xsl:with-param name="pFun" select="$vFunPrintEmpty"/> <xsl:with-param name="pX" select="$vIterHeader"/> </xsl:call-template> </xsl:variable> <xsl:copy-of select= "ext:node-set($vrtfRightBlank)/* [position() > 1] "/> </tr> </xsl:template> <xsl:template match="myFun:printTh" mode="f:FXSL"> <xsl:param name="arg1"/> <xsl:copy-of select="$arg1"/> <th> <xsl:value-of select="$vMaxCols -count($arg1/*)"/> </th> </xsl:template> <xsl:template match="myFun:printEmpty" mode="f:FXSL"> <xsl:param name="arg1"/> <xsl:copy-of select="$arg1"/> <td width="100">&#xA0;</td> </xsl:template> </xsl:stylesheet> 

When the above conversion is applied to the provided XML file, the desired result is created .

+2
source

Here is the XSLT 2.0 solution for the fixed problem :

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:funs" exclude-result-prefixes="xs my"> <xsl:output omit-xml-declaration="yes" method="html" indent="yes" encoding="utf-8"/> <xsl:key name="kItemByAddress" match="item" use="xs:integer(address)"/> <xsl:variable name="vMaxCols" select= "xs:integer(max(/*/*/(start + size)))+1 "/> <xsl:variable name="vMinAddress" select= "xs:integer(min(/*/*/address))"/> <xsl:variable name="vMaxAddress" select= "xs:integer(max(/*/*/address))"/> <xsl:variable name="vDoc" select="/"/> <xsl:template match="/*"> <html> <table border="1"> <thead> <tr> <th>Address</th> <xsl:for-each select="1 to $vMaxCols"> <th> <xsl:value-of select="$vMaxCols -."/> </th> </xsl:for-each> </tr> </thead> <tbody> <xsl:for-each select="$vMinAddress to $vMaxAddress"> <tr> <td width="100"><xsl:sequence select="."/></td> <xsl:variable name="vsortedItems" as="element()*"> <xsl:perform-sort select="key('kItemByAddress', ., $vDoc)"> <xsl:sort select="end" data-type="number" order="descending"/> </xsl:perform-sort> </xsl:variable> <xsl:for-each select="1 to $vMaxCols"> <xsl:sequence select="my:cellAtPos($vMaxCols -.,$vsortedItems)"/> </xsl:for-each> </tr> </xsl:for-each> </tbody> </table> </html> </xsl:template> <xsl:function name="my:cellAtPos" as="element()?"> <xsl:param name="pcellNum" as="xs:integer"/> <xsl:param name="pSortedItems" as="element()*"/> <xsl:variable name="vEmptyCell" as="element()"> <td width="100">&#xA0;</td> </xsl:variable> <xsl:variable name="vstartingItem" select= "$pSortedItems[(start+size -1) eq $pcellNum][1]"/> <xsl:variable name="vInsideItem" select= "$pSortedItems[(start+size -1) > $pcellNum and $pcellNum >= start ][1]"/> <xsl:choose> <xsl:when test="not($vstartingItem | $vInsideItem)"> <xsl:sequence select="$vEmptyCell"/> </xsl:when> <xsl:when test="$vstartingItem"> <td width="100" colspan="{$vstartingItem/size}"> <xsl:value-of select="$vstartingItem/name"/> </td> </xsl:when> <xsl:otherwise/> </xsl:choose> </xsl:function> </xsl:stylesheet> 

When this conversion is applied to the provided new XML document :

 <items> <item> <name>D</name> <address>0</address> <start>0</start> <size>2</size> </item> <item> <name>E</name> <address>0</address> <start>3</start> <size>4</size> </item> <item> <name>F</name> <address>7</address> <start>5</start> <size>2</size> </item> </items> 

The result obtained is :

 <html> <table border="1"> <thead> <tr> <th>Address</th> <th>7</th> <th>6</th> <th>5</th> <th>4</th> <th>3</th> <th>2</th> <th>1</th> <th>0</th> </tr> </thead> <tbody> <tr> <td width="100">0</td> <td width="100">&nbsp;</td> <td width="100" colspan="4">E</td> <td width="100">&nbsp;</td> <td width="100" colspan="2">D</td> </tr> <tr> <td width="100">1</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> </tr> <tr> <td width="100">2</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> </tr> <tr> <td width="100">3</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> </tr> <tr> <td width="100">4</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> </tr> <tr> <td width="100">5</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> </tr> <tr> <td width="100">6</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> </tr> <tr> <td width="100">7</td> <td width="100">&nbsp;</td> <td width="100" colspan="2">F</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> <td width="100">&nbsp;</td> </tr> </tbody> </table> </html> 
+1
source

Declarative languages โ€‹โ€‹such as XSLT can do many of the same things that mutables can use recursion. This python code can display a countdown from 7 to 0 without using variables:

 def countdown(i): if i==0: print 0 else: print i countdown(i-1) countdown(7) 

For other items, you donโ€™t even need recursion. You can do this declaratively. The start and size fields indicate that between start and start+size you will not fill the character | . So think about how you can visualize this table with conditional statements in a regular language, and it should be translatable in XSLT.

0
source

This works for me in Firefox and Opera (spaces are everywhere in IE).

Creating it according to your sample ASCII table, since adding the appropriate HTML tags will cause more noise around the core logic you are interested in.

test.xml:

 <?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="test.xsl"?> <items> <item> <name>A</name> <address>0</address> <start>0</start> <size>2</size> </item> <item> <name>B</name> <address>1</address> <start>2</start> <size>4</size> </item> <item> <name>C</name> <address>2</address> <start>5</start> <size>2</size> </item> <item> <name>D</name> <address>3</address> <start>3</start> <size>1</size> </item> </items> 

test.xsl:

 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" encoding="UTF-8" indent="no" doctype-public="-//W3C//DTD HTML 4.01//EN" doctype-system="http://www.w3.org/TR/html4/strict.dtd"/> <xsl:template match="/items"> <html lang="en"> <head> <title>Test</title> </head> <body> <pre><xsl:text>+---------+------+------+------+------+------+------+------+------+ | Address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +---------+------+------+------+------+------+------+------+------+ </xsl:text> <xsl:apply-templates select="item"/></pre> </body> </html> </xsl:template> <xsl:template match="item"> <xsl:text>| </xsl:text><xsl:value-of select="address"/><xsl:text> |</xsl:text> <xsl:call-template name="cells"> <xsl:with-param name="name" select="name"/> <xsl:with-param name="start" select="start"/> <xsl:with-param name="size" select="size"/> </xsl:call-template> <xsl:text>+---------+------+------+------+------+------+------+------+------+&#10;</xsl:text> </xsl:template> <xsl:template name="cells"> <xsl:param name="count" select="7"/> <xsl:param name="name"/> <xsl:param name="start"/> <xsl:param name="size"/> <xsl:if test="$count &gt; -1"> <!-- Leading cell space --> <xsl:text> </xsl:text> <!-- Name or space --> <xsl:choose> <xsl:when test="$count = $start + $size - 1"> <xsl:value-of select="$name"/> </xsl:when> <xsl:otherwise> <xsl:text> </xsl:text> </xsl:otherwise> </xsl:choose> <!-- Trailing cell space --> <xsl:text> </xsl:text> <!-- End cell marker or space to span --> <xsl:choose> <xsl:when test="$count = 0 or $size = 1"> <xsl:text>|</xsl:text> </xsl:when> <xsl:otherwise> <xsl:choose> <xsl:when test="$count &gt; $start and $count &lt; $start + $size"> <xsl:text> </xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>|</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> <!-- Line break after last cell --> <xsl:if test="$count = 0"> <xsl:text>&#10;</xsl:text> </xsl:if> <xsl:call-template name="cells"> <xsl:with-param name="count" select="$count - 1"/> <xsl:with-param name="name" select="$name"/> <xsl:with-param name="start" select="$start"/> <xsl:with-param name="size" select="$size"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet> 

Generated Output:

 +---------+------+------+------+------+------+------+------+------+ | Address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +---------+------+------+------+------+------+------+------+------+ | 0 | | | | | | | A | +---------+------+------+------+------+------+------+------+------+ | 1 | | | B | | | +---------+------+------+------+------+------+------+------+------+ | 2 | | C | | | | | | +---------+------+------+------+------+------+------+------+------+ | 3 | | | | | D | | | | +---------+------+------+------+------+------+------+------+------+ 
0
source

Source: https://habr.com/ru/post/1305226/


All Articles