Austin Crapo
Austin Crapo

Reputation: 13

XSL Stylesheet for dynamic XML Data

I want to create 1 XSL style sheet that can create HTML Table code with data specific headers and column counts. Here are two example sets of data I want processed by 1 style sheet

<root> 
      <row> 
        <postId>1</postId> 
        <id>1</id> 
        <name>name 1</name> 
        <email>[email protected]</email> 
        <body>body 1</body> 
      </row> 
      <row> 
        <postId>1</postId> 
        <id>2</id> 
        <name>name 2</name> 
        <email>[email protected]</email> 
        <body>body 2</body> 
      </row> 
</root>

<root> 
      <row> 
        <id>1</id> 
        <desc>desc 1</desc> 
        <Note>Note 1</Note> 
      </row> 
      <row> 
        <id>2</id> 
        <desc>desc 2</desc> 
        <Note>Note 2</Note> 
      </row> 
      <row> 
        <id>3</id> 
        <desc>desc 3</desc> 
        <Note>Note 3</Note>
      </row> 
</root>

Then I'd like the sheet to produce outputs like:

<table>
  <thead>
    <th>postId</th><th>id</th><th>name</th><th>email</th><th>body</th>
  </thead>
  <tbody>
    <tr>
      <td>1</td><td>1</td><td>mane 1</td><td>[email protected]</td><td>body 1</td>
    </tr>
    <tr>
      <td>1</td><td>2</td><td>mane 2</td><td>[email protected]</td><td>body 2</td>
    </tr>
  </tbody>

<table>
  <thead>
    <th>id</th><th>desc</th><th>Note</th>
  </thead>
  <tbody>
    <tr>
      <td>1</td><td>desc 1</td><td>Note 1</td>
    </tr>
    <tr>
      <td>2</td><td>desc 2</td><td>Note 2</td>
    </tr>
    <tr>
      <td>3</td><td>desc 3</td><td>Note 3</td>
    </tr>
  </tbody>
</table>

I've figured out the table header (see below) but I can't seem to get the body to work. I can't figure out how to show a value of an element I don't know the name of or even if one exists.

<?xml version="1.0"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="root">
  <html>
    <body>
      <h2>My Table Data</h2>
        <table border="1">
          <thead>
            <tr bgcolor="#9acd32">
              <xsl:for-each select="row[1]/*">
                <th><xsl:value-of select ="name(.)"/></th>        
              </xsl:for-each>
            </tr>
          </thead>
          <tbody> 
            ?????
          </tbody>

Upvotes: 1

Views: 45

Answers (1)

Tim C
Tim C

Reputation: 70618

If your row elements always has the same number of elements, and in the same order, you wouldn't have to worry about the names, and your ????? could simply be replaced by this....

<xsl:for-each select="row">
   <tr>
      <xsl:for-each select="*">
         <td>
            <xsl:value-of select="." />
         </td>
      </xsl:for-each>
   </tr>
</xsl:for-each>

On the other hand, if the row elements could have elements in different order, or even missing, then (assuming the first row was always complete), you could define a variable holding the "header" row cells

 <xsl:variable name="headers" select="row[1]/*"/>

Then your ???? becomes this...

<xsl:for-each select="row">
    <xsl:variable name="currentRow" select="."/>
    <tr>
        <xsl:for-each select="$headers">
        <xsl:variable name="currentHeaderName" select="name()" />
           <td>
              <xsl:value-of select="$currentRow/*[name() = $currentHeaderName]"/>
           </td>
        </xsl:for-each>
    </tr>
  </xsl:for-each>

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="root">
      <html>
        <body>
            <h2>My Table Data</h2>
            <xsl:variable name="headers" select="row[1]/*"/>
            <table border="1">
              <thead>
                  <tr bgcolor="#9acd32">
                     <xsl:for-each select="$headers">
                        <th>
                           <xsl:value-of select="name(.)"/>
                        </th>        
                     </xsl:for-each>
                  </tr>
              </thead>
              <tbody> 
                  <xsl:for-each select="row">
                    <xsl:variable name="currentRow" select="."/>
                    <tr>
                        <xsl:for-each select="$headers">
                        <xsl:variable name="currentHeaderName" select="name()" />
                           <td>
                              <xsl:value-of select="$currentRow/*[name() = $currentHeaderName]"/>
                           </td>
                        </xsl:for-each>
                    </tr>
                  </xsl:for-each>
              </tbody>
             </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Related Questions