<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/pool/xslt_ht.xslt" type="application/xml"?>
<xsl:stylesheet
  xmlns:d = "http://herbaer.de/xmlns/20051201/doc"
  xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
  xmlns:xl = "http://www.w3.org/1999/xlink"
  version = "1.0"
  exclude-result-prefixes = "xl"
>
<!--
  Hilfsvorlagen zur Ausgabe und Verarbeitung von Text
  2009, 2014 Herbert Schiemann <h.schiemann@herbaer.de>
  Borkener Str. 167, 46284 Dorsten, Germany
  Diese Datei wird unter den Bedingungen der GPL Version 3 oder
  einer neueren Version weitergegeben.
  Jede Gewährleistung ist ausgeschlossen.

  2014-04-12 txt.righttrim
  2014-05-19 txt.lefttrim
  2020-06-19 txt.split: Paramter prev
-->
<d:info xmlns="http://herbaer.de/xmlns/20051201/doc">
  <title>txt.xslt</title>
  <subtitle>Hilfsvorlagen zur Ausgabe und Verarbeitung von Text</subtitle>
  <date>2012-01-01</date>
  <author>
    <personname>
      <firstname>Herbert</firstname>
      <surname>Schiemann</surname>
    </personname>
    <email>h.schiemann@herbaer.de</email>
  </author>
</d:info>

<d:para>
  Das Wurzelelement für Text-Vorlagen
</d:para>
<xsl:variable name="txt.docroot" select="document('')/xsl:stylesheet"/>

<d:para>
  Die Zeichenfolge, die einen Zeilenwechsel kodiert
</d:para>
<xsl:variable name="txt.break">
  <xsl:text>
</xsl:text>
</xsl:variable>

<d:para>
  Zeichen, die in einem üblichen Programmiersprachen-Namen erlaubt sind
</d:para>
<xsl:variable
  name = "txt.namechars"
  select = "'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'"
/>

<d:para>
  Wiederholt einen Text
</d:para>
<xsl:template name="txt.repeat">
  <!-- Der Text, der wiederholt wird -->
  <xsl:param name="txt" select="' '"/>

  <!-- Die Anzahl: so oft wird der Text ausgegeben -->
  <xsl:param name="count" select="0"/>

  <xsl:choose>
    <xsl:when test="string-length ($txt) = 0 or $count &lt; 1"/>
    <xsl:when test="$count = 1">
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:if test="$count mod 2 &gt;= 1">
        <xsl:value-of select="$txt"/>
      </xsl:if>
      <xsl:call-template name="txt.repeat">
        <xsl:with-param name="txt" select="concat ($txt, $txt)"/>
        <xsl:with-param name="count" select="floor ($count div 2)"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.repeat -->

<d:para>
  Richtet einen Text in einem Feld aus.
  Auch wenn der Text länger ist als das Feld,
  wird der gesamte Text ausgegeben.
</d:para>
<xsl:template name="txt.fillfield">
  <!-- der einzusetzende Text -->
  <xsl:param name="txt" select="."/>
  <!-- die Feldbreite -->
  <xsl:param name="width" select="12"/>
  <!-- das Füllzeichen -->
  <xsl:param name="fillchar" select="' '"/>
  <!-- die Ausrichtung: links (l), zentriert (c) oder rechts (r) -->
  <xsl:param name="align" select="'l'"/>

  <xsl:variable name="len" select="string-length ($txt)"/>
  <xsl:choose>
    <xsl:when test="$len &gt;= $width">
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:when test="starts-with ($align, 'l')">
      <xsl:value-of select="$txt"/>
      <xsl:call-template name="txt.repeat">
        <xsl:with-param name="txt" select="$fillchar"/>
        <xsl:with-param name="count" select="$width - $len"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="starts-with ($align, 'r')">
      <xsl:call-template name="txt.repeat">
        <xsl:with-param name="txt" select="$fillchar"/>
        <xsl:with-param name="count" select="$width - $len"/>
      </xsl:call-template>
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="lft" select="floor (($width - $len) div 2)"/>
      <xsl:call-template name="txt.repeat">
        <xsl:with-param name="txt" select="$fillchar"/>
        <xsl:with-param name="count" select="$lft"/>
      </xsl:call-template>
      <xsl:value-of select="$txt"/>
      <xsl:call-template name="txt.repeat">
        <xsl:with-param name="txt" select="$fillchar"/>
        <xsl:with-param name="count" select="$width - $lft"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.fillfield -->

<d:para>
  Ersetzt Zeichenfolgen, die nicht durch ein nachfolgendes
  besonderes Zeichen geschützt sind (backward protection)
</d:para>
<xsl:template name="txt.replace_bprot">
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>

  <!-- Die zu ersetzende Zeichenfolge -->
  <xsl:param name="what" select="$txt.break"/>

  <!-- Die einzusetzende Zeichenfolge -->
  <xsl:param name="with" select="' '"/>

  <!-- Die Zeichen, die "rückwärts" schützen -->
  <xsl:param name="bprotect" select="'&#9;&#10;&#13; '"/>

  <xsl:choose>
    <xsl:when
      test = "
        string-length ($txt) = 0
        or string-length ($what) = 0
        or not (contains ($txt, $what))
      "
    >
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="after" select="substring-after ($txt, $what)"/>
      <xsl:value-of select="substring-before ($txt, $what)"/>
      <xsl:choose>
        <xsl:when
          test = "
            string-length ($after) &gt; 0
            and contains ($bprotect, substring ($after, 1, 1))
          "
        >
          <xsl:value-of select="$what"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$with"/>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:call-template name="txt.replace_bprot">
        <xsl:with-param name="txt" select="$after"/>
        <xsl:with-param name="what" select="$what"/>
        <xsl:with-param name="with" select="$with"/>
        <xsl:with-param name="bprotect" select="$bprotect"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.replace_bprot -->

