RE: [xsl] maximum depth of nested tags needed for colspan

Subject: RE: [xsl] maximum depth of nested tags needed for colspan
From: bryan.s.schnabel@xxxxxxxxxxxxxx
Date: Mon, 10 Nov 2003 12:25:13 -0800
I think I understand what you want to do.

I would probably determine the maximum number of <question>s that would make
could make up a target <row>, and set that as a parameter, then for each <b>
or <f>, count the number of <question>s, and, via call-template, recursively
add a "filler" <cell>s until each <row> had the number of <cell>s it needed
to comply with the number sent in the parameter.

I added a few <question>s to you input file to better illustrate the point.

So this XSL:

<xsl:template match="node()|@*">
 <xsl:copy>
  <xsl:apply-templates select="@*|node()"/>
 </xsl:copy>
</xsl:template>

<xsl:variable name="colcount">
 <xsl:for-each select="a/b | a/f">
  <xsl:sort order="descending" select="count(.//question)" />
   <xsl:if test="position()=1">
    <xsl:value-of select="count(.//question)"/>
   </xsl:if>
  </xsl:for-each>
</xsl:variable>

<xsl:template match="a">
 <table>
   <xsl:attribute name="cols">
    <xsl:value-of select="$colcount" />
   </xsl:attribute>
   <xsl:apply-templates />
 </table>
</xsl:template>

<xsl:template match="b | f">
 <row>
  <xsl:variable name="hi">
   <xsl:for-each select=".//question">
    <xsl:sort order="descending" select="count(.//question)" />
     <xsl:if test="position()=1">
      <xsl:value-of select="count(.//question) + 1"/>
     </xsl:if>
   </xsl:for-each>
  </xsl:variable>
  <xsl:if test="$hi &lt; $colcount">
   <xsl:call-template name="nexter">
    <xsl:with-param name="for-next" select="$colcount" />
    <xsl:with-param name="for-bottom" select="$hi" />
   </xsl:call-template>
  </xsl:if>

  <xsl:for-each select=".//question">
   <xsl:sort order="ascending"  />
    <cell>
     <xsl:value-of select="count(descendant::question) + 1" />
    </cell>
  </xsl:for-each>
 </row>
</xsl:template>

<xsl:template name="nexter">
 <xsl:param name="for-next" />
 <xsl:param name="for-bottom" />
 <xsl:variable name="adj-next" select="$for-next - 1" />
 <cell filler="yes">
  <xsl:value-of select="$for-next" />
 </cell>
 <xsl:if test="$adj-next > $for-bottom">
   <xsl:call-template name="nexter">
    <xsl:with-param name="for-next" select="$adj-next" />
    <xsl:with-param name="for-bottom" select="$for-bottom" />
   </xsl:call-template>
 </xsl:if>
</xsl:template>

Applied to this input:

<a>
  <b>
    <question>
       <c/>
      <question>
         <d/>
        <question>
          <e/>
        </question>
      </question>
    </question>
  </b>
  <f>
    <question>
      <question>
        <question>
          <question>
            <g/>
          </question>
        </question>
      </question>
    </question>
  </f>
  <f>
    <question>
      <question>
        <question>
         <question>
           <question>
             <question>
               <question>
                 <g/>
               </question>
             </question>
           </question>
         </question>
        </question>
      </question>
    </question>
  </f>
</a>

produces this crude table:

<table cols="7">
   <row>
      <cell filler="yes">7</cell>
      <cell filler="yes">6</cell>
      <cell filler="yes">5</cell>
      <cell filler="yes">4</cell>
      <cell>3</cell>
      <cell>2</cell>
      <cell>1</cell>
   </row>
   <row>
      <cell filler="yes">7</cell>
      <cell filler="yes">6</cell>
      <cell filler="yes">5</cell>
      <cell>4</cell>
      <cell>3</cell>
      <cell>2</cell>
      <cell>1</cell>
   </row>
   <row>
      <cell>7</cell>
      <cell>6</cell>
      <cell>5</cell>
      <cell>4</cell>
      <cell>3</cell>
      <cell>2</cell>
      <cell>1</cell>
   </row>
</table>

You'd need to fiddle with it to get the cells to contain desired values.

Bryan Schnabel

-----Original Message-----
From: Andy Verbunt [mailto:andy@xxxxxxxx] 
Sent: Friday, November 07, 2003 11:47 AM
To: XSL-List@xxxxxxxxxxxxxxxxxxxxxx
Subject: [xsl] maximum depth of nested tags needed for colspan


Hi there,

I wish somebody could help me with the problem I've been having for
quite a few days now:

I have this xml file:

<a>
  <b>
    <question>
       <c/>
      <question>
         <d/>
        <question>
          <e/>
        </question>
      </question>
    </question>
  </b>
  <f>
    <question>
      <question>
        <question>
          <question>
            <g/>
          </question>
        </question>
      </question>
    </question>
  </f>
</a>

I never checked this xml, but I guess you catch my drift...

The question-tags are relevant, but nevertheless, I put some other tags
in and around the question tags to show you that there's more than one
type of tag.

I'd like to make an xslt that can transform this xml to html, actually
to a table. I need to indent questions which are deeper in the
hierarchy.
Basically this means that I need to transform the a-tag to a table tag.
I need the maximum depth of the question tags as a colspan attribute for
the td-tag in order to get the indentation right. In this case that
would be: 4, since <f> contains 4 nested question tags while <b>
contains only 3.

I found some similar examples in 'XSLT 2nd edition' from Michael Kay,
which were solved using recursion, but these were not about nested tags.
He uses some trick with two params: first and max-of-rest, but the tags
he uses are all on the same 'level', while my question-tags are nested.
I added that code at the end of my message. 

Adding a level attribute with the current depth to the question tag is
easy using count(ancestor::question) but I cannot find out how to add
the 4 (in this case) to the first tag.

Please help...
Kind regards,
Andy.


	<xsl:template name="max">
		<xsl:param name="list"/>
		<xsl:choose>
			<xsl:when test="$list">
				<xsl:variable name="first"
select="count($list[1]/LINE)"/>
				<xsl:variable name="max-of-rest">
					<xsl:call-template name="max">
						<xsl:with-param
name="list" select="$list[position()!=1]"/>
					</xsl:call-template>
				</xsl:variable>
				<xsl:choose>
					<xsl:when test="$first &gt;
$max-of-rest">
						<xsl:value-of
select="$first"/>
					</xsl:when>
					<xsl:otherwise>
						<xsl:value-of
select="$max-of-rest"/>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:when>
			<xsl:otherwise>0</xsl:otherwise>
		</xsl:choose>
	</xsl:template>



 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread