toneb
toneb

Reputation: 143

XSLT and dynamic table columns

I have developed an XSL file that transforms xml files into a html table. The idea is to have only one xsl file transform many xml files into a html table, instead of having 10 xml files with 10 accompanying xsl files. I've included the one xsl file and 2 xml files that uses the xsl file to transform them into a html tables. The problem I'm having is that I can't seem to figure out how the columns for the rows get created to complete the generated table. Please have test the code below to get an understanding. All support is welcome. Thanks!

tone

XSL File: test_xsl.xsl

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>

<xsl:template match="/root/sheet">
    <html>
        <head></head>
        <body>
            <table border="1" width="100%" cellpadding="0" cellspacing="0" height="100%">

                <xsl:apply-templates select="headers"/>

                <xsl:for-each select="rows">
                    <xsl:for-each select="item">
                        <tr>
                            <td>
                                <table border="1" width="100%" height="100%" cellpadding="0" cellspacing="0">
                                    <tr>
                                        <td>
                                            <b><xsl:value-of select="name" disable-output-escaping="yes" /></b>
                                        </td>

                                    </tr>
                                </table>
                            </td>
                        </tr>
                    </xsl:for-each>
                </xsl:for-each>
            </table>
        </body>
    </html>
</xsl:template>
<xsl:template match="headers">
    <tr>
        <xsl:apply-templates select="item"/>
    </tr>
</xsl:template>
<xsl:template match="headers//item">
    <th>
        <xsl:choose>
            <xsl:when test="item">
                <table border="1" width="100%" height="100%">
                    <tr><td colspan="{count(item)}"><xsl:value-of select="name"/></td></tr>
                    <xsl:apply-templates select="item"/>
                </table>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="name"/>
            </xsl:otherwise>
        </xsl:choose>
    </th>
</xsl:template>
</xsl:stylesheet>

XML File 1: test_xml1.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="test_xsl.xsl"?>

<root>
    <sheet>
        <titles>
            <item>
                <name><![CDATA[Title 1]]></name>
            </item>
            <item>
                <name><![CDATA[Title 2]]></name>
            </item>
            <item>
                <name><![CDATA[Title 3]]></name>
            </item>
        </titles>
        <headers>
            <item>
                <name><![CDATA[Header 1]]></name>
            </item>
            <item>
                <name><![CDATA[Header 2]]></name>
                <item>
                    <name><![CDATA[Sub header 1 of Header 2]]></name>
                </item>
                <item>
                    <name><![CDATA[Sub header 2 of Header 2]]></name>
                    <item>
                        <name><![CDATA[Sub header 1 of Sub header 2 of Header 2]]></name>
                    </item>
                    <item>
                        <name><![CDATA[Sub header 2 of Sub header 2 of Header 2]]></name>
                    </item>
                </item>
            </item>
            <item>
                <name><![CDATA[Header 3]]></name>
            </item>
        </headers>
        <rows>
            <item>
                <name><![CDATA[Row 1]]></name>
            </item>
            <item>
                <name><![CDATA[Row 2]]></name>
            </item>
            <item>
                <name><![CDATA[Row 3]]></name>
            </item>
            <item>
                <name><![CDATA[Row 4]]></name>
            </item>
        </rows>
    </sheet>
</root>

XML File 2: test_xml2.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="test_xsl.xsl"?>
<root>
<sheet>
  <titles>
   <item>
    <name><![CDATA[Title 1]]></name>
   </item>

   <item>
    <name><![CDATA[Title 2]]></name>
   </item>

   <item>
    <name><![CDATA[Title 3]]></name>
   </item>
  </titles>
  <headers>
    <item>
    <name><![CDATA[Header 1]]></name>
   </item>

   <item>
    <name><![CDATA[Header 2]]></name>
   </item>

   <item>
    <name><![CDATA[Header 3]]></name>
   </item>
   <item>
    <name><![CDATA[Header 4]]></name>

    <item>
     <name><![CDATA[Sub header 1 of Header 4]]></name>
    </item>

    <item>
     <name><![CDATA[Sub header 2 of Header 4]]></name>
    </item>
   </item>
  </headers>

  <rows>
   <item>
    <name><![CDATA[Row 1]]></name>
   </item>
   <item>
    <name><![CDATA[Row 2]]></name>
   </item>                           

   <item>
    <name><![CDATA[Row 3]]></name>
   </item>                           

   <item>
    <name><![CDATA[Row 4]]></name>
   </item>   


  </rows>
 </sheet>
</root>

UPDATE

Here is an xsl file that will format the test_xml1.xml file I've provided. When trying to use this xsl file with the test_xml2.xml file, you will notice that the table appears with a column missing. The reason for this is because it's being hard coded. Ideally this should be dynamic. Hope I was clear. Thanks for your help!

<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>

<xsl:template match="/root/sheet">
    <html>
        <head></head>
        <body>
            <table border="1" width="100%" cellpadding="0" cellspacing="0" height="100%">
                <xsl:apply-templates select="headers"/>
                <xsl:for-each select="rows">
                    <xsl:for-each select="item">
                        <tr>
                            <td>
                                <table border="1" width="100%" height="100%" cellpadding="0" cellspacing="0">
                                    <tr>
                                        <td>
                                            <b><xsl:value-of select="name" disable-output-escaping="yes" /></b>
                                        </td>

                                    </tr>
                                </table>
                            </td>
                            <td><br /></td>
                            <td><br /></td>
                        </tr>
                    </xsl:for-each>
                </xsl:for-each>
            </table>
        </body>
    </html>
</xsl:template>
<xsl:template match="headers">
    <tr>
        <xsl:apply-templates select="item"/>
    </tr>
</xsl:template>
<xsl:template match="headers//item">
    <th>
        <xsl:choose>
            <xsl:when test="item">
                <table border="1" width="100%" height="100%">
                    <tr><td colspan="{count(item)}" width="40%"><xsl:value-of select="name"/></td></tr>
                    <xsl:apply-templates select="item"/>
                </table>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="name"/>
            </xsl:otherwise>
        </xsl:choose>
    </th>
</xsl:template>

Upvotes: 1

Views: 8532

Answers (1)

Catch22
Catch22

Reputation: 3351

There's no data for the columns and there's no relationship between the headers and the actual rows but this will produce the right number of (empty) cells...

<xsl:template match="/root/sheet">
    <html>
      <head></head>
      <body>
        <table border="1" width="100%" cellpadding="0" cellspacing="0" height="100%">
          <xsl:apply-templates select="headers"/>
          <xsl:for-each select="rows">
            <xsl:for-each select="item">
              <tr>
                <td>
                  <xsl:value-of select="name" disable-output-escaping="yes" />
                </td>
                <!--
                <td>
                  <br />
                </td>
                <td>
                  <br />
                </td>-->
                <!-- Loop through all the first level headers except the first one -->
                <xsl:for-each select="//headers/item[position() &gt; 1]">
                  <td>
                    <br />
                  </td>
                </xsl:for-each>
              </tr>
            </xsl:for-each>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

Basically, instead of hard coding the cells, you just loop though the first level headers to get the right number of cells. And in the sample code above, I'm skipping the first cell (position() > 1) as you are already outputing it.

Upvotes: 1

Related Questions