Einen String in Token aufteilen

(Auszug aus "XSLT Kochbuch" von Sal Mangano)

Problem

Sie wollen einen String anhand des Vorkommens eines oder mehrerer Trennzeichen in Token aufteilen.

Lösung

XSLT 1.0

Jeni Tennison implementierte diese Lösung (die Kommentare sind allerdings von mir). Der Tokenizer liefert jedes Token als einen Knoten zurück, der aus einem token-Elementtext besteht. Wenn der Trennzeichenstring leer ist, wird standardmäßig eine Token-Aufteilung auf Zeichenebene durchgeführt:

<xsl:template name="tokenize">
  <xsl:param name="string" select="''"/>
  <xsl:param name="delimiters" select="' &#x9;&#xA;'"/>
  <xsl:choose>
    <!-- Nichts zu tun, wenn der String leer ist -->
    <xsl:when test="not($string)"/>
    <!-- Fehlende Trennzeichen signalisieren eine Token-Aufteilung auf Zeichenebene. -->
    <xsl:when test="not($delimiters)">
      <xsl:call-template name="_tokenize-characters">
        <xsl:with-param name="string" select="$string"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="_tokenize-delimiters">
        <xsl:with-param name="string" select="$string"/>
        <xsl:with-param name="delimiters" select="$delimiters"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
<xsl:template name="_tokenize-characters">
  <xsl:param name="string"/>
  <xsl:if test="$string">
    <token>
      <xsl:value-of select="substring($string, 1, 1)"/>
    </token>
    <xsl:call-template name="_tokenize-characters">
      <xsl:with-param name="string" select="substring($string, 2)"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>
<xsl:template name="_tokenize-delimiters">
  <xsl:param name="string"/>
  <xsl:param name="delimiters"/>
  <xsl:param name="last-delimit"/>
  <!-- Extrahieren eines Trennzeichens -->
  <xsl:variable name="delimiter" select="substring($delimiters, 1, 1)"/>
  <xsl:choose>
    <!-- Wenn das Trennzeichen leer ist, haben wir ein Token -->
    <xsl:when test="not($delimiter)">
      <token>
        <xsl:value-of select="$string"/>
      </token>
    </xsl:when>
    <!-- Wenn der String wenigstens ein Trennzeichen enthält, müssen wir ihn aufteilen -->
    <xsl:when test="contains($string, $delimiter)">
      <!-- Wenn er mit dem Trennzeichen beginnt, müssen wir den vorhergehenden Teil nicht behandeln -->
      <xsl:if test="not(starts-with($string, $delimiter))">
        <!-- Behandelt den Teil, der vor dem aktuellen Trennzeichen kommt, mit dem nächsten Trennzeichen. Gibt es kein nächstes Trennzeichen, dann entdeckt der erste Test in diesem Template das Token -->
        <xsl:call-template name="_tokenize-delimiters">
          <xsl:with-param name="string" select="substring-before($string, $delimiter)"/>
          <xsl:with-param name="delimiters" select="substring($delimiters, 2)"/>
        </xsl:call-template>
      </xsl:if>
      <!-- Behandelt den Teil, der nach dem Trennzeichen kommt, mit Hilfe des aktuellen Trennzeichens -->
      <xsl:call-template name="_tokenize-delimiters">
        <xsl:with-param name="string" select="substring-after($string, $delimiter)"/>
        <xsl:with-param name="delimiters" select="$delimiters"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <!-- Keine Vorkommen des aktuellen Trennzeichens, deshalb weitergehen zum nächsten -->
      <xsl:call-template name="_tokenize-delimiters">
        <xsl:with-param name="string" select="$string"/>
        <xsl:with-param name="delimiters" select="substring($delimiters, 2)"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

XSLT 2.0

Benutzen Sie die XPath-2.0-Funktion tokenize( ), die im Rezept Reguläre Ausdrücke nutzen behandelt wird.

Diskussion

Die Aufteilung in Token ist eine gebräuchliche Stringverarbeitungsaufgabe. In Sprachen mit leistungsfähigen Regex-Mechanismen ist die Token-Aufteilung trivial. In diesem Bereich wird XSLT durch Sprachen wie Perl, Python, JavaScript und Tcl übertroffen. Dieses Rezept zeigt jedoch, dass XSLT ebenfalls mit einer Token-Aufteilung klarkommt, falls Sie sich innerhalb der Grenzen reinen XSLTs bewegen müssen. Falls Sie bereit sind, Erweiterungen zu verwenden, können Sie für solche einfachen Stringmanipulationen wie die Token-Aufteilung auf eine andere Sprache zurückgreifen.

Falls Sie den XSLT-Ansatz verwenden und Ihr Prozessor nicht für Endrekursion optimiert ist, wollen Sie möglicherweise einen Teile-und-herrsche-Algorithmus für die Zeichen-Token-Aufteilung benutzen:

<xsl:template name="_tokenize-characters">
  <xsl:param name="string"/>
  <xsl:param name="len" select="string-length($string)"/>
  <xsl:choose>
    <xsl:when test="$len = 1">
      <token>
        <xsl:value-of select="$string"/>
      </token>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="_tokenize-characters">
        <xsl:with-param name="string" select="substring($string, 1, floor($len div 2))"/>
        <xsl:with-param name="len" select="floor($len div 2)"/>
      </xsl:call-template>
      <xsl:call-template name="_tokenize-characters">
        <xsl:with-param name="string" select="substring($string, floor($len div 2) + 1)"/>
        <xsl:with-param name="len" select="ceiling($len div 2)"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Siehe auch

Unter Code-Generierung wird gezeigt, wie Sie auf die Regex-Funktionalität von JavaScript zugreifen, falls Ihr XSLT-Prozessor JavaScript-basierte Erweiterungen erlaubt. Java besitzt außerdem einen integrierten Tokenizer (java.util.StringTokenizer).

  

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema XSLT bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © 2006 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT Kochbuch" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O'Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de