Elo: Parameter erhöhen

guten tag,

ich suche schon seid einiger zeit eine lösung für folgendes problem:

input: fußnoten in docbook 5.0, d.h. in der form <footnote><para>hier steht der Fußnotentext</para></footnote> - diese steht direkt im text.

output: im text steht nur die referenzzahl in form von <a id="fn_texti" href="fn_footi">(i)</a> , wobei i die Fußnotenzahl ist.
        am seitenende entsprechend:
<a id="fn:footi" href="fn:texti">und der Fußnotentext</a>

mein erster gedanke war eine for-each schleife, jedoch ergab sich da das problem, dass ich nicht wusste, wie ich den Parameter i beim nächsten schritt erhöhen sollte, z.b. in dem ich das definierte template (name=bulid_anchor) in sich selbst aufrufe. nun habe ich es auf choose umgemünzt und eine for-each schleife drum gesetzt, aber es funktioniert nicht richtig (denn fußnotentext habe ich bisher noch nicht verarbeitet, also keinen rückwärtigen anker erstellt - bitte berücksichtigen):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:d="http://docbook.org/ns/docbook" exclude-result-prefixes="d">
...
<xsl:template match="/">
  <html  xmlns="http://www.w3.org/1999/xhtml">
    <head>
     <title></title>
    </head>
  <body>
 <xsl:call-template name="build_anchor"/>
  </body>
 </html>
</xsl:template>

...

<xsl:template name="build_anchor">
   <xsl:param name="i" select="1"></xsl:param>
 <xsl:for-each select="*">
  xsl:choose
   <xsl:when test="name()='d:footnote'">
    <xsl:element name="a">
     <xsl:attribute name="id">
       xsl:textfn_text</xsl:text>
       <xsl:value-of select="$i"/>
     </xsl:attribute>
     <xsl:attribute name="href">
       xsl:text#fn_foot</xsl:text>
       <xsl:value-of select="$i"/>
     </xsl:attribute>
    xsl:text(</xsl:text><xsl:value-of select="$i"/>xsl:text)</xsl:text>
    <xsl:call-template name="build_anchor">
      <xsl:with-param name="i" select="$i+1"></xsl:with-param>
    </xsl:call-template>
   </xsl:element>
  </xsl:when>
  xsl:otherwise
   <xsl:apply-templates select="current()"/>
  </xsl:otherwise>
 </xsl:choose>
 </xsl:for-each>
</xsl:template>

dieser weg erscheint mir jedoch äußerst umständlich. ist eine erhöhung des parameters i in einer einfach for-each schleife möglich?

ich bitte um tipps und anregungen

