Search code examples
xmlrecursionxslt

XSLT conversion with recursion


I need to convert an XML document to HTML.

Input XML:

<items>
    <item no="1" par_no="0" user="Mike">Hi all!</item>
    <item no="2" par_no="1" user="Jane">Hi...</item>
    <item no="3" par_no="2" user="Pit"> says: wasap man?</item>
    <item no="4" par_no="2" user="Karol">are you ok?</item>
    <item no="5" par_no="4" user="Nick">I think he's not in the mood.</item>
    <item no="6" par_no="5" user="Karol">I just ask a question.</item>
    <item no="7" par_no="1" user="Pit">says: how are you?</item>
    <item no="8" par_no="7" user="Mike">fine!</item>
</items>

Output HTML:

<?xml version="1.0" encoding="UTF-8"?>
<ul>
  <li><b>Mike</b> says: Hi all!
    <ul>
      <li><b>Jane</b>  says: Hi...
          <li><b>Pit</b> says: wasap man?
          <li><b>Karol</b> says: are you ok?
            <ul>
              <li><b>Nick</b> says: I tihnk he's not in the mood.
                <ul>
                  <li><b>Karol</b> says: I just ask a question.
                </ul>
              </li>
            </ul>
          </li>
        </ul>
      </li>
      <li><b>Pit</b> says: how are you?
        <ul>
          <li><b>Mike</b> says: fine!
        </ul>
      </li>
    </ul>
  </li>
</ul>

I tried to solve this problem. I got the code. The rows are being ordered, but I can't get the attachment. My XSL:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
 <xsl:output method="html" /> 
 <xsl:template match="items"> 
    <html> 
        <ul>
            <xsl:apply-templates select="item[@par_no=0]"/> 
            
        </ul>
    </html> 
 </xsl:template> 
 
 <xsl:template match="item">    
    
    <xsl:variable name="varNo" select="@no"/> 
    
        <li>
            <b><xsl:value-of select="@user"/></b>
            <xsl:text> says: </xsl:text>
            <xsl:value-of select="."/> 
        </li>   
 
    <xsl:apply-templates select="//items/item[@par_no=$varNo]"> 
        <xsl:sort select="@par_no" data-type="number"/>                 
    </xsl:apply-templates> 
    
 </xsl:template> 
</xsl:stylesheet>

I do not know where to insert tags to get such a nested structure. Please help!


Solution

  • I think you could do simply (using only XSLT 1.0):

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html"/>
    
    <xsl:key name="chld" match="item" use="@par_no" />
    
    <xsl:template match="/items">
        <ul>
            <xsl:apply-templates select="item[@par_no='0']"/>
        </ul>
    </xsl:template>
    
    <xsl:template match="item">
        <li>
            <b>
                <xsl:value-of select="@user"/>
            </b>
            <xsl:text> says: </xsl:text>
            <xsl:value-of select="."/>
            <ul>
                <xsl:apply-templates select="key('chld', @no)"/>
            </ul>
        </li>
    </xsl:template>
    
    </xsl:stylesheet>
    

    The result, as displayed in a browser, is:

    enter image description here

    Try it here.