user3629892
user3629892

Reputation: 3046

show list as table in xsl-fo

I'm trying to render this list as a table in xsl-fo

<ul class="tablelist">
             <li class="a">A</li>
             <li class="a">A
    </li>
             <li class="b">B
    </li>
             <li class="b">B
    </li>
             <li class="a">A</li>
             <li class="b">B</li>
             <li class="a">A</li>
             </ul>

All the ones with class A in the left column, all the ones with class B in the right column.

My current solution:

  <fo:table>
              <fo:table-column column-number="1" column-width="30mm"/>
        <fo:table-column column-number="2" />
  <fo:table-body>
      <xsl:for-each select="li[@class='a']">
        <fo:table-row>
        <fo:table-cell column-number="1">
            <fo:block>
                <xsl:apply-templates/>
            </fo:block>
        </fo:table-cell>
        </fo:table-row>
      </xsl:for-each>
              <xsl:for-each select="li[@class='b']">
        <fo:table-row>
        <fo:table-cell column-number="2">
            <fo:block>
                <xsl:apply-templates/>
            </fo:block>
        </fo:table-cell>
        </fo:table-row>
      </xsl:for-each>
      </fo:table-body>
  </fo:table>

... doesnt work, of course. What would I need to change?

Thanks for help!

EDIT:

Desired output in this case would be:

<fo:table>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>
A
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
B
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block>
A
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
B
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block>
A
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
B
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block>
A
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block/
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>

because there are four class="a" and three class="b"elements. So, 4 rows in total, in 4 rows the left cell is A and in three of those rows, the right column is B.

Hope, it is a bit clearer now!

Upvotes: 0

Views: 1002

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 117073

Here's another way you could look at it:

XSLT 1.0

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/">
    <table>
        <xsl:call-template name="generate-rows">
            <xsl:with-param name="left" select="ul/li[@class='a']"/>
            <xsl:with-param name="right" select="ul/li[@class='b']"/>
        </xsl:call-template>    
    </table>
</xsl:template>

<xsl:template name="generate-rows">
    <xsl:param name="left"/>
    <xsl:param name="right"/>
    <xsl:param name="i" select="1"/>
    <xsl:if test="$i &lt;= count($left) or $i &lt;= count($right)">
        <row>
            <cell><xsl:value-of select="$left[$i]"/></cell>
            <cell><xsl:value-of select="$right[$i]"/></cell>
        </row>
        <xsl:call-template name="generate-rows">
            <xsl:with-param name="left" select="$left"/>
            <xsl:with-param name="right" select="$right"/>      
            <xsl:with-param name="i" select="$i + 1"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

Upvotes: 2

Daniel Haley
Daniel Haley

Reputation: 52878

One option is to use position() to apply-templates to the element with the opposite class that's in the same position.

If you know that there will always be more a class elements than b class elements (or if you don't care what happens to the remaining b class elements), you could do something like this:

<xsl:template match="ul[@class='tablelist']">
    <fo:table>
        <fo:table-column column-number="1" column-width="30mm"/>
        <fo:table-column column-number="2" />
        <fo:table-body>
            <xsl:for-each select="li[@class='a']">
                <xsl:variable name="pos" select="position()"/>
                <fo:table-row>
                    <fo:table-cell column-number="1">
                        <fo:block>
                            <xsl:apply-templates/>
                        </fo:block>
                    </fo:table-cell>
                    <fo:table-cell column-number="2">
                        <fo:block>
                            <xsl:apply-templates select="../li[@class='b'][position()=$pos]"/>
                        </fo:block>
                    </fo:table-cell>
                </fo:table-row>
            </xsl:for-each>
        </fo:table-body>
    </fo:table>
</xsl:template>

If you do care about those b class elements, when there are more b than a, you could do something like this:

<xsl:template match="ul[@class='tablelist']">
    <fo:table>
        <fo:table-column column-number="1" column-width="30mm"/>
        <fo:table-column column-number="2" />
        <fo:table-body>
            <xsl:choose>
                <xsl:when test="count(li[@class='a']) >= count(li[@class='a'])">
                    <xsl:apply-templates select="li[@class='a']" mode="createRow"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="li[@class='b']" mode="createRow"/>                        
                </xsl:otherwise>
            </xsl:choose>
        </fo:table-body>
    </fo:table>
</xsl:template>

<xsl:template match="li[@class='a']" mode="createRow">
    <xsl:variable name="pos" select="position()"/>
    <fo:table-row>
        <fo:table-cell column-number="1">
            <fo:block>
                <xsl:apply-templates/>
            </fo:block>
        </fo:table-cell>
        <fo:table-cell column-number="2">
            <fo:block>
                <xsl:apply-templates select="../li[@class='b'][position()=$pos]"/>
            </fo:block>
        </fo:table-cell>
    </fo:table-row>
</xsl:template>

<xsl:template match="li[@class='b']" mode="createRow">
    <xsl:variable name="pos" select="position()"/>
    <fo:table-row>
        <fo:table-cell column-number="1">
            <fo:block>
                <xsl:apply-templates select="../li[@class='a'][position()=$pos]"/>
            </fo:block>
        </fo:table-cell>
        <fo:table-cell column-number="2">
            <fo:block>
                <xsl:apply-templates/>
            </fo:block>
        </fo:table-cell>
    </fo:table-row>
</xsl:template>

Upvotes: 1

Related Questions