Tunnelparameter

(Auszug aus "XSLT 2.0 & XPath 2.0" von Frank Bongers, Kapitel 3.)

Solange ein Parameter, der bei einem Aufruf weitergegeben werden soll, auch unmittelbar im aufgerufenen Template verwendet werden soll, ist die Handhabung verhältnismäßig einfach. Komplexer – und in XSLT 1.0 unlösbar – wird die Problemstellung, wenn eine Template-Regel oder ein benanntes Template übersprungen werden soll, weil der Parameter erst in einem nachfolgenden Template ausgelesen wird, aber gleichzeitig eine explizite Weitergabe nicht möglich oder nicht erwünscht ist.

XSLT 2.0 rückt diesem Problem mit den sogenannten Tunnelparametern zu Leibe. Ein in dieser Form übergebener Parameter wird gewissermaßen in den Verarbeitungsprozess geworfen und kann von einem nachfolgenden Template aufgefischt werden. Das Medium, in dem sich die Parameter unterdessen weiterbewegen, wird, durchaus anschaulich, als Tunnelstrom bezeichnet.

Erzeugt wird ein Tunnelparameter, wie jeder andere Parameter auch, mittels der Instruktion xsl:with-param. Nur ist zusätzlich zur normalen Syntax die Hinzufügung eines weiteren Attributs erforderlich, des tunnel-Attributs:

<xsl:with-param name="p1" tunnel="yes">
  Nachricht von Template 1
</xsl:with-param>

Der geheimnisvolle Tunnelparameter

Hier soll ein kleines, etwas verspieltes Beispiel des Prinzips vorgeführt werden. Es lässt sich mit jedem beliebigen Quelldokument verarbeiten, da auf dessen Informationen nicht zugegriffen wird.

Es existiert eine Template-Regel, die in Zusammenhang mit dem Dokumentkno­ten aufgerufen wird. Diese Regel ruft ein benanntes Template auf und entlässt gleichzeitig einen Parameter $param_1 mit tunnel="yes" in den Tunnelstrom. Mit diesem Parameter geschehen in Folge merkwürdige Dinge. Plötzlich ver­ändert sich sein ausgegebener Wert.

Abbildung: Der geheimnisvolle Tunnelparameter (tunnel.html).

Von hier ab wird es interessant. Eigentlich können Parameterwerte doch nicht überschrieben werden? Oder etwa doch?

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/1999/xhtml">
  <xsl:output method="xhtml" encoding="ISO-8859-1" indent="yes" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>
  <xsl:template match="/">
    <html>
      <head><title>Tunnelbotschaften</title></head>
      <body>
        <h1>Ein Template schickt eine Nachricht:</h1>
        <p>Die Nachricht lautet: Nachricht vom Haupttemplate.</p>
        <xsl:call-template name="template1">
          <xsl:with-param name="param_1" tunnel="yes">Nachricht vom Haupttemplate</xsl:with-param>
        </xsl:call-template>
      </body>
    </html>
  </xsl:template>
  <xsl:template name="template1">
    <xsl:param name="param_1">Da gehe ich nicht darauf ein!</xsl:param>
    <p><b>Wert von $param_1 in Template 1: </b><xsl:value-of select="$param_1"/></p>
    <xsl:call-template name="template2"/>
  </xsl:template>
  <xsl:template name="template2">
    <p>Hier Template 2: Hier ist weiter nicht los. Übergebe an Template 3!</p>
    <xsl:call-template name="template3"/>
  </xsl:template>
  <xsl:template name="template3">
    <xsl:param name=" param_1" tunnel="yes">Hier steht ein Defaultwert</xsl:param>
    <p><b>Wert von $param_1 in Template3: </b><xsl:value-of select="$param_1"/></p>
    <xsl:if test="not(contains($param_1, 'Stop'))">
      <xsl:call-template name="template4"/>
    </xsl:if>
  </xsl:template>
  <xsl:template name="template4">
    <p>Hier Template 4: Hier ist auch nichts los. Übergebe an Template 5! Anbei eine neue Nachricht an alle, die es angeht.</p>
    <xsl:call-template name="template5">
      <xsl:with-param name="param_1" tunnel="yes">Neue Nachricht von Template 4.</xsl:with-param>
    </xsl:call-template>
  </xsl:template>
  <xsl:template name="template5">
    <xsl:param name=" param_1" tunnel="yes">Hier steht ein Defaultwert</xsl:param>
    <p><b>Wert von $param_1 in Template 5: </b><xsl:value-of select="$param_1"/></p>
    <p>Gebe zurück an Template 3! Und Stop.</p>
    <xsl:call-template name="template3"/>
  </xsl:template>
</xsl:stylesheet>

Code-Beispiel: kap03/3.01.6/tunnel.xsl.

Im Stylesheet existiert eine Kette von benannten Templates, die sich gegensei­tig aufrufen. Das erste von ihnen, Template 1, besitzt einen Parameter mit dem geforderten Namen. Da dieser aber nicht das tunnel-Attribut mit Wert "yes" besitzt, hat er quasi keine »Angelerlaubnis«, sich den Parameterwert aus dem Tunnelstrom zu holen. Er nimmt mit seinem Defaultwert vorlieb und ruft Template 2 auf. Template 2 besitzt überhaupt keinen Parameter, gibt nur eine Meldung aus und ruft Template 3.

Template 3 besitzt ebenfalls einen Parameter param_1, der aber diesmal über ein Attribut tunnel="yes" verfügt. Nachdem ein entsprechender Parameter im Tunnelstrom vorliegt, wird er ausgelesen und ausgegeben. Template 3 ruft nun Template 4 auf, das sich meldet und Template 5 aufruft und hierbei aber erneut einen Parameter param_1 mit Tunnelattribut übergibt, und zwar mit einem neuen Wert.

Template 5, das auch über den erforderlichen Parameter verfügt, liest den neuen Wert aus und ruft wieder Template 3 auf. Auch Template 3 liest den Parameter erneut aus und sieht diesmal den neuen Wert. Hat also tatsächlich eine Wertzuweisung stattgefunden? Es sieht zumindest so aus. In Wirklichkeit ist es aber nicht der Fall, denn dies würde gegen ein Grundprinzip von XSLT verstoßen.

Was passiert tatsächlich? Eine echte Neuzuweisung des Werts liegt hier nicht vor, sondern nur eine eigenartige Version von Binding Shadow. Es können im Prinzip mehrere gleichnamige Parameter mit gleichem Bezeichner im Tunnel­strom koexistieren. Hierbei verdeckt ein im Laufe eines Verarbeitungszweigs neu hinzugekommener Parameter seinen gleichnamigen Vorgänger.

Dieser wird nicht gelöscht oder überschrieben, sondern kann lediglich nicht ausgelesen werden. Sobald der neue Parameter aus dem Scope geht, ist er wie­der sichtbar, und zwar mit dem ursprünglichen Wert.

Folgende Eigenschaften des Tunnelparameters kommen hier zum Tragen:

  • Der Tunnelparameter ist sichtbar in allen Template-Regeln, die derjenigen unter­geordnet sind, aus der heraus er übergeben wurde.
  • Der Tunnelparameter kann durch einen gleichnamigen Tunnelparameter ver­deckt werden.
  • Der Tunnelparameter kann nur durch ein xsl:param mit tunnel="yes" ausge­lesen werden, auch wenn der Bezeichner übereinstimmt.
  • Ein Tunnelparameter wird durch einen Lesevorgang nicht gelöscht, sondern steht untergeordneten Templates nach wie vor zur Verfügung.

Hinweis:
In diesem Beispiel wurde als Demonstration der Verarbeitungs­zweig in sich selbst zurückgelenkt, was riskant ist, da ein solcher Einsatz von benannten Templates zu einer Endlosschleife führt. Dem wurde – etwas une­legant – mit einem Codewort im neu übergebenen Wert vorgebeugt, das den erneuten Aufruf des Folge-Templates unterbindet.

Ob und wie nützlich diese scheinbare Neubelegung von Parameterwerten sich in der Praxis erweisen wird, muss sich noch herausstellen. Neben dieser, sich etwas nebulös äußernden Variante von Template-Durchtunnelung existiert aller­dings noch eine zweite, weniger spektakulär und unterschwellig, aber dafür umso praktischer.

   

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

Copyright © Galileo Press, Bonn 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT 2.0 & XPath 2.0 ― Das umfassende Handbuch" 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.


Galileo Press, Rheinwerkallee 4, 53227 Bonn