Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use XSLT recursion to convert any xml data to a html table view:

Tags:

java

xml

xslt

For a given xml, I need to generate a html table to represent the values in the xml. I need the recursion for any keyN, if valueN is text then just print it. If valueN is xml, then print a (nested)table with it's value. I think my lack of understanding of how to use XSLT recursion correctly is the base of the question. Any help appreciated.

Input:

<root>
    <key1> Text Value  </key1>
<key2> 
    <a> aaa </a>
    <b> bbb </b>
</key2>
<keyN> valueN </keyN>
<root>

Output:

<table border="1px">
    <tr>
        <td> key1 </td>
        <td> Text Value </td>
    </tr>

    <tr>
        <td> key2 </td>
        <td>
            <table border="1px">
                <tr> <td> a </td> <td> aaa </td> </tr>
                <tr> <td> b </td> <td> bbb </td> </tr>
            </table>
        </td>
    </tr>

    <tr> 
        <td> keyN </td>
        <td>
            valueN (if valueN is text)
                    OR
            <table> ... </table> (if valueN is xml)
        <td>
    </tr>
</table>
like image 659
sanjayav Avatar asked May 30 '26 08:05

sanjayav


2 Answers

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/*//*[1]">
        <table border="1">
            <xsl:call-template name="makeRow"/>
        </table>
    </xsl:template>
    <xsl:template match="*" name="makeRow">
        <tr>
            <td>
                <xsl:value-of select="name()"/>
            </td>
            <td>
                <xsl:apply-templates select="node()[1]"/>
            </td>
        </tr>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="/*">
        <xsl:apply-templates select="node()[1]"/>
    </xsl:template>
</xsl:stylesheet>

Output:

<table border="1">
    <tr>
        <td>key1</td>
        <td> Text Value  </td>
    </tr>
    <tr>
        <td>key2</td>
        <td>
            <table border="1">
                <tr>
                    <td>a</td>
                    <td> aaa </td>
                </tr>
                <tr>
                    <td>b</td>
                    <td> bbb </td>
                </tr>
            </table></td>
    </tr>
    <tr>
        <td>keyN</td>
        <td> valueN </td>
    </tr>
</table>

Note: This use the fine grained traversal patter. Three rules: "first child descendant of root element", output table and call makeRow; makeRow (match any element not being the first child descendant nor root element) output tr and table cells with name and first child applycation, then apply templates to next sibling; root element rule, start the fine grained traversal.

This transformation:

<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:template match="/*">
  <table border="1px">
   <xsl:apply-templates/>
  </table>
 </xsl:template>

 <xsl:template match="*[*][parent::*]">
     <tr>
      <td><xsl:value-of select="name()"/></td>
      <td>
        <table border="1px">
          <xsl:apply-templates/>
        </table>
      </td>
     </tr>
 </xsl:template>

 <xsl:template match="*[not(*)]">
   <tr>
      <td><xsl:value-of select="name()"/></td>
    <td><xsl:value-of select="."/></td>
   </tr>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<root>
    <key1> Text Value  </key1>
    <key2>
        <a> aaa </a>
        <b> bbb </b>
    </key2>
    <keyN> valueN </keyN>
</root>

produces the wanted, correct result:

<table border="1px">
   <tr>
      <td>key1</td>
      <td> Text Value  </td>
   </tr>
   <tr>
      <td>key2</td>
      <td>
         <table border="1px">
            <tr>
               <td>a</td>
               <td> aaa </td>
            </tr>
            <tr>
               <td>b</td>
               <td> bbb </td>
            </tr>
         </table>
      </td>
   </tr>
   <tr>
      <td>keyN</td>
      <td> valueN </td>
   </tr>
</table>

Do note the power of XSLT:

  1. No explicit recursion.

  2. No conditionals inside any template.

  3. Completely push-style of processing.

like image 35
Dimitre Novatchev Avatar answered May 31 '26 20:05

Dimitre Novatchev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!