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
John
  • 2,820
  • 3
  • 30
  • 50

3 Answers3

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>
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • 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 Aug 29 '18 at 13:45
  • @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 `` to `2.0` and this transformation should be executed with no such warning message, and should produce the same results – Dimitre Novatchev Aug 29 '18 at 14:33
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>
Pencho Ilchev
  • 3,201
  • 18
  • 21
  • 1
    @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. – Dimitre Novatchev Dec 24 '11 at 16:25
  • How can I apply this into my xml ? – Arnab Jun 21 '21 at 14:11
-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>
adt
  • 4,320
  • 5
  • 35
  • 54