XSL: Convert xml to html sorted multi-column table

I am considering a similar problem with what has been described here.

Convert list to 2-D table

but with a slight wrinkle. My XML is not in any specific order, and I would like to sort it for display. For example, my XML

<items> <item>A</item> <item>C</item> <item>E</item> <item>B</item> <item>D</item> <!-- ... any number of item nodes ... --> <item> 

and I want my output to be (where I ignore unnamed nodes for illustrative purposes)

 <table> <tr> <td>A</td> <td>C</td> <td>E</td> </tr> <tr> <td>B</td> <td>D</td> <td /> </tr> </table> 

XSL I base this on the link above (I need to use XSL 1.0):

 <xsl:template match="/*"> <table> <xsl:call-template name="make-columns"> <xsl:with-param name="nodelist" select="item"/> </xsl:call-template> </table> </xsl:template> <xsl:template name="make-columns"> <xsl:param name="nodelist"/> <xsl:param name="columns-number" select="3"/> <tr> <xsl:apply-templates select="$nodelist[ not(position() > $columns-number) ]"/> <xsl:if test="count($nodelist) &lt; $columns-number"> <xsl:call-template name="empty-cells"> <xsl:with-param name="finish" select="$columns-number - count($nodelist)"/> </xsl:call-template> </xsl:if> </tr> <!-- If some nodes are left, recursively call current template, passing only nodes that are left --> <xsl:if test="count($nodelist) > $columns-number"> <xsl:call-template name="make-columns"> <xsl:with-param name="nodelist" select="$nodelist[ position() > $columns-number ]"/> </xsl:call-template> </xsl:if> </xsl:template> <xsl:template match="item"> <td> <xsl:apply-templates/> </td> </xsl:template> <xsl:template name="empty-cells"> <xsl:param name="finish"/> <td/> <xsl:if test="not($finish = 1)"> <xsl:call-template name="empty-cells"> <xsl:with-param name="finish" select="$finish - 1"/> </xsl:call-template> </xsl:if> </xsl:template> 

I tried to embed commands in various apply-templates, but that doesn't work.

ideas?

Jeff

Update from comments

I want to display a multi-color table with 3 columns, where the entries are in alphabetical order vertically

+1
source share
2 answers

This conversion is :

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:param name="pNumCols" select="3"/> <xsl:variable name="vNumRows" select= "ceiling(count(/*/*) div $pNumCols)"/> <xsl:variable name="vrtfSorted"> <xsl:for-each select="/*/*"> <xsl:sort/> <xsl:copy-of select="."/> </xsl:for-each> </xsl:variable> <xsl:variable name="vSorted" select="ext:node-set($vrtfSorted)/*"/> <xsl:template match="/"> <table> <xsl:apply-templates select= "$vSorted[not(position() > $vNumRows)]"/> </table> </xsl:template> <xsl:template match="item"> <tr> <xsl:apply-templates select= "(.|following-sibling::*[position() mod $vNumRows =0])/text()"/> </tr> </xsl:template> <xsl:template match="text()"> <td><xsl:value-of select="."/></td> </xsl:template> </xsl:stylesheet> 

when applied to the provided XML document:

 <items> <item>A</item> <item>C</item> <item>E</item> <item>B</item> <item>D</item> </items> 

creates the desired, correct result:

 <table> <tr> <td>A</td> <td>C</td> <td>E</td> </tr> <tr> <td>B</td> <td>D</td> </tr> </table> 
+1
source

Refresh . Now, with an explanation of the new explanation, this stylesheet:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> <xsl:strip-space elements="*"/> <xsl:param name="pColumns" select="3"/> <xsl:template match="items"> <xsl:variable name="vrtfChilds"> <xsl:for-each select="*"> <xsl:sort/> <xsl:copy-of select="."/> </xsl:for-each> </xsl:variable> <xsl:variable name="vChilds" select="msxsl:node-set($vrtfChilds)/*"/> <xsl:variable name="vRows" select="ceiling(count($vChilds) div $pColumns)"/> <table> <xsl:for-each select="$vChilds[$vRows >= position()]"> <tr> <xsl:call-template name="columns"> <xsl:with-param name="pRows" select="$vRows"/> </xsl:call-template> </tr> </xsl:for-each> </table> </xsl:template> <xsl:template name="columns"> <xsl:param name="pData" select="."/> <xsl:param name="pColumn" select="$pColumns"/> <xsl:param name="pRows" select="0"/> <xsl:if test="$pColumn"> <td> <xsl:apply-templates select="$pData"/> </td> <xsl:call-template name="columns"> <xsl:with-param name="pData" select="$pData/following-sibling::*[$pRows]"/> <xsl:with-param name="pColumn" select="$pColumn - 1"/> <xsl:with-param name="pRows" select="$pRows"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet> 

Conclusion:

 <table> <tr> <td>A</td> <td>C</td> <td>E</td> </tr> <tr> <td>B</td> <td>D</td> <td></td> </tr> </table> 

Note : node-set extension function for two-phase conversion.

+1
source

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


All Articles