Re: [xsl] xpath dynamic selection

Subject: Re: [xsl] xpath dynamic selection
From: Wim Lemkens <wim.lemkens@xxxxxxxxxx>
Date: Sun, 11 Jul 2004 13:13:38 +0200
On Sunday 11 July 2004 11:09, Jeni Tennison wrote:
> Hi Wim,
>
> I found it really quite difficult to follow your question. It would
> help if you could show an small sample of your input XML and the
> output that you'd like to generate from it, plus all the relevant
Thanks for the suggestions.
Ok, I'll clearify my vague question with some real code. But it is rather 
long.

This is the relevant part of the input:
<usecase>
<title>Zoek boek op</title>
<description>De gebruiker heeft gegevens van een bepaald boek dat hij wilt 
ontlenen en wilt weten waar het boek zich bevindt in de 
bibliotheek.</description>
<actor>De gebruiker vult in eventueel verschillende velden gegevens in over 
een boek dat hij zoekt.</actor>
<system>
  <alt>1</alt>
  Het systeem geeft een overzicht van de verschillende boeken die voldoen aan 
de zoekterm
</system>
<actor>
  <alt>2</alt>
  De gebruiker kiest het boek dat hij wilt opvragen
</actor>
<system>
  Het systeem geeft de gegevens van het gevonden boek weer.
</system>
<alternativecourses>
  <alternative>
    <system>
      Er is maar 1 overeenkomstig resultaat : Het systeem geeft direct de 
gegevens van het gevonden boek weer.
    </system>
  </alternative>
  <alternative>
    <actor>
      De gebruiker kiest om te zoeken op nieuwe gegevens.
    </actor>
    <system>
      Het systeem geeft de invulvelden terug weer. (terug van stap 1)
    </system>
  </alternative>
</alternativecourses>
</usecase>

The required output would be: (without debug info):

De gebruiker heeft gegevens van een bepaald boek dat hij wilt ontlenen en wilt 
weten waar het boek zich bevindt in de bibliotheek.

1 De gebruiker vult in eventueel verschillende velden gegevens in over een 
boek dat hij zoekt.
2		Het systeem geeft een overzicht van de verschillende boeken die voldoen aan 
de zoekterm
3 De gebruiker kiest het boek dat hij wilt opvragen 
4		Het systeem geeft de gegevens van het gevonden boek weer. Het systeem geeft 
de gegevens van het gevonden boek weer. 

Alternatieve Paden
2		Er is maar 1 overeenkomstig resultaat : Het systeem geeft direct de 
gegevens van het gevonden boek weer. 

<<(note this is the second alternative)>>
3 De gebruiker kiest om te zoeken op nieuwe gegevens. 
4		Het systeem geeft de invulvelden terug weer. (terug van stap 1) 


And here are the important parts of xsl:
<xsl:template match="usecase">
  <<snip: some numbering setup copied from orderedlist>>

  <xsl:variable name="start">
    <xsl:choose>
      <xsl:when test="@continuation='continues'">
        <xsl:call-template name="usecase-starting-number"/>
      </xsl:when>
      <xsl:when test="$pi-start != ''">
        <xsl:value-of select="$pi-start"/>
      </xsl:when>
      <xsl:otherwise>1</xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <<snip: some numbering setup copied from orderedlist>>

  <div class="{name(.)}">
    <xsl:call-template name="anchor"/>

    <xsl:if test="title">
     <xsl:call-template name="formal.object.heading"/>
    </xsl:if>
    <table class="usecase">
    <xsl:if test="description">
     <xsl:apply-templates select="description"/>
    </xsl:if>
  <tr><td>
    <ol>
      <xsl:if test="$start != '1'">
        <xsl:attribute name="start">
          <xsl:value-of select="$start"/>
        </xsl:attribute>
      </xsl:if>
  <<snip: some numbering setup copied from orderedlist>>
      <xsl:apply-templates select="*[(self::actor
                                   or self::system)]"/>
    </ol>
   </td></tr>
  </table>
      <xsl:apply-templates select="alternativecourses"/>
  </div>
   
    <xsl:apply-templates select="*[not(self::actor
                                   or self::title
				   or self::alternativecourses
				   or self::description
				   or self::system)]"/>
