removr
removr

Reputation: 3

XSLT create table with dynamic number of rows and columns

I am new to XSLT and need your help. I have to create word tables in XSLT. The number of columns and rows is dynamic.

This is an example XML:

<Movies>
  <Genre name="Action">
    <Movie>
      <Name>Crash</Name>
      <Released>2005</Released>
    </Movie>
  </Genre>
  <Genre name="Drama">
    <Movie>
      <Name>The Departed</Name>
      <Released>2006</Released>
    </Movie>
    <Movie>
      <Name>The Pursuit of Happyness</Name>
      <Released>2006</Released>
    </Movie>
  </Genre>
  <Genre name="Comedy">
    <Movie>
      <Name>The Bucket List</Name>
      <Released>2007</Released>
    </Movie>
  </Genre>
</Movies>

The genre element can contain any number of movie elements.

The Table should look like this:
Picture

This is the XSLT:

    <xsl:template match="/">
        <w:document>
            <w:body>    
                <w:tbl>
                    <w:tr>
                        <xsl:for-each select="/Movies/Genre">
                            <w:tc>
                                <w:p>
                                    <w:r>
                                        <w:t>
                                            <xsl:value-of select="@name"/>
                                        </w:t>
                                    </w:r>
                                </w:p>
                            </w:tc>
                        </xsl:for-each> 
                    </w:tr>

                    <!-- Movies? -->

                </w:tbl>
            </w:body>
        </w:document>
    </xsl:template>

The column header is not a problem, but how can I write the movie elements as desired? Is there a way with two for-each loops, or do I have to use apply-templates? Thanks for your support!

Upvotes: 0

Views: 2407

Answers (1)

ideafixxxer
ideafixxxer

Reputation: 474

Unfortunately I'm not familiar with DOCX format, so you may want to correct the output, but as for the XSLT, the following should do the trick

  <xsl:template match="/">
    <w:document>
      <w:body>
        <w:tbl>
          <w:tr>
            <xsl:for-each select="/Movies/Genre">
              <w:tc>
                <w:p>
                  <w:r>
                    <w:t>
                      <xsl:value-of select="@name"/>
                    </w:t>
                  </w:r>
                </w:p>
              </w:tc>
            </xsl:for-each>
          </w:tr>

          <!-- Movies? -->

          <xsl:call-template name="movies-row">
            <xsl:with-param name="i" select="1"></xsl:with-param>
          </xsl:call-template>

        </w:tbl>
      </w:body>
    </w:document>
  </xsl:template>

  <xsl:template name="movies-row">
    <xsl:param name="i"/>

      <w:tr>
        <xsl:for-each select="/Movies/Genre">
          <w:tc>
            <w:p>
              <w:r>
                <w:t>
                  <xsl:choose>
                    <xsl:when test="count(Movie) >= $i">
                      <xsl:value-of select="concat(Movie[$i]/Name, ' (', Movie[$i]/Released, ')')"/>
                    </xsl:when>
                    <xsl:otherwise>
                      <!-- empty cell -->
                    </xsl:otherwise>
                  </xsl:choose>
                </w:t>
              </w:r>
            </w:p>
          </w:tc>
        </xsl:for-each>
      </w:tr>

    <xsl:if test="/Movies/Genre[count(Movie) > $i]">
      <xsl:call-template name="movies-row">
        <xsl:with-param name="i" select="$i + 1"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

Upvotes: 1

Related Questions