3

Below is my XML File -

<School>
  <Std c="8">
    <Name>ABC</Name>
    <Age>12</Age>
    <Name>EFG</Name>
    <Age>11</Age>
    <Name>PQR</Name>
    <Age>12</Age>
    <Name>XYZ</Name>
    <Age>11</Age>
  </Std>
</School>

I want HTML out-put as -

Name    Age
ABC     12 
EFG     11
PQR     12
XYZ     11

3 Answers 3

7

Here is a fully generic solution that works with any number of columns:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kColsByName" match="Std/*"
  use="name()"/>

 <xsl:variable name="vCols" select=
  "*/*/*
        [generate-id()
        =
        generate-id(key('kColsByName', name())[1])
        ]
  "/>

 <xsl:variable name="vNumCols" select="count($vCols)"/>

 <xsl:template match="/*/Std">
     <table>
      <tr>
        <xsl:apply-templates select="$vCols"
             mode="head"/>
      </tr>
      <xsl:apply-templates select=
       "*[position() mod $vNumCols = 1]"/>
     </table>
 </xsl:template>

 <xsl:template match="Std/*" mode="head">
  <th><xsl:value-of select="name()"/></th>
 </xsl:template>

 <xsl:template match="Std/*">
  <tr>
   <xsl:apply-templates mode="inrow" select=
    "(. | following-sibling::*)
         [not(position() > $vNumCols)]"/>
  </tr>
 </xsl:template>

  <xsl:template match="Std/*" mode="inrow">
  <td><xsl:value-of select="."/></td>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<School>
  <Std c="8">
    <Name>ABC</Name>
    <Age>12</Age>
    <Name>EFG</Name>
    <Age>11</Age>
    <Name>PQR</Name>
    <Age>12</Age>
    <Name>XYZ</Name>
    <Age>11</Age>
  </Std>
</School>

the wanted, correct result is produced:

<table>
   <tr>
      <th>Name</th>
      <th>Age</th>
   </tr>
   <tr>
      <td>ABC</td>
      <td>12</td>
   </tr>
   <tr>
      <td>EFG</td>
      <td>11</td>
   </tr>
   <tr>
      <td>PQR</td>
      <td>12</td>
   </tr>
   <tr>
      <td>XYZ</td>
      <td>11</td>
   </tr>
</table>

Now, if we add a new column, say Sex, to the original XML document:

<School>
  <Std c="8">
    <Name>ABC</Name>
    <Age>12</Age>
    <Sex>M</Sex>
    <Name>EFG</Name>
    <Age>11</Age>
    <Sex>F</Sex>
    <Name>PQR</Name>
    <Age>12</Age>
    <Sex>F</Sex>
    <Name>XYZ</Name>
    <Age>11</Age>
    <Sex>M</Sex>
  </Std>
</School>

we can apply the same transformation above without any modifications, and it produces the correct result again -- this shows that the transformation is truly generic:

<table>
   <tr>
      <th>Name</th>
      <th>Age</th>
      <th>Sex</th>
   </tr>
   <tr>
      <td>ABC</td>
      <td>12</td>
      <td>M</td>
   </tr>
   <tr>
      <td>EFG</td>
      <td>11</td>
      <td>F</td>
   </tr>
   <tr>
      <td>PQR</td>
      <td>12</td>
      <td>F</td>
   </tr>
   <tr>
      <td>XYZ</td>
      <td>11</td>
      <td>M</td>
   </tr>
</table>
Sign up to request clarification or add additional context in comments.

2 Comments

It looks things are moving forward as I tried this generic xslt style sheet only to be meet with the error: "Running an XSL-T 1.0 stylesheet with a 2.0 processor." Anyone have a generic solution for XSL-T 2.0?
@frederickjh, This is not an error -- just a warning. The transformation should be executed OK. In case the transformation was not executed, this means that the XSLT processor you are using is not compliant with the W3C XSLT 2.0 Specification. You also can change the version attribute of <xsl:stylesheet> to 2.0 and this transformation should be executed with no such warning message, and should produce the same results
3
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="html" indent="yes"/>

<xsl:template match="School">
<table>
  <tr>
    <th>Name</th>
    <th>Age</th>
  </tr>
  <xsl:for-each select="Std/Name">
    <tr>
      <td>
        <xsl:value-of select="."/>
      </td>
      <td>
        <xsl:value-of select="following::Age"/>
      </td>
    </tr>
  </xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>

2 Comments

@John and Pencho: This solution is rather static and non-generic, contains hardcoded names and xsl:for-each and isn't extensible -- requires modifications any time some elements are renamed or a new element is added. See my answer for a truly generic solution that doesn't require any modification on any of those changes.
How can I apply this into my xml ?
-1

http://p2p.wrox.com/xslt/66523-create-generic-xsl-template-create-table.html

this xslt generates generic table :

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

  <xsl:output method="html" indent="yes"/>

  <xsl:template match="/*">
    <table border="1" >
      <thead >
        <tr bgcolor="red">
          <xsl:apply-templates select="*[1]/*" mode="th"/>
        </tr>
      </thead>
      <tbody>
        <xsl:apply-templates select="*"/>
      </tbody>
    </table>
  </xsl:template>

  <xsl:template match="/*/*/*" mode="th">
    <th>
      <xsl:value-of select="name()"/>
    </th>
  </xsl:template>

  <xsl:template match="/*/*">
    <tr>
      <xsl:apply-templates select="*"/>
    </tr>
  </xsl:template>

  <xsl:template match="/*/*/*">
    <td>
      <xsl:value-of select="."/>
    </td>
  </xsl:template>

</xsl:stylesheet>

1 Comment

Sorry, but this solution produces just a one (very-long) row table !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.