mfg elo

  1. Hallo,

    dieser weg erscheint mir jedoch äußerst umständlich. ist eine erhöhung des parameters i in einer einfach for-each schleife möglich?

    Nein, for-each ist in XSL auch gar keine Schleife im klassischen Sinn. XSL ist nämlich eine funktionale Programmiersprache, lies Dir dazu bitte einmal Tims Posting durch.

    Es gibt mit XSLT jedoch ein paar andere Möglichkeiten, das so durchzunummerieren, wie man es haben will:

    xsl:number
    count(preceding::irgendwas)

    (Oder eben Deine rekursiven Templates, was in funktionalen Sprachen eben einer Schleife entspricht)

    Viele Grüße,
    Christian

    1. hallo,

      nun da ich zeit hab, noch ein feedback. hab nochmal alles probiert und tatsächlich funktioniert es mit xsl:number (wenn man das attribut level="any" verwendet) - war mir nicht bekannt;)

      also, hier mal der code:

      <xsl:variable name="foot_nr">
       <xsl:if test="local-name(.)='footnote'"><!--funktioniert nicht -->
        <xsl:number count="d:footnote" format="1" level="any"/>
       </xsl:if>
      </xsl:variable>

      <xsl:template match="d:footnote">
        <a>
         <xsl:attribute name="class">fn_text</xsl:attribute>
         <xsl:attribute name="id">
           xsl:textfn_text</xsl:text>
           <xsl:value-of select="$foot_nr"/>
         </xsl:attribute>
         <xsl:attribute name="href">
           xsl:text#fn_foot</xsl:text>
           <xsl:value-of select="$foot_nr"/>
         </xsl:attribute>
           xsl:text(</xsl:text>
           <xsl:value-of select="$foot_nr"/>
           xsl:text)</xsl:text>
        </a>
      </xsl:template>

      <xsl:template name="footbox"><-- ausgabe dann am ende der html-datei-->
        <div>
         <xsl:attribute name="class">fn</xsl:attribute>
       <xsl:for-each select=".//preceding::d:footnote">
          <p>
           <a>
            <xsl:attribute name="class">fn_foot</xsl:attribute>
            <xsl:attribute name="id">
              xsl:textfn_foot</xsl:text>
              <xsl:value-of select="$foot_nr"/>
            </xsl:attribute>
            <xsl:attribute name="href">
              xsl:text#fn_text</xsl:text>
              <xsl:value-of select="$foot_nr"/>
            </xsl:attribute>
           <xsl:value-of select="$foot_nr"/>
          </a>
          <xsl:value-of select="."/>
         </p>
       </xsl:for-each>
      </div>
      </xsl:template>

      alles soweit okay und funktioniert auch, wenn ich die variablen lokal definiere. sinnvoller ist natürlich eine globale definition und dies habe ich auch versucht zu tun, jedoch wird der knoten nicht richtig ermittelt. selbst wenn ich den pfad mit .//preceding::d:footnote angebe, funktioniert es nicht. ersetze ich probeweise jedoch die xsl:if anweisung mit xsl:for-each und dem pfad .//preceding::d:footnote gibt er etwas aus. auch unter <xsl:number count="..." ist mir eine solche pfadangabe nicht erlaubt? warum bzw. wie sollte ich dann diese knoten ermitteln?

  2. Hallo Elo,

    dieser weg erscheint mir jedoch äußerst umständlich. ist eine erhöhung des parameters i in einer einfach for-each schleife möglich?

    Da die XML-Daten nicht bekannt sind, bin ich mir nicht sicher, wie das umgesetzt werden soll. Da Du XSLT 2.0 verwendest käme zur Generierung der Fußnoten formal auch diese Vorgehensweise in Betracht (to ist ein neuer XPath 2.0-Operator):

    <xsl:for-each select="1 to 5">  
      <xsl:variable name="i" select="position()"/>  
      <a id="fn_text{$i}" href="#fn_foot{$i}"><xsl:value-of select="concat('(',$i,')')"/></a>  
    </xsl:for-each>
    

    wobei für den Wert 5 ein dynamischer stehen müsste, beispielsweise count(whatever_from_xml).

    Grüße,
    Thomas

    1. Hallo miteinander,

      danke erstmal für die tipps und die postings zu for-each waren sehr interessant. nach diesen beiträgen ist hängengeblieben, dass ich in einer for-each anweisung keine dynamischen werte erzeugen bzw. verwenden kann, was defacto eine klassische schleife ausschließt.

      nochmal zu den xml-ausgangsdaten: es handelt sich dabei um docbook 5.0, jedoch mit einer einfachen struktur, d.h.

      <article>
        <info>...
        <sect1>
          <para>
          <para>
          ...
          <sect2>
            <para>
            ...
          <sect2>
            <para>
            <para>
      ,wobei in jedem <para> dann die fußnoten stehen (footnote/para). problem ist also, dass die fußnoten nicht hintereinander stehen bzw. unterschiedliche elternknoten haben - somit ist eine variablendefinition über xsl:number/ oder einem einfachen <xsl:value-of select="position()"/> nicht möglich.
      die von thomas vorgestellte methodik mit a to b funktioniert, hat jedoch den hacken, dass an jeder fußnote alle fußnoten ausgegeben werden - werde probieren, ob ich das lösen kann.
      mein erster gedanke war der einsatz von generate-id und das hat auch prima funktioniert und war nicht allzu kompliziert. wäre eine rückkehr zu dieser variante sinnvoll? es sollte ja nicht nur funktionieren, sondern die eingesetzte methode sollte auch nachvollziehbar und sinnvoll sein. bin von der idee abgekommen, da ich meine, gelesen zu haben, dass id's in diesem sinne nur intern verarbeitet werden.

      Grüße Elo und für weitere anregungen/anmerkungen wäre ich dankbar;)