XSLT & XSL-FO: Creating a table with multiple rows?

前端 未结 2 1734
隐瞒了意图╮
隐瞒了意图╮ 2021-01-27 03:34

I\'m fairly new to XSLT and I am stuck with a problem where I have an Element with an unknown amount of children, and I need to display these children in a table such that there

相关标签:
2条回答
  • 2021-01-27 04:03

    One approach is to use two recursive templates:

    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:ext="http://exslt.org/common"
                    xmlns:fo="http://www.w3.org/1999/XSL/Format"
                    exclude-result-prefixes="ext">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
    
        <!-- set the number of columns you want globally -->
        <xsl:param name="set-cols" select="'5'"/>
    
    
        <xsl:template match="books">
            <!-- count the needed rows -->
            <xsl:variable name="set-row" select="ceiling(count(book) div $set-cols)"/>
    
            <fo:table margin-left="auto" margin-right="auto">
                <fo:table-body>
                    <xsl:call-template name="rows">
                        <xsl:with-param name="books">
                            <xsl:apply-templates/>
                        </xsl:with-param>
                        <xsl:with-param name="set-row" select="$set-row"/>
                    </xsl:call-template>
                </fo:table-body>
            </fo:table>
        </xsl:template>
    
    
        <!-- rows -->
        <xsl:template name="rows">
            <xsl:param name="books" select="''"/>
            <xsl:param name="set-row" select="''"/>
            <xsl:param name="count-rows" select="'0'"/>
    
            <xsl:if test="$set-row &gt; 0">
                <fo:table-row table-layout="fixed">
                    <xsl:call-template name="cols">
                        <xsl:with-param name="books" select="$books"/>
                        <xsl:with-param name="count-rows" select="$count-rows"/>
                    </xsl:call-template>
                </fo:table-row>
                <xsl:call-template name="rows">
                    <xsl:with-param name="books" select="$books"/>
                    <xsl:with-param name="set-row" select="$set-row - 1"/>
                    <xsl:with-param name="count-rows" select="$count-rows + 1"/>
                </xsl:call-template>
            </xsl:if>
        </xsl:template>
    
    
        <!-- columns -->
        <xsl:template name="cols">
            <xsl:param name="books" select="''"/>
            <xsl:param name="cols" select="$set-cols"/>
            <xsl:param name="count-rows" select="''"/>
            <xsl:param name="count-cols" select="'1'"/>
    
            <xsl:if test="$cols &gt; 0">
                <fo:table-cell border="1">
                    <fo:block font-weight="bold">
                        <xsl:variable name="book" select="ext:node-set($books)//book[position() = ($count-rows * $set-cols + $count-cols)]"/>
                        <xsl:value-of select="$book/author"/>
                    </fo:block>
                </fo:table-cell>
                <xsl:call-template name="cols">
                    <xsl:with-param name="books" select="$books"/>
                    <xsl:with-param name="cols" select="$cols - 1"/>
                    <xsl:with-param name="count-rows" select="$count-rows"/>
                    <xsl:with-param name="count-cols" select="$count-cols + 1"/>
                </xsl:call-template>
            </xsl:if>
        </xsl:template>
    
    </xsl:stylesheet>
    

    With yout input

    <books>
        <book>
            <author>Ralls, Kim</author>
            <title>Midnight Rain</title>
        </book>
        <book>
            <author>Corets, Eva</author>
            <title>Maeve Ascendant</title>
        </book>
        <!-- ... -->
    </books>
    

    you get:

    <fo:table margin-left="auto" margin-right="auto" xmlns:fo="http://www.w3.org/1999/XSL/Format">
        <fo:table-body>
            <fo:table-row table-layout="fixed">
                <fo:table-cell border="1">
                    <fo:block font-weight="bold">Ralls, Kim</fo:block>
                </fo:table-cell>
                <fo:table-cell border="1">
                    <fo:block font-weight="bold">Corets, Eva</fo:block>
                </fo:table-cell>
                <fo:table-cell border="1">
                    <fo:block font-weight="bold">Corets, Eva</fo:block>
                </fo:table-cell>
                <fo:table-cell border="1">
                    <fo:block font-weight="bold">Randall, Cynthia</fo:block>
                </fo:table-cell>
                <fo:table-cell border="1">
                    <fo:block font-weight="bold">Thurman, Paula</fo:block>
                </fo:table-cell>
            </fo:table-row>
            <fo:table-row table-layout="fixed">
                <fo:table-cell border="1">
                    <fo:block font-weight="bold">Knorr, Stefan</fo:block>
                </fo:table-cell>
                <fo:table-cell border="1">
                    <fo:block font-weight="bold">Kress, Peter</fo:block>
                </fo:table-cell>
                <fo:table-cell border="1">
                    <fo:block font-weight="bold">Crichton, Michael</fo:block>
                </fo:table-cell>
                <fo:table-cell border="1">
                    <fo:block font-weight="bold">Orwell, George</fo:block>
                </fo:table-cell>
                <fo:table-cell border="1">
                    <fo:block font-weight="bold">Martin, George</fo:block>
                </fo:table-cell>
            </fo:table-row>
        </fo:table-body>
    </fo:table>
    
    0 讨论(0)
  • 2021-01-27 04:15

    The previous answers are way to complicated for what should be (and is) easy. Recursion is not required for such a simple thing.

    In XSL FO you do not need to structure tables with rows. You can use the attribute "ends-row" to specify that you are ending a row and starting a new one. You can easily adapt this simple example and even pass in the "number of columns" (see the mod 5 ... which means after every fifth one start a new row ... change to 4 or 8 or whatever you wish) ... You would just create the structure for the table (fo:table and fo:table-body) outside of this. Inside the table body just put cells as children like this template does:

      <xsl:template match="book">
        <xsl:variable name="pos" select="position()"/>
        <fo:table-cell>
            <xsl:if test="not($pos mod 5)">
                <xsl:attribute name="ends-row">true</xsl:attribute>
            </xsl:if>
            <fo:block>
                <xsl:value-of select="author"/>
            </fo:block>
        </fo:table-cell>
    </xsl:template>
    

    So putting this into a simple example with your data ... see below. Formats your XML into five columns per row.

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        version="1.0">
    <xsl:template match="/">
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <fo:layout-master-set>
                <fo:simple-page-master margin-top="1in" margin-left="1in" margin-bottom="1in"
                    margin-right="1in" page-width="8in" page-height="11in" master-name="first">
                    <fo:region-body margin-top="0pt"/>
                    <fo:region-before extent="0pt"/>
                    <fo:region-after extent="0pt"/>
                </fo:simple-page-master>
            </fo:layout-master-set>
            <fo:page-sequence master-reference="first">
                <fo:flow flow-name="xsl-region-body" font-size="12pt" font-family="Helvetica">
        <xsl:apply-templates/>
                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>
        <xsl:template match="books">
            <fo:table>
                <fo:table-body>
                    <xsl:apply-templates/>
                </fo:table-body>
            </fo:table>
        </xsl:template>
        <xsl:template match="book">
            <xsl:variable name="pos" select="position()"/>
            <fo:table-cell border="1pt solid black">
                <xsl:if test="not($pos mod 5)">
                    <xsl:attribute name="ends-row">true</xsl:attribute>
                </xsl:if>
                <fo:block>
                    <xsl:value-of select="author"/>
                </fo:block>
            </fo:table-cell>
        </xsl:template>
    
    </xsl:stylesheet>
    
    0 讨论(0)
提交回复
热议问题