Search code examples
xsltxslt-2.0xsl-fo

How to loop through the alphabet with XSLT?


I need to create a dynamic XSL-FO table in XSLT 2.0, that looks similar to this:

+------+------+------+------+------+------+
|      |   1  |  2   |  3   |  4   |   5  |
+------+------+------+------+------+------+
|   A  |      |      |      |      |      |
+------+------+------+------+------+------+
|   B  |      |      |      |      |      |
+------+------+------+------+------+------+
|   C  |      |      |      |      |      |
+------+------+------+------+------+------+
|   D  |      |      |      |      |      |
+------+------+------+------+------+------+
|   E  |      |      |      |      |      |
+------+------+------+------+------+------+

Both end-stops (rows, columns) are dynamic and specified with the last number/letter in the source data.

<input>
    <end-stop-column>5</end-stop-column>
    <end-stop-row>E</end-stop-row>
</input>

I thought of an for-each approach (pseudo code):

<fo:table>
    <fo:table-body>
        <fo:table-row>
            <fo:table-cell><fo:block></fo:block></fo:table-cell>
            <xsl:for-each select="1 to 5">
                <xsl:variable name="colid" select="current()"/>
                <fo:table-cell><fo:block><xsl:value-of select="$colid"/></fo:block></fo:table-cell>
            </xsl:for-each>
        </fo:table-row>
        <xsl:for-each select="A to E">
            <xsl:variable name="rowid" select="current()"/>
            <fo:table-row>
                <fo:table-cell><fo:block><xsl:value-of select="$rowid"/></fo:block></fo:table-cell>                    <xsl:for-each select="1 to 5">
                    <xsl:variable name="colid" select="current()"/>
                    <fo:table-cell>
                        <fo:block>
                            <xsl:text>Value for </xsl:text>
                            <xsl:value-of select="$rowid"/>
                            <xsl:text> </xsl:text>
                            <xsl:value-of select="$colid"/>
                        </fo:block>
                    </fo:table-cell>
                </xsl:for-each>
            </fo:table-row>
        </xsl:for-each>
    </fo:table-body>
</fo:table>

The above XSLT does not work, because for-each within the in context can only handle numbers.

How to handle the letters in the rows? The rows may not stop at Z and start again from ZA, ZB, ..., ZZ, ZZA, ....


Solution

  • Use a mapping from letters to numbers, if string-to-codepoints(end-stop-row) suffices (https://www.w3.org/TR/xpath-functions/#func-string-to-codepoints) (will depend on the alphabet you have in mind), use that. The formatting of numbers you process in a second step as letters can be handled by xsl:number or format-number.