xsl-list
[Top] [All Lists]

Re: [xsl] Flat list to nested list,grouping

2011-03-31 17:43:14
Kjellaug,

Here's a SS that uses a pseudo-recursive approach to stick in the <list>
markup and a kludge to stick in the <Pkt> markup.  This works with
AltovaXML, I believe it should work with other XSLT 1.0 processors but you
never know. 

Regards,

Murray

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

 <xsl:output version="1.0" method="xml" indent="no" encoding="UTF-8"/>


  <xsl:template match="/">
    <xsl:element name="myresult">
    <xsl:call-template name="handleElement">
      <xsl:with-param name="thisElement" select="child::*[1]/child::*[1]"/>
      <xsl:with-param name="currentLevel" select="0"/>
    </xsl:call-template>
    </xsl:element>
  </xsl:template>


  <xsl:template name="handleElement">
    <xsl:param name="thisElement"/>
    <xsl:param name="currentLevel"/>
    
    <xsl:variable name="thisVal" select="$thisElement/@val"></xsl:variable>
    <xsl:variable name="thisLevel" select="concat(substring-after($thisVal,
'LNum'), substring-after($thisVal, 'LPara'))"/>
    
    <xsl:choose>
      <!-- look for start of new list -->
      <xsl:when test="contains($thisVal, 'LNum') and string($currentLevel)
&lt; $thisLevel">
        <xsl:element name="list">
          <xsl:attribute name="level"><xsl:value-of select="$currentLevel +
1"/></xsl:attribute>
          <xsl:call-template name="handleElement">
            <xsl:with-param name="thisElement" select="$thisElement"/>
            <xsl:with-param name="currentLevel" select="$currentLevel + 1"/>
          </xsl:call-template>
          <xsl:value-of select="'&lt;/Pkt&gt;'"
disable-output-escaping="yes"/>
        </xsl:element>
        <!-- spin forward to end of this list -->
        <xsl:choose>
          <xsl:when test="$currentLevel = 0">
            <xsl:variable name="endofList"
select="$thisElement/following::p[not(starts-with(@val,
'L'))][1]/preceding::*[1]"/>
            <!-- at lowest level we process the next node -->
            <xsl:call-template name="nextElement">
              <xsl:with-param name="thisElement" select="$endofList"/>
              <xsl:with-param name="currentLevel" select="0"/>
            </xsl:call-template>
          </xsl:when>
          <xsl:otherwise>
            <xsl:variable name="endofList"
select="$thisElement/following::p[not(starts-with(@val, 'L')) or
substring(@val, string-length(@val)) &lt;
string($currentLevel)][1]/preceding::*[1]"/>
            <!-- at non-zero level we need to look for "included" list nodes
-->
            <xsl:if test="starts-with($endofList/@val, 'L') and
substring($endofList/@val, string-length($endofList/@val)) =
string($currentLevel)">
              <xsl:value-of select="'&lt;/Pkt&gt;'"
disable-output-escaping="yes"/>
              <xsl:call-template name="handleElement">
                <xsl:with-param name="thisElement" select="$endofList"/>
                <xsl:with-param name="currentLevel" select="$currentLevel"/>
              </xsl:call-template>
            </xsl:if>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <!-- new list item at same level -->
      <xsl:when test="contains($thisVal, 'LNum') and string($currentLevel) =
$thisLevel">
        <xsl:variable name="pktLevel"
select="$thisElement/preceding::*[contains(@val, 'LNum') or
not(starts-with(@val, 'L'))][1]/@val"/>
        <xsl:if test="$thisElement/@val = $pktLevel">
          <xsl:value-of select="'&lt;/Pkt&gt;'"
disable-output-escaping="yes"/>
        </xsl:if>
        <xsl:value-of select="'&lt;Pkt&gt;'" disable-output-escaping="yes"/>
        <xsl:element name="A">
          <xsl:value-of  select="$thisElement"/>
        </xsl:element>
        <xsl:call-template name="nextElement">
          <xsl:with-param name="thisElement" select="$thisElement"/>
          <xsl:with-param name="currentLevel" select="$currentLevel"/>
        </xsl:call-template>
      </xsl:when>
      <!-- list paragrpah -->
      <xsl:when test="contains($thisVal, 'LPara')">
        <xsl:element name="A">
          <xsl:value-of select="$thisElement"/>
        </xsl:element>
        <xsl:call-template name="nextElement">
          <xsl:with-param name="thisElement" select="$thisElement"/>
          <xsl:with-param name="currentLevel" select="$currentLevel"/>
        </xsl:call-template>
      </xsl:when>
      <!-- horse of a different colour -->
      <xsl:otherwise>
        <xsl:choose>
          <xsl:when test="$currentLevel = 0">
            <!-- node at level 0 not "inside" any list -->
            <xsl:copy-of  select="$thisElement"/>
            <xsl:call-template name="nextElement">
              <xsl:with-param name="thisElement" select="$thisElement"/>
              <xsl:with-param name="currentLevel" select="0"/>
            </xsl:call-template>
          </xsl:when>
          <xsl:otherwise><!-- stop recursing --></xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- feed next element to element handler if it exists -->
  <xsl:template name="nextElement">
    <xsl:param name="thisElement"/>
    <xsl:param name="currentLevel"/>
    <xsl:if test="$thisElement/following::*">
      <xsl:call-template name="handleElement">
        <xsl:with-param name="thisElement"
select="$thisElement/following::*[1]"/>
        <xsl:with-param name="currentLevel" select="$currentLevel"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>