<d:para>
  Ersetzt Teilzeichenfolgen global nach Vorgabe einer Liste:
  Der erste Listeneintrag wird durch den zweiten ersetzt,
  der dritte durch den vierten usw.
  Wenn die Anzahl der Listeneinträge ungerade ist,
  wird der letzte Listeneintrag durch die leere Zeichenkette ersetzt.
</d:para>
<xsl:template name="txt.replacelist">
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>

  <!-- Die Liste der zu ersetzenden und einzusetzenden Teilzeichenfolgen -->
  <xsl:param name="list"/>

  <!-- Die Listen-Trennzeichenfolge -->
  <xsl:param name="sep" select="','"/>

  <xsl:choose>
    <xsl:when test="            string-length ($txt) = 0         or string-length ($list) = 0       "
    >
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="what">
        <xsl:call-template name="txt.firstentry">
          <xsl:with-param name="txt" select="$list"/>
          <xsl:with-param name="sep" select="$sep"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:variable name="what_rem">
        <xsl:call-template name="txt.remaininglist">
          <xsl:with-param name="txt" select="$list"/>
          <xsl:with-param name="sep" select="$sep"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:variable name="with">
        <xsl:call-template name="txt.firstentry">
          <xsl:with-param name="txt" select="$what_rem"/>
          <xsl:with-param name="sep" select="$sep"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:variable name="rem">
        <xsl:call-template name="txt.remaininglist">
          <xsl:with-param name="txt" select="$what_rem"/>
          <xsl:with-param name="sep" select="$sep"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:choose>
        <xsl:when test="string-length ($what) &gt; 0 and contains ($txt, $what)">
          <xsl:call-template name="txt.replacelist">
            <xsl:with-param name="txt" select="substring-before ($txt, $what)"/>
            <xsl:with-param name="list" select="$rem"/>
            <xsl:with-param name="sep" select="$sep"/>
          </xsl:call-template>
          <xsl:value-of select="$with"/>
          <xsl:call-template name="txt.replacelist">
            <xsl:with-param name="txt" select="substring-after ($txt, $what)"/>
            <xsl:with-param name="list" select="$list"/>
            <xsl:with-param name="sep" select="$sep"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="txt.replacelist">
            <xsl:with-param name="txt" select="$txt"/>
            <xsl:with-param name="list" select="$rem"/>
            <xsl:with-param name="sep" select="$sep"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.replacelist -->

<d:para>
Ersetzt einzelne Zeichen durch Einträge in einer Liste,
entfernt "überzählige" Zeichen
</d:para>
<xsl:template name="txt.replacechars">
  <!-- Der Text, in dem Zeichen ersetzt werden -->
  <xsl:param name="txt" select="."/>

  <!-- Die zu ersetzenden Zeichen -->
  <xsl:param name="chars"/>
  <!--
    Die Liste der Ersatzzeichenfolgen.
    Wenn diese Liste weniger Einträge enthält, als chars Zeichen,
    dann werden die "überzähligen" Zeichen entfernt.
  -->
  <xsl:param name="list"/>

  <!-- Die Listen-Trennzeichenfolge -->
  <xsl:param name="sep" select="','"/>

  <xsl:choose>
    <xsl:when test="string-length ($txt) = 0"/>
    <xsl:when test="string-length ($chars) = 0">
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="rlist">
        <xsl:if test="string-length ($sep) &gt; 0 and contains ($list, $sep)">
          <xsl:value-of select="substring-after ($list, $sep)"/>
        </xsl:if>
      </xsl:variable>
      <xsl:variable name="ch" select="substring ($chars, 1, 1)"/>
      <xsl:choose>
        <xsl:when test="contains ($txt, $ch)">
          <xsl:call-template name="txt.replacechars">
            <xsl:with-param name="txt" select="substring-before ($txt, $ch)"/>
            <xsl:with-param name="chars" select="substring ($chars, 2)"/>
            <xsl:with-param name="list" select="$rlist"/>
            <xsl:with-param name="sep" select="$sep"/>
          </xsl:call-template>
          <xsl:choose>
            <xsl:when test="string-length ($sep) &gt; 0 and contains ($list, $sep)">
              <xsl:value-of select="substring-before ($list, $sep)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$list"/>
            </xsl:otherwise>
          </xsl:choose>
          <xsl:call-template name="txt.replacechars">
            <xsl:with-param name="txt" select="substring-after ($txt, $ch)"/>
            <xsl:with-param name="chars" select="$chars"/>
            <xsl:with-param name="list" select="$list"/>
            <xsl:with-param name="sep" select="$sep"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="txt.replacechars">
            <xsl:with-param name="txt" select="$txt"/>
            <xsl:with-param name="chars" select="substring ($chars, 2)"/>
            <xsl:with-param name="list" select="$rlist"/>
            <xsl:with-param name="sep" select="$sep"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.replacechars -->

