xsl:message effektiv einsetzen

(Auszug aus "XSLT Kochbuch" von Sal Mangano)

Problem

Sie möchten Ihr Stylesheet untersuchen, um festzustellen, warum es nicht das macht, was Sie erwarten.

Achtung!
Ein häufiger Fehler ist der, dass Sie ein Stylesheet auf einem Dokument ausführen und keinerlei Ausgabe sehen oder nur eine Textausgabe ohne Elemente darin. Meiner Erfahrung nach deutet das fast immer auf ein Namensraumproblem hin. Man vergisst sehr leicht, Namensraumpräfixe in match-Attribute von xsl:template hinzuzufügen, oder es gibt keine Übereinstimmung zwischen dem Namensraum-URI im Dokument und jenem im Stylesheet. Denken Sie daran, dass es auf den Namensraum-URI und nicht auf das Präfix ankommt. Eine Abweichung von nur einem Buchstaben führt zu einem Problem. Bei langen URIs neige ich dazu, die Namensraum-Deklaration aus dem Dokument ins Stylesheet zu kopieren, damit beide wirklich übereinstimmen.

Lösung

XSLT 1.0

Das einfachste Werkzeug in Ihrem Debugging-Arsenal ist xsl:message, mit dem häufig geprüft wird, ob ein bestimmtes Template ausgeführt wird:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- ... -->
  <xsl:template match="someElement[someChild = 'someValue']">
    <xsl:message>Matched someElement[someChild = 'someValue']</xsl:message>
    <!-- ... -->
  </xsl:template>
</xsl:stylesheet>

Noch hilfreicher wird diese Technik, wenn Sie dabei relevante Daten auch anzeigen. Vergewissern Sie sich, dass Sie die Ausgabe mit einem bekannten beschreibenden Text versehen, damit Sie die Ausgabe von anderen Vorkommen von xsl:message unterscheiden und feststellen können, wann eine Meldung (mit einem leeren Ergebnis) ausgeführt wurde:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="someElement[someChild = 'someValue']">
    <xsl:param name="myParam"/>
    <!-- Das ist keine wirksame Debugging-Technik. Wenn Sie einen Test ausführen und nichts sehen, kann das daran liegen, dass das Template keine Übereinstimmung ergab, oder daran, dass es eine Übereinstimmung mit einem leeren $myParam gab. -->
    <xsl:message><xsl:value-of select="$myParam"/></xsl:message>
  </xsl:template>
  <xsl:template match="someElement[someChild = 'someOtherValue']">
    <xsl:param name="myParam"/>
    <!-- Das hier ist besser -->
    <xsl:message>Matched someElement[someChild = 'someOtherValue']</xsl:message>
    <xsl:message>$myParam=[<xsl:value-of select="$myParam"/>]</xsl:message>
  </xsl:template>
</xsl:stylesheet>

Verwenden Sie einen Debugging-Parameter, um eine xsl:message-basierte Ausstattung in Ihrem Stylesheet zu erhalten. Platzieren Sie den Parameter in Ihrem eigenen Namensraum, falls Sie den Code an andere weitergeben möchten, um nicht mit deren Debug-Ausstattung in Konflikt zu kommen:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dbg="http:www.ora.com/XSLTCookbook/ns/debug">
  <xsl:param name="dbg:debugOn" select="false( )"/>
  <xsl:template match="someElement[someChild = 'someValue']">
    <xsl:param name="myParam"/>
    <xsl:if test="$dbg:debugOn">
      <xsl:message>Matched someElement[someChild = 'someValue']</xsl:message>
      <xsl:message>$myParam=[<xsl:value-of select="$myParam"/>]</xsl:message>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

XSLT 2.0

Es gibt zwei praktische Verbesserungen in 2.0. Zunächst verfügt xsl:message nun über ein Auswahlattribut, das Sie an Stelle der Syntax zur Konstruktion einer Sequenz benutzen können. Für kleine Meldungen ist das sehr praktisch. Und zweitens kann das terminate-Attribut nun ein Attributwert-Template sein. Dadurch werden globale Änderungen am Terminierungsverhalten sowie die Erzeugung von Zusicherungsnachrichten bei Stilen wesentlich einfacher.

<!-- Ausgeben des Werts von $foo und terminieren, wenn er negativ ist -->
<xsl:message select=" 'foo=', $foo " terminate="{ if ($foo lt 0) then 'yes' else 'no'}" />

Je nachdem, welchen XSLT-Prozessor Sie verwenden, können Sie eventuell vom use-when-Attribut profitieren, der bei allen XSLT 2.0-Anweisungen Standard ist. Der Trick besteht darin, eine eigene Debug-Systemeigenschaft abzutesten. Wenn bei der Saxon-Implementierung von system-property( ) das Argument ein Name außerhalb eines Namensraums ist (d.h., wenn der Name kein Präfix hat), dann wird er als Referenz auf eine Java-Systemeigenschaft interpretiert, und der Wert dieser Eigenschaft wird zurückgegeben, sofern er existiert. Damit erhält man Meldungen, die unter bestimmten Bedingungen kompiliert werden.

<xsl:message use-when="system-property('debug_on') = 'yes' ">
  <xsl:text>Debug mode is on!</xsl:text>
</xsl:message>

Das debug-on setzen Sie dann, wenn Sie Saxon mit Java starten:

java -Ddebug_on=yes -jar c:\saxon\saxon8.jar test.xml test.xslt

Diskussion

XSLT 1.0

Bevor es Debugger gab, wurde mit Print-Anweisungen gearbeitet. Zwar gibt es mittlerweile einige interaktive XSLT-Debugger, aber soweit ich weiß, ist keiner davon gratis verfügbar.

Zusätzlich zur obigen Verwendung von xsl:message könnten Sie auch den Einsatz von Zusicherungen (engl. assertions) erwägen, um damit Vor- und Nachbedingungen bzw. Invarianten zu testen, die an einer bestimmten Stelle des Stylesheets wahr sein müssen:

<xsl:if test="debugOn">
  <xsl:if test="Test einer Invarianten einfügen">
    <xsl:message terminate="yes">Meldung über eine Verletzung oder einen Fehler.</xsl:message>
  </xsl:if>
</xsl:if>

In solchen Zusicherungstests wird oftmals terminate="yes" verwendet, weil es sich hierbei per definitionem um irreparable Fehler handelt.

Eine wichtige Überlegung beim Debuggen mit xsl:message gilt dem Zielort der Ausgabe, die je nach Umgebung des ausgeführten XSLT-Skripts variieren kann. Falls die Transformation z.B. in einem Browser ausgeführt wird, werden Sie die Ausgabe gar nicht zu Gesicht bekommen. Es empfielt sich, Stylesheets zuerst mit einem Kommandozeilenprozessor zu testen, bevor Sie den nächsten Schritt in die eigentliche Zielumgebung machen.

Falls die Ausgabe aus XML oder HTML besteht, besteht eine Alternative zu xsl:message darin, Debugging-Kommentare mit xsl:comment ins resultierende Dokument einzufügen. Insbesondere können Sie alle Templates in Ihrem Stylesheet mit einem xsl:comment am Anfang beginnen, um einen roten Faden von der Ausgabe bis zurück zu den Templates zu haben, von denen sie erzeugt wurde:

<xsl:template match="*">
  <xsl:comment>Generiert durch Übereinstimmung mit Platzhalter</xsl:comment>
  ...
</xsl:template>
...
<xsl:template match="*" mode="foo">
  <xsl:comment>Generiert durch Übereinstimmung mit Platzhalter und mode=foo</xsl:comment>
  ...
</xsl:template>

  

<< 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