</xsl:template>

<xsl:template match="usecase/actor">
  <xsl:param name="ucid"/>
  <li>
    <xsl:attribute name="number">
        <xsl:call-template name="usecase-step-number"/>
    </xsl:attribute>
    <xsl:variable name="step">
        <xsl:call-template name="usecase-step-number"/>
    </xsl:variable>

  <div class="actor">
  	<xsl:apply-templates match="alt">
	  <xsl:with-param name="step" select="$step"/>
	</xsl:apply-templates>
	<xsl:apply-templates select="*[not(self::alt)]"/>
  </div>
  </li>
</xsl:template>

<xsl:template match="usecase/system">
  <li>
    <xsl:attribute name="number">
        <xsl:call-template name="usecase-step-number"/>
    </xsl:attribute>
    <xsl:variable name="step">
        <xsl:call-template name="usecase-step-number"/>
    </xsl:variable>
  <div class="system">
  	<xsl:apply-templates match="alt">
	  <xsl:with-param name="step" select="$step"/>
	</xsl:apply-templates>
	<xsl:apply-templates/>
  </div>
  </li>
</xsl:template>

<xsl:template match="alternativecourses">
     Alternatieve Paden
    <xsl:param name="node" select="."/>
  
  <div class="{name(.)}">
    <xsl:call-template name="anchor"/>

    <xsl:if test="title">
     <xsl:call-template name="formal.object.heading"/>
    </xsl:if>
    <table class="usecase">
    <xsl:if test="description">
     <xsl:apply-templates select="description"/>
    </xsl:if>
    <tr><td>
    <ol>
  	<xsl:apply-templates match="alternativecourses/alternative">
	</xsl:apply-templates>
    </ol>
   </td></tr>
  </table>
  </div> 
</xsl:template>

<xsl:template match="alt">
    <xsl:param name="step"/>
    
    <xsl:param name="number">
      <xsl:apply-templates/>
    </xsl:param>
<!-- temporary debuginfo -->
ucid : <xsl:copy-of select="$ucid"/>
number : <xsl:copy-of select="$number"/>
step : <xsl:copy-of select="$step"/>
</xsl:template>

<xsl:template match="alternativecourses/alternative/actor">
  <li>
    <xsl:attribute name="number">
        <xsl:call-template name="alternative-step-number"/>
    </xsl:attribute>
  <div class="actor">
	<xsl:apply-templates/>
  </div>
  </li>
</xsl:template>

<xsl:template match="alternativecourses/alternative/system">
  <li>
    <xsl:attribute name="number">
        <xsl:call-template name="alternative-step-number"/>
    </xsl:attribute>
  <div class="system">
	<xsl:apply-templates/>
  </div>
  </li>
</xsl:template>

<xsl:template match="alternativecourses/alternative">
    <xsl:param name="node" select="."/>
    <xsl:param name="number">
      <xsl:call-template name="alternative-number"/>
    </xsl:param>

	<!-- get the startignumber 			_problem is here!!!!_ -->
    <xsl:param name="start">
	<xsl:value-of select="ancestor::../../*/alt[@number=current()/@number]"/>
    </xsl:param>    

<!-- temporary debug info -->
    anumber : <xsl:copy-of select="$number"/>
    step : <xsl:copy-of select="$start"/>

    	<!-- generate the new list -->
  <xsl:variable name="pi-start">
    <xsl:call-template name="dbhtml-attribute">
      <xsl:with-param name="pis"
                      select="processing-instruction('dbhtml')"/>
      <xsl:with-param name="attribute" select="'start'"/>
    </xsl:call-template>
  </xsl:variable>

  <xsl:variable name="numeration">
    <xsl:call-template name="list.numeration"/>
  </xsl:variable>

  <xsl:variable name="type">
    <xsl:choose>
      <xsl:when test="$numeration='arabic'">1</xsl:when>
      <xsl:when test="$numeration='loweralpha'">a</xsl:when>
      <xsl:when test="$numeration='lowerroman'">i</xsl:when>
      <xsl:when test="$numeration='upperalpha'">A</xsl:when>
      <xsl:when test="$numeration='upperroman'">I</xsl:when>
      <!-- What!? This should never happen -->
      <xsl:otherwise>
        <xsl:message>
          <xsl:text>Unexpected numeration: </xsl:text>
          <xsl:value-of select="$numeration"/>
        </xsl:message>
        <xsl:value-of select="1"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  
  <div class="{name(.)}">
    <xsl:call-template name="anchor"/>
  <tr><td>
    <ol>
      <xsl:if test="$start != '1'">
        <xsl:attribute name="start">
          <xsl:value-of select="$start"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:if test="$numeration != ''">
        <xsl:attribute name="type">
          <xsl:value-of select="$type"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:if test="@spacing='compact'">
        <xsl:attribute name="compact">
          <xsl:value-of select="@spacing"/>
        </xsl:attribute>
      </xsl:if>
    <xsl:apply-templates select="*[(self::actor
                                   or self::system)]"/>
    </ol>
   </td></tr>
  </div>
  
    <xsl:apply-templates select="*[not(self::actor
                                   or self::title
				   or self::description
				   or self::system)]"/>
</xsl:template>

<xsl:template name="usecase-step-number">
  <!-- context node must be a system or actor in a usecase -->
  <xsl:param name="node" select="."/>

  <xsl:choose>
    <xsl:when test="$node/@override">
      <xsl:value-of select="$node/@override"/>
    </xsl:when>
    <xsl:when test="$node/preceding-sibling::*[(self::system or 
self::actor)]">
      <xsl:variable name="pnum">
        <xsl:call-template name="usecase-step-number">
          <xsl:with-param name="node" 
select="$node/preceding-sibling::*[(self::system or self::actor)][1]"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:value-of select="$pnum + 1"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="usecase-starting-number">
        <xsl:with-param name="list" select="parent::*"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="usecase-starting-number">
  <xsl:param name="list" select="."/>
  <xsl:choose>
    <xsl:when test="not($list/@continuation = 'continues')">1</xsl:when>
    <xsl:otherwise>
      <xsl:variable name="prevlist"
                    select="$list/preceding::usecase[1]"/>
      <xsl:choose>
        <xsl:when test="count($prevlist) = 0">2</xsl:when>
        <xsl:otherwise>
          <xsl:variable name="prevlength" select="count($prevlist/listitem)"/>
          <xsl:variable name="prevstart">
            <xsl:call-template name="usecase-starting-number">
              <xsl:with-param name="list" select="$prevlist"/>
            </xsl:call-template>
          </xsl:variable>
          <xsl:value-of select="$prevstart + $prevlength"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="alternative-number">
  <xsl:param name="node" select="."/>

  <xsl:choose>
    <xsl:when test="$node/@override">
      <xsl:value-of select="$node/@override"/>
    </xsl:when>
    <xsl:when test="$node/preceding-sibling::alternative">
      <xsl:variable name="pnum">
        <xsl:call-template name="alternative-number">
          <xsl:with-param name="node" 
select="$node/preceding-sibling::alternative[1]"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:value-of select="$pnum + 1"/>
    </xsl:when>
    <xsl:otherwise>
      1
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="alternative-step-number">
  <!-- context node must be a system or actor in alternative -->
  <xsl:param name="node" select="."/>

  <xsl:choose>
    <xsl:when test="$node/@override">
      <xsl:value-of select="$node/@override"/>
    </xsl:when>
    <xsl:when test="$node/preceding-sibling::*[(self::system or 
self::actor)]">
      <xsl:variable name="pnum">
        <xsl:call-template name="usecase-step-number">
          <xsl:with-param name="node" 
select="$node/preceding-sibling::*[(self::system or self::actor)][1]"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:value-of select="$pnum + 1"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="usecase-starting-number">
        <xsl:with-param name="list" select="parent::*"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

I hope this code helps more to comprehend the question.
The problem is locate around line 221 of the mail.

I tried the things you suggested, but they didn't work.


Thanks,

Wim Lemkens

Current Thread