<d:para>
Entfernt Leerzeichen um bestimmte Zeichen herum
</d:para>
<xsl:template name="txt.remove_space_around">

  <!-- Der zu verkürzende Text -->
  <xsl:param name="txt" select="normalize-space (.)"/>

  <!-- Die Zeichen, deren umgebende Leerzeichen entfernt werden -->
  <xsl:param name="chars" select="'(){}[]=;+*:,'"/>

  <xsl:choose>
    <xsl:when test="string-length ($chars) = 0">
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="txt.remove_space_around">
        <xsl:with-param name="txt">
          <xsl:variable name="chr" select="substring ($chars, 1, 1)"/>
          <xsl:variable name="sep">
            <xsl:choose>
              <xsl:when test="$chr = '#'">,</xsl:when>
              <xsl:otherwise>#</xsl:otherwise>
            </xsl:choose>
          </xsl:variable>
          <xsl:call-template name="txt.replacelist">
            <xsl:with-param name="txt" select="$txt"/>
            <xsl:with-param
              name = "list"
              select = "
                concat (
                ' ', $chr, ' ', $sep, $chr, $sep,
                $chr, ' ', $sep, $chr, $sep,
                ' ', $chr, $sep, $chr
                )
              "
            />
            <xsl:with-param name="sep" select="$sep"/>
          </xsl:call-template>
        </xsl:with-param>
        <xsl:with-param name="chars" select="substring ($chars, 2)"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.remove_space_around -->

<d:section>
<d:para>
  Zerlegt einen Text an Trennzeichenfolgen und ruft für jeden Textabschnitt
  die Vorlage für das Element <d:parameter>elem</d:parameter>
  im Modus <d:literal>txt.apply</d:literal>
  mit den folgenden Parametern auf:
</d:para>
<d:variablelist>
  <d:varlistentry>
    <d:term><d:parameter>txt</d:parameter></d:term>
    <d:listitem>
      <d:para>
        Der Textabschnitt, eine Teilzeichenkette des zu zerlegenden Textes,
        die durch die Trennzeichenfolge begrenzt wird.
        Die Trennzeichenfolge selbst ist ausgenommen.
      </d:para>
    </d:listitem>
  </d:varlistentry>
  <d:varlistentry>
    <d:term><d:parameter>lnr</d:parameter></d:term>
    <d:listitem>
      <d:para>
        Eine laufende Nummer, beginnend mit 1.
      </d:para>
    </d:listitem>
  </d:varlistentry>
  <d:varlistentry>
    <d:term><d:parameter>par</d:parameter></d:term>
    <d:listitem>
      <d:para>
        Der Parameter <d:parameter>par</d:parameter> wird "durchgereicht".
      </d:para>
    </d:listitem>
  </d:varlistentry>
  <d:varlistentry>
    <d:term><d:parameter>last</d:parameter></d:term>
    <d:listitem>
      <d:para>
        Beim letzten Textabschnitt der Wert <d:literal>1</d:literal>,
        sonst nicht definiert.
      </d:para>
    </d:listitem>
  </d:varlistentry>
  <d:varlistentry>
    <d:term><d:parameter>prev</d:parameter></d:term>
    <d:listitem>
      <d:para>
        Der vorhergehende Listeneintrag
      </d:para>
    </d:listitem>
  </d:varlistentry>
</d:variablelist>
</d:section>
<xsl:template name="txt.split">
  <!-- Der zu zerlegende Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die Trennzeichenfolge -->
  <xsl:param name="sep" select="$txt.break"/>
  <!-- Das Element, dessen Vorlage im Modus "txt.apply" aufgerufen wird -->
  <xsl:param name="elem" select="$txt.docroot/xsl:template [@name = 'txt.enumerate']"/>
  <!-- Ein durchgereichter Parameter -->
  <xsl:param name="par"/>
  <!-- Eine laufende Nummer -->
  <xsl:param name="lnr" select="1"/>
  <!-- Der vorhergehende Wert -->
  <xsl:param name="prev" select="''"/>
  <xsl:choose>
    <xsl:when test="string-length ($txt) = 0"/>
    <xsl:when test="string-length ($sep) = 0 or not (contains ($txt, $sep))">
      <xsl:apply-templates select="$elem" mode="txt.apply">
        <xsl:with-param name="txt" select="$txt"/>
        <xsl:with-param name="lnr" select="$lnr"/>
        <xsl:with-param name="par" select="$par"/>
        <xsl:with-param name="last" select="1"/>
        <xsl:with-param name="prev" select="$prev"/>
      </xsl:apply-templates>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates select="$elem" mode="txt.apply">
        <xsl:with-param name="txt" select="substring-before ($txt, $sep)"/>
        <xsl:with-param name="lnr" select="$lnr"/>
        <xsl:with-param name="par" select="$par"/>
        <xsl:with-param name="prev" select="$prev"/>
      </xsl:apply-templates>
      <xsl:call-template name="txt.split">
        <xsl:with-param name="txt" select="substring-after ($txt, $sep)"/>
        <xsl:with-param name="sep" select="$sep"/>
        <xsl:with-param name="elem" select="$elem"/>
        <xsl:with-param name="lnr" select="$lnr + 1"/>
        <xsl:with-param name="par" select="$par"/>
        <xsl:with-param name="prev" select="substring-before ($txt, $sep)"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.split -->

<d:para>
  Teilzeichenkette bis zu dem letzten Begrenzungszeichen einschließlich.
  Wenn die Zeichenkette kein Begrenzungszeichen enthält,
  dann ist das Ergebnis leer.
</d:para>
<xsl:template name="txt.tolastchar">
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die Begrenzungszeichen -->
  <xsl:param name="delim" select="'&#10;&#9; '"/>

  <xsl:variable name="len" select="string-length ($txt)"/>
  <xsl:choose>
    <xsl:when test="$len = 0 or string-length ($delim) = 0"/>
    <xsl:when test="contains ($delim, substring ($txt, $len, 1))">
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="txt.tolastchar">
        <xsl:with-param name="txt" select="substring ($txt, 1, $len - 1)"/>
        <xsl:with-param name="delim" select="$delim"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.tolastchar -->

<d:para>
  Teilzeichenkette nach dem letzten Begrenzungszeichen.
  Wenn die Zeichenkette kein Begrenzungszeichen enthält,
  dann ist das Ergebnis die ganze Zeichenkette.
</d:para>
<xsl:template name="txt.afterlastchar">
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die Begrenzungszeichen -->
  <xsl:param name="delim" select="'&#10;&#9; '"/>

  <xsl:variable name="len" select="string-length ($txt)"/>
  <xsl:choose>
    <xsl:when test="string-length ($txt) = 0"/>
    <xsl:when test="string-length ($delim) = 0">
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:when test="contains ($txt, substring ($delim, 1, 1))">
      <xsl:call-template name="txt.afterlastchar">
        <xsl:with-param name="txt" select="substring-after ($txt, substring ($delim, 1, 1))"
        />
        <xsl:with-param name="delim" select="$delim"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="txt.afterlastchar">
        <xsl:with-param name="txt" select="$txt"/>
        <xsl:with-param name="delim" select="substring ($delim, 2)"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.afterlastchar -->

<d:para>
Die letzten Zeichen werden entfernt, sofern sie zu den Begrenzungszeichen gehören.
</d:para>
<xsl:template name="txt.righttrim">
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die Begrenzungszeichen -->
  <xsl:param name="delim" select="'&#10;&#9; '"/>
  <!--  Länge von $txt -->
  <xsl:variable name="len" select="string-length ($txt)"/>
  <xsl:choose>
    <xsl:when test="$len = 0"/>
    <xsl:when test="contains ($delim, substring ($txt, $len, 1))">
      <xsl:call-template name="txt.righttrim">
        <xsl:with-param name="txt" select="substring ($txt, 1, $len - 1)"/>
        <xsl:with-param name="delim" select="$delim"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$txt"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.righttrim -->

<d:para>
Die ersten Zeichen werden entfernt, sofern sie zu den Begrenzungszeichen gehören.
</d:para>
<xsl:template name="txt.lefttrim">
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die Begrenzungszeichen -->
  <xsl:param name="delim" select="'&#10;&#9; '"/>
  <!--  Länge von $txt -->
  <xsl:variable name="len" select="string-length ($txt)"/>
  <xsl:choose>
    <xsl:when test="$len = 0"/>
    <xsl:when test="contains ($delim, substring ($txt, $len, 1))">
      <xsl:call-template name="txt.lefttrim">
        <xsl:with-param name="txt" select="substring ($txt, 2)"/>
        <xsl:with-param name="delim" select="$delim"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$txt"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.lefttrim -->

<d:para>
  Teilzeichenkette bis zum ersten Begrenzungszeichen einschließlich.
  Wenn die Zeichenkette kein Begrenzungszeichen enthält,
  dann ist das Ergebnis die ganze Zeichenkette.
</d:para>
<xsl:template name="txt.tofirstchar">
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die Begrenzungszeichen -->
  <xsl:param name="delim" select="'&#10;&#9; '"/>
  <xsl:choose>
    <xsl:when test="string-length ($delim) = 0 or string-length ($txt) = 0">
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="d" select="substring ($delim, 1, 1)"/>
      <xsl:call-template name="txt.tofirstchar">
        <xsl:with-param name="txt">
          <xsl:choose>
            <xsl:when test="contains ($txt, $d)">
              <xsl:value-of select="concat (substring-before ($txt, $d), $d)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$txt"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="delim" select="substring ($delim, 2)"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.tofirstchar -->

<d:para>
  Teilzeichenkette bis zum ersten Begrenzungszeichen ausschließlich.
  Wenn die Zeichenkette kein Begrenzungszeichen enthält,
  dann ist das Ergebnis die ganze Zeichenkette.
</d:para>
<xsl:template name="txt.beforefirstchar">
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die Begrenzungszeichen -->
  <xsl:param name="delim" select="'&#10;&#9; '"/>
  <xsl:choose>
    <xsl:when test="string-length ($delim) = 0 or string-length ($txt) = 0">
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="d" select="substring ($delim, 1, 1)"/>
      <xsl:call-template name="txt.beforefirstchar">
        <xsl:with-param name="txt">
          <xsl:choose>
            <xsl:when test="contains ($txt, $d)">
              <xsl:value-of select="substring-before ($txt, $d)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$txt"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="delim" select="substring ($delim, 2)"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.beforefirstchar -->

<d:para>
  Teilzeichenkette der ersten Zeichen,
  die in der Liste der "erlaubten" Zeichen vorkommen.
  Das erste Zeichen, das nicht in der Liste enthalten ist,
  ist ausgenommen.
</d:para>
<xsl:template name="txt.firstcharsin">
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die erlaubten Zeichen -->
  <xsl:param name="chars" select="'&#10;&#9; '"/>
  <xsl:choose>
    <xsl:when test="string-length ($chars) = 0 or string-length ($txt) = 0"/>
    <xsl:otherwise>
      <xsl:variable name="fc" select="substring ($txt, 1, 1)"/>
      <xsl:choose>
        <xsl:when test="contains ($chars, $fc)">
          <xsl:value-of select="$fc"/>
          <xsl:call-template name="txt.firstcharsin">
            <xsl:with-param name="txt" select="substring ($txt, 2)"/>
            <xsl:with-param name="chars" select="$chars"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise/>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.firstcharsin -->

<d:para>
Die Rest-Zeichenfolge nach dem letzen Vorkommen der Such-Zeichenkette
oder die gesamte Zeichenkette, wenn die Such-Zeichenkette nicht gefunden wird.
</d:para>
<xsl:template name="txt.substring_afterlast">
  <!-- Zeichenkette, in der gesucht wird -->
  <xsl:param name="txt" select="."/>
  <!-- Zeichenkette, die gesucht wird -->
  <xsl:param name="what" select="','"/>
  <xsl:choose>
    <xsl:when test="contains ($txt, $what)">
      <xsl:call-template name="txt.substring_afterlast">
        <xsl:with-param name="txt" select="substring-after ($txt, $what)"/>
        <xsl:with-param name="what" select="$what"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$txt"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.substring_afterlast -->

<d:section>
<d:para>
Ein Text ist in "Wörter" und "Nichtwörter" zu zerlegen.
Alle Zeichen werden einzeln verarbeitet.
Die Vorlage ruft sich dazu rekursiv selbst auf.
Sie ist dabei in einem von zwei Zuständen:
</d:para>

<d:itemizedlist>
<d:listitem>
<d:para>
Im ersten Zustand (Anfangszustand) wird jedes Zeichen, das kein "Einleitungszeichen" ist,
an die bisher gelesene Komponente (Nichtwort) angehängt.
Sobald ein "Einleitungszeichen" gefunden wird, endet das aktuelle Wort.
Das Einleitungszeichen gehört zum folgenden Wort. Der Zustand wechselt.
</d:para>
</d:listitem>
<d:listitem>
<d:para>
Im zweiten Zustand wird jedes "Wortzeichen" an das gelesene Wort angehängt.
Das erste Zeichen, das kein "Wortzeichen" ist, gehört zum folgenden "Nichtwort".
Der Zustand wechselt.
</d:para>
</d:listitem>
</d:itemizedlist>
<d:para>
Das letzte Wort oder Nichtwort endet mit der Zeichenkette.
Für jedes nicht-leere Wort
wird die auf <d:parameter>wordelem</d:parameter> passende Vorlage aufgerufen,
für jedes nicht-leere Nichtwort
die auf <d:parameter>nonwordelem</d:parameter> passende Vorlage.
Die beiden Zustände sind als zwei verschiedene Vorlagen implementiert.
</d:para>
<d:para>
Die Vorlagen für <d:parameter>wordelem</d:parameter> und
<d:parameter>nonwordelem</d:parameter> werden im Modus
<d:tag class="attvalue">txt.apply</d:tag>
mit den folgenden Parametern aufgerufen:
</d:para>
<d:simplelist>
<d:member>txt</d:member>
<d:member>par</d:member>
<d:member>lnr</d:member>
<d:member>last</d:member>
</d:simplelist>
<d:para>
Der Parameter <d:parameter>last</d:parameter> ist nur beim letzten "Wort"
oder "Nichtwort" mit dem Wert 1 definiert.
</d:para>
</d:section>
<xsl:template name="txt.wordsplit">
  <!-- Der zu zerlegende Text -->
  <xsl:param name="txt" select="."/>
  <!-- Das bisher gelesene Nichtwort -->
  <xsl:param name="word" select="''"/>
  <!-- Die Einleitungszeichen -->
  <xsl:param name="inchars" select="'$'"/>
  <!-- Die Wort-Fortsetzungszeichen -->
  <xsl:param name="wordchars" select="'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-'"
  />
  <!-- Bestimmt die Vorlage für Wörter -->
  <xsl:param name="wordelem"/>
  <!-- Bestimmt die Vorlage für "Nichtwörter" -->
  <xsl:param name="nonwordelem"/>
  <!-- Wird als Parameter "par" durchgereicht -->
  <xsl:param name="par"/>
  <!-- Lfd Nummer nummeriert die "Wörter" -->
  <xsl:param name="lnr" select="1"/>

  <xsl:choose>
    <xsl:when test="string-length ($txt) = 0">
      <xsl:if test="string-length ($word) &gt; 0">
        <xsl:apply-templates select="$nonwordelem" mode="txt.apply">
          <xsl:with-param name="txt" select="$word"/>
          <xsl:with-param name="par" select="$par"/>
          <xsl:with-param name="lnr" select="$lnr"/>
          <xsl:with-param name="last" select="1"/>
        </xsl:apply-templates>
      </xsl:if>
    </xsl:when>
    <xsl:when test="string-length ($inchars) = 0">
      <xsl:apply-templates select="$nonwordelem" mode="txt.apply">
        <xsl:with-param name="txt" select="$txt"/>
        <xsl:with-param name="par" select="$par"/>
        <xsl:with-param name="lnr" select="$lnr"/>
        <xsl:with-param name="last" select="1"/>
      </xsl:apply-templates>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="fc" select="substring ($txt, 1, 1)"/>
      <xsl:choose>
        <xsl:when test="contains ($inchars, $fc)">
          <xsl:if test="string-length ($word) &gt; 0">
            <xsl:apply-templates select="$nonwordelem" mode="txt.apply">
              <xsl:with-param name="txt" select="$word"/>
              <xsl:with-param name="par" select="$par"/>
              <xsl:with-param name="lnr" select="$lnr"/>
            </xsl:apply-templates>
          </xsl:if>
          <xsl:call-template name="txt.wordsplit.wordmode">
            <xsl:with-param name="txt" select="substring ($txt, 2)"/>
            <xsl:with-param name="word" select="$fc"/>
            <xsl:with-param name="inchars" select="$inchars"/>
            <xsl:with-param name="wordchars" select="$wordchars"/>
            <xsl:with-param name="wordelem" select="$wordelem"/>
            <xsl:with-param name="nonwordelem" select="$nonwordelem"/>
            <xsl:with-param name="par" select="$par"/>
            <xsl:with-param name="lnr" select="$lnr"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="txt.wordsplit">
            <xsl:with-param name="txt" select="substring ($txt, 2)"/>
            <xsl:with-param name="word" select="concat ($word, $fc)"/>
            <xsl:with-param name="inchars" select="$inchars"/>
            <xsl:with-param name="wordchars" select="$wordchars"/>
            <xsl:with-param name="wordelem" select="$wordelem"/>
            <xsl:with-param name="nonwordelem" select="$nonwordelem"/>
            <xsl:with-param name="par" select="$par"/>
            <xsl:with-param name="lnr" select="$lnr"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.wordsplit -->

<d:para>
Der "Wortmodus" des Wortzerlegers
</d:para>
<xsl:template name="txt.wordsplit.wordmode">
  <!-- Der zu zerlegende Text -->
  <xsl:param name="txt"/>
  <!-- Das bisher gelesene Wort -->
  <xsl:param name="word"/>
  <!-- Die Einleitungszeichen -->
  <xsl:param name="inchars"/>
  <!-- Die Wort-Fortsetzungszeichen -->
  <xsl:param name="wordchars"/>
  <!-- Bestimmt die Vorlage für Wörter -->
  <xsl:param name="wordelem"/>
  <!-- Bestimmt die Vorlage für "Nichtwörter" -->
  <xsl:param name="nonwordelem"/>
  <!-- Wird als Parameter "par" durchgereicht -->
  <xsl:param name="par"/>
  <!-- Lfd Nummer nummeriert die "Wörter" -->
  <xsl:param name="lnr" select="1"/>
  <xsl:choose>
    <xsl:when test="string-length ($txt) = 0">
      <xsl:apply-templates select="$wordelem" mode="txt.apply">
        <xsl:with-param name="txt" select="$word"/>
        <xsl:with-param name="par" select="$par"/>
        <xsl:with-param name="lnr" select="$lnr"/>
        <xsl:with-param name="last" select="1"/>
      </xsl:apply-templates>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="fc" select="substring ($txt, 1, 1)"/>
      <xsl:choose>
        <xsl:when test="contains ($wordchars, $fc)">
          <xsl:call-template name="txt.wordsplit.wordmode">
            <xsl:with-param name="txt" select="substring ($txt, 2)"/>
            <xsl:with-param name="word" select="concat ($word, $fc)"/>
            <xsl:with-param name="inchars" select="$inchars"/>
            <xsl:with-param name="wordchars" select="$wordchars"/>
            <xsl:with-param name="wordelem" select="$wordelem"/>
            <xsl:with-param name="nonwordelem" select="$nonwordelem"/>
            <xsl:with-param name="par" select="$par"/>
            <xsl:with-param name="lnr" select="$lnr"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="$wordelem" mode="txt.apply">
            <xsl:with-param name="txt" select="$word"/>
            <xsl:with-param name="par" select="$par"/>
            <xsl:with-param name="lnr" select="$lnr"/>
          </xsl:apply-templates>
          <xsl:call-template name="txt.wordsplit">
            <xsl:with-param name="txt" select="$txt"/>
            <xsl:with-param name="word" select="''"/>
            <xsl:with-param name="inchars" select="$inchars"/>
            <xsl:with-param name="wordchars" select="$wordchars"/>
            <xsl:with-param name="wordelem" select="$wordelem"/>
            <xsl:with-param name="nonwordelem" select="$nonwordelem"/>
            <xsl:with-param name="par" select="$par"/>
            <xsl:with-param name="lnr" select="$lnr + 1"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.wordsplit.wordmode -->

<d:para>
Ersetzt alle Zeichen außer Buchstaben, Ziffern und dem Zeichen "/" (Sonderzeichen)
durch Leerzeichen,
ersetzt Folgen  unmittelbar aufeinander folgender Leerzeichen durch das Zeichen "_"
und das Zeichen "/" durch "."
</d:para>
<xsl:template name="txt.makedotword">
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>
  <xsl:value-of
    select = "
      translate ( normalize-space ( translate ( $txt, concat (
      '.,_;:-!§$%&amp;/\(){}[]=?*+#@|',
      &quot;'&quot;,
      '&quot;' ), '
      ' ) ), ' /', '_.' )
    "
  />
</xsl:template><!-- txt.makedotword -->

<d:para>
  Die Teilzeichenkette vor der Trennzeichenfolge
  oder die ganze Zeichenfolge, wenn sie die Trennzeichenfolge nicht enthält.
  Die beiden Vorlagen <d:tag class="attvalue">txt.firstentry</d:tag>
  und <d:tag class="attvalue">txt.remaininglist</d:tag>
  erlauben zusammen eine einfache Verarbeitung von Listen.
</d:para>
<xsl:template name="txt.firstentry">
  <!-- Der zu zerlegende Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die Trennzeichenfolge -->
  <xsl:param name="sep" select="','"/>
  <xsl:choose>
    <xsl:when test="string-length ($sep) = 0 or not (contains ($txt, $sep))">
      <xsl:value-of select="$txt"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="substring-before ($txt, $sep)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.firstentry -->

<d:para>
  Die Teilzeichenkette nach der Trennzeichenfolge
  oder die leere Zeichenfolge, wenn sie die Trennzeichenfolge nicht enthält.
  Zusammen mit der Vorlage <d:tag class="attvalue">txt.firstentry</d:tag>
  erlaubt diese Vorlage eine einfache Verarbeitung von Listen.
</d:para>
<xsl:template name="txt.remaininglist">
  <!-- Der zu zerlegende Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die Trennzeichenfolge -->
  <xsl:param name="sep" select="','"/>
  <xsl:choose>
    <xsl:when test="string-length ($sep) = 0 or not (contains ($txt, $sep))"/>
    <xsl:otherwise>
      <xsl:value-of select="substring-after ($txt, $sep)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.remaininglist -->

<d:para>
  Zerlegt einen Text in Abschnitte (Zeilen) einer maximalen Größe,
  die mit mit einem geeigneten Trennzeichen enden.
  Für jeden Textabschnitt ruft sie eine Vorlage auf.
</d:para>
<xsl:template name="txt.chunk">
  <!-- Der zu zerlegende Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die Trennzeichen -->
  <xsl:param name="delim" select="'&#10;&#9; '"/>
  <!-- Die maximale Länge -->
  <xsl:param name="maxlen" select="90"/>
  <!-- Das Element, dessen Vorlage im Modus "txt.apply" aufgerufen wird -->
  <xsl:param name="elem" select="$txt.docroot/xsl:template [@name = 'txt.indenter']"/>
  <!-- Ein durchgereichter Parameter -->
  <xsl:param name="par" select="' '"/>
  <!-- Eine laufende Nummer -->
  <xsl:param name="lnr" select="1"/>

  <xsl:choose>
    <xsl:when test="string-length ($txt) = 0"/>
    <xsl:when test="string-length ($txt) &lt;= $maxlen">
      <xsl:apply-templates select="$elem" mode="txt.apply">
        <xsl:with-param name="txt" select="$txt"/>
        <xsl:with-param name="lnr" select="$lnr"/>
        <xsl:with-param name="par" select="$par"/>
      </xsl:apply-templates>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="try">
        <xsl:call-template name="txt.tolastchar">
          <xsl:with-param name="txt" select="substring ($txt, 1, $maxlen)"/>
          <xsl:with-param name="delim" select="$delim"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:variable name="chunk">
        <xsl:choose>
          <xsl:when test="string-length ($try) &gt; 0">
            <xsl:value-of select="$try"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:call-template name="txt.tofirstchar">
              <xsl:with-param name="txt" select="$txt"/>
              <xsl:with-param name="delim" select="$delim"/>
            </xsl:call-template>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:variable>
      <xsl:apply-templates select="$elem" mode="txt.apply">
        <xsl:with-param name="txt" select="$chunk"/>
        <xsl:with-param name="lnr" select="$lnr"/>
        <xsl:with-param name="par" select="$par"/>
      </xsl:apply-templates>
      <xsl:call-template name="txt.chunk">
        <xsl:with-param name="txt" select="substring ($txt, string-length ($chunk) + 1)"/>
        <xsl:with-param name="delim" select="$delim"/>
        <xsl:with-param name="maxlen" select="$maxlen"/>
        <xsl:with-param name="elem" select="$elem"/>
        <xsl:with-param name="lnr" select="$lnr + 1"/>
        <xsl:with-param name="par" select="$par"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template><!-- txt.chunk -->

<!-- Dokumentation zum Modus "txt.apply" -->
<d:section xmlns="http://herbaer.de/xmlns/20051201/doc" role="mode.txt.apply">
<para>
Der Modus <tag class="attvalue">txt.apply</tag> bezeichnet Vorlagen,
die von "Iteratoren" benutzt werden. Ihnen werden die folgenden Parameter übergeben:
</para>
<variablelist>
  <varlistentry>
    <term><parameter>txt</parameter></term>
    <listitem>
      <para>Das aktuelle "Iterator-Wort"</para>
    </listitem>
  </varlistentry>
  <varlistentry>
    <term><parameter>lnr</parameter></term>
    <listitem>
      <para>Die lfd. Nummer der Iterator-Position, beginnend mit 1</para>
    </listitem>
  </varlistentry>
  <varlistentry>
    <term><parameter>par</parameter></term>
    <listitem>
      <para>
        Ein Parameter, der dem Iterator übergeben ist und den dieser weitergibt.
      </para>
    </listitem>
  </varlistentry>
  <varlistentry>
    <term><parameter>last</parameter></term>
    <listitem>
      <para>
        Wenn dieser Parameter definiert ist und nicht leer und nicht Null ist,
        dann ist der Aufruf der letzte des Iterators.
      </para>
    </listitem>
  </varlistentry>
</variablelist>
</d:section>

<d:para>
  Selbstpassende Vorlage, rückt Folgezeilen ein
</d:para>
<xsl:template
  name = "txt.indenter"
  mode = "txt.apply"
  match = "xsl:template [@name = 'txt.indenter' and @mode = 'txt.apply']"
>
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die lfd. Nummer -->
  <xsl:param name="lnr" select="1"/>
  <!-- Die Einrückung -->
  <xsl:param name="par" select="' '"/>
   <xsl:if test="$lnr &gt; 1">
    <xsl:value-of select="concat ($txt.break, $par)"/>
  </xsl:if>
  <xsl:value-of select="$txt"/>
</xsl:template><!-- txt.indenter -->

<d:para>
  Selbstpassende Vorlage, zählt einen Wert auf: "[lnr]. [txt]\n"
</d:para>
<xsl:template
  name = "txt.enumerate"
  mode = "txt.apply"
  match = "xsl:template [@name = 'txt.enumerate' and @mode = 'txt.apply']"
>
  <!-- Der Text -->
  <xsl:param name="txt" select="."/>
  <!-- Die lfd. Nummer -->
  <xsl:param name="lnr" select="1"/>
  <xsl:value-of select="concat ($lnr, '. ', $txt, $txt.break)"/>
</xsl:template><!-- txt.enumerate -->

<d:para>
  Der Dateiname aus einem Dateipfad:
  die Teilzeichenkette nach dem letzten Schrägstrich
  oder umgekehrten Schrägstrich
</d:para>
<xsl:template name="txt.filename">
  <!-- Der Dateipfad -->
  <xsl:param name="txt" select="."/>
  <xsl:call-template name="txt.afterlastchar">
    <xsl:with-param name="txt" select="$txt"/>
    <xsl:with-param name="delim" select="'/\'"/>
  </xsl:call-template>
</xsl:template><!-- txt.filename -->

<d:para>
  Der Basis-Dateiname aus einem Dateipfad:
  die Buchstaben, Ziffern und Unterstriche
  nach dem letzten Schrägstrich oder umgekehrten Schrägstrich
</d:para>
<xsl:template name="txt.basefilename">
  <!-- Der Dateipfad -->
  <xsl:param name="txt" select="."/>
  <xsl:call-template name="txt.firstcharsin">
    <xsl:with-param name="txt">
      <xsl:call-template name="txt.afterlastchar">
        <xsl:with-param name="txt" select="$txt"/>
        <xsl:with-param name="delim" select="'/\'"/>
      </xsl:call-template>
    </xsl:with-param>
    <xsl:with-param name="chars" select="$txt.namechars"/>
  </xsl:call-template>
</xsl:template><!-- txt.basefilename -->

<d:para>
Die Einträge der ersten Liste, die auch in der zweiten Liste
vorkommen, in der Reihenfolge der ersten Liste.
</d:para>
<xsl:template name="txt.listintersect">
  <!--
    Die erste Liste:
    Die leere Zeichenkette steht für die leere Liste.
  -->
  <xsl:param name="txt"/>
  <!-- Die zweite Liste (Selektor-Liste) -->
  <xsl:param name="select"/>
  <!--
    Die Trennzeichenfolge trennt die Einträge der Liste.
    Eine Zeichenkette, die die Trennzeichenfolge n mal enthält,
    steht für eine Liste mit n + 1 Einträgen.
    Eine Zeichenkette, die nur einmal die Trennzeichenfolge enthält,
    steht für eine Liste mit zwei leeren Einträgen.
    Es ist keine Möglichkeit vorgesehen, eine Liste mit genau einem leeren Eintrag
    darzustellen.
  -->
  <xsl:param name="sep" select="' '"/>
  <xsl:choose>
    <xsl:when test="string-length ($txt) = 0 or string-length ($select) = 0"/>
    <xsl:when test="string-length ($sep) = 0">
      <xsl:if test="$txt = $select">
        <xsl:value-of select="$txt"/>
      </xsl:if>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="rx">
        <xsl:call-template name="txt.listintersect._impl_">
          <xsl:with-param name="txt" select="$txt"/>
          <xsl:with-param name="select" select="concat ($sep, $select, $sep)"/>
          <xsl:with-param name="sep" select="$sep"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:if test="string-length ($rx) &gt; 0">
        <xsl:value-of select="substring ($rx, string-length ($sep) + 1)"/>
      </xsl:if>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<d:para>
"Private" Vorlage zur Implementation der Vorlage txt.listitersect
</d:para>
<xsl:template name="txt.listintersect._impl_">
  <xsl:param name="txt" select="$txt"/>
  <xsl:param name="select" select="concat ($sep, $select, $sep)"/>
  <xsl:param name="sep" select="$sep"/>
  <xsl:choose>
    <xsl:when test="not (contains ($txt, $sep))">
      <xsl:if test="contains ($select, concat ($sep, $txt, $sep))">
        <xsl:value-of select="concat ($sep, $txt)"/>
      </xsl:if>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="wrd" select="substring-before ($txt, $sep)"/>
      <xsl:if test="contains ($select, concat ($sep, $wrd, $sep))">
        <xsl:value-of select="concat ($sep, $wrd)"/>
      </xsl:if>
      <xsl:call-template name="txt.listintersect._impl_">
        <xsl:with-param name="txt" select="substring-after ($txt, $sep)"/>
        <xsl:with-param name="select" select="$select"/>
        <xsl:with-param name="sep" select="$sep"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>
