3.2  Eindeutigkeit der Regelbasis

Die Regelbasis von XSLT kann wahrscheinlich unendlich viele Regeln aufnehmen, wenn man unsere Limitierung bzgl. der Hardware nicht beachtet. Für die Vollständigkeit, Eindeutigkeit und Konsistenz der Regelbasis ist der Programmierer aber selbst verantwortlich.
Um die Eindeutigkeit der Regeln zu gewährleisten, gibt es verschiedene Mechanismen.23e23e23e

3.2.1  Reihenfolge der Match-Regeln

Im Normalfall sollte auf einen bestimmten Knoten in einem bestimmten Szenario genau eine Regel matchen. Falls es einen Konflikt gibt, wird zumindest bei Saxon diejenige Regel herangezogen, die im Stylesheet zuletzt deklariert wurde.
Diesen Umstand zu kennen, ist genau dann wichtig, wenn man einen bestehenden Stylesheet-Code übernehmen muss. Getreu dem Motto "Never change a running system" sollte man die Sache diesbzgl. sehr behutsam aufräumen.

3.2.2  Präzedenz der Auswertung

Match-Regeln werden gemäß ihrer Spezifität sortiert und diejenige, die auf einem Knoten in einem bestimmten Szenario am besten zutrifft, wird zur Auswertung herangezogen. Grds. werden die Regeln anhand folgender Kriterien sortiert:
1.

Importierte Template Regeln haben immer eine niedrigere Priorität als die Regeln des importierenden Stylesheets.

| | Rejected by , .
2.

Templates mit einem höheren Priority Attribut haben Vorrang.

3.

Templates ohne Priorität bekommen automatisch eine Default-Priorität. Die höchste Default-Priorität ist 0.5 .

4.

Diese Default Priorität errechnet sich anhand der Bedingungen oder Wildcards, die an einen Match-Regel geknüpft sind:

| | Rejected by , .
  • Wenn mehrere Templates matchen, dann wird das am meisten spezifische zur Auswertung herangezogen.
  • Das am meisten spezifische Template wird anhand der Prioritäten berechnet.
  • Einfache Elementnamen (z.B. "para") haben Prio 0 .
  • Wildcards (z.B. *, @* ) haben Priorität -0.25
  • Knoten-Tests für andere Knoten (e.g. comment(), node() , etc. ) haben Priorität -0.5
  • In allen anderen Fällen ist die Prio 0.5 .
4.

Beispiele:

  • para -> 0
  • h:* -> -0.25
  • * -> -0.25
  • node() -> -0.25
  • contents/para -> 0.5
  • contents/* -> 0.5
5.

Mit einer Kommandozeilen-Option kann bei Saxon festgelegt werden, dass die Transformation abbricht, sobald es einen Konflikt bei der Regelauswertung gibt.

3.2.3  Import Präzendenz und Default-Regel

Wie in der obigen Sektion unter Punkt 1. angegeben, haben alle Regeln in einem importierten Stylesheet eine geringere Priorität als im importierenden Stylesheet. Diesen Umstand kann man sich zunutze machen, um eine Default-Regel einzubinden, bspw:
<xsl:template match="*" mode="#all"/>
Da diese Regel sich in einem importierten Stylesheet befindet, hat sie geringere Priorität als alle anderen Regeln und greift nur dann, wenn für einen betretenen Knoten keine anderen Match-Regeln definiert sind.
Das ist z.B. praktisch, um nicht "gehandelte" Element zu identifizieren - dazu wäre die obige Regel nicht leer, sondern würde bspw. einen gelb markierten Warntext direkt in das Ausgabeformat schreiben.
Eine leere Default-Regel ist dagegen gut, wenn bspw. in einer XML-2-XML Migration automatisch Knoten im XML Baum abgetrennt werden sollen...

3.2.4  Prioritäten

Alle
Match-Regeln werden mit einer Priorität ausgestattet. Der Stylesheet-Entwickler hat die Möglichkeit diese Priorität zu überschreiben. Dazu wird das Attribut
@priority
an der Match-Regel verwendet. Ein Use-Case für die Prioritäten wäre bspw. folgendes Filter-Szenario
Beispiel Seminarverwaltung
  • Die Eingabeinstanz soll in einer Vorprozessierung gefiltert werden.
  • Dabei sollen Seminar-Elemente markiert werden, die nicht besonderen Bedingungen entsprechen:
    • Das Seminar-Element hat ein Feld "Ende-Datum" das abgelaufen ist.
    • Am Seminar-Element sind mehrere Dozenten angestellt, obwohl das Seminar-Element vom Typ "Single" ist.
    • Einem Seminar-Element ist kein Dozent zugeordnet.
  • Sicherlich kann es Seminar-Elemente geben, die alle drei Bedingungen erfüllen. Um das Error-Log aber nicht zu überfüllen, sollen die Filter nach ihren Prioritäten ausgeführt werden.
In XSLT Templates überführt, könnte diese Anforderung so umgsetzt werden:
<xsl:template match="Seminar[Ende-Datum/xs:date(.) le current-date()]" 
              priority="30" mode="filter-seminare"> 
  <xsl:element name="Filtered-Seminar" namespace="{namespace-uri()}"> 
    <xsl:attribute name="reason">termed-seminar</xsl:attribute> 
    <xsl:apply-templates select="node()|@*" mode="filter-seminare"/> 
  </xsl:element> 
</xsl:template> 

<xsl:template match="Seminar[Type eq 'SINGLE' and count(dozenten/dozent) gt 1]"
              priority="20" mode="filter-seminare"> 
  <xsl:element name="filtered-Seminar" namespace="{namespace-uri()}"> 
    <xsl:attribute name="reason">dozenten-count</xsl:attribute> 
    <xsl:apply-templates select="node()|@*" mode="filter-seminare"/> 
  </xsl:element> 
</xsl:template> 

<xsl:template match="Seminar[not(dozenten/dozent)]" mode="filter-seminare"> 
  <xsl:element name="filtered-Seminar" namespace="{namespace-uri()}"> 
    <xsl:attribute name="reason">dozenten-missing</xsl:attribute> 
    <xsl:apply-templates select="node()|@*" mode="filter-seminare"/> 
  </xsl:element> 
</xsl:template>
Neben des Einsatzes des @priority Attributs und des nachfolgend beschriebenen @mode Attributs ist sicherlich auch noch interessant, dass die gefilterten Seminar-Elemente hier nicht gelöscht werden, sondern umbenannt werden. Auf diese Weise können sie in einem nachfolgenden Transformationsschritt (Stichwort: Vortransformationen) weiterbehandelt werden, stören aber in der regulären Verarbeitung nicht.

3.2.5  Modus Attribute

An allen Templates hat man die Möglichkeit einen selbst deklarierten Modus anzugeben. Wenn dann der XSLT Prozessor in eine bestimmte Richtung gepusht, vgl. Push vs. Pull Stylesheets , wird, werden nur diejenigen Regeln zur Auswertung herangezogen, die im selben Modus sind, wie der apply-templates Call selbst.
Beispielsweise möchte man die Titel im Kapitel anders behandeln als die Kapitel im Inhaltsverzeichnis, denn im TOC sollen z.B. keine Fussnoten-Marker angezeigt werden.
In Templates formuliert würde so eine Anweisung folgendermassen aussehen:
<xsl:template match="title" mode="toc">
  <div class="toc-entry">
    <xsl:apply-templates select="*[not(self::footnote)]"/>
  </div>
</xsl:template>

<xsl:template match="title">
  <h1>
    <xsl:apply-templates/>
  </h1>
</xsl:template>
Die Generierung des TOC könnte dann so ablaufen:
<xsl:for-each select="chapter">
  <xsl:apply-templates select="title" mode="toc">
</xsl:for-each>
Bzgl. der Eindeutigkeit der Regelbasis kann man so anhand des Mode-Attributes Ausführungsgruppen bilden.
WARNUNG!
Wie auch bei Angabe der Priorities kann man auf diese Weise Regeln setzen, die nie ausgeführt werden, weil sie vllt. im Zuge einer Refactoring-Massnahme abgeklemmt und dann vergessen werden.
Auch das mode -Attribut ist also mit Vorsicht zu geniessen und sparsam einzusetzen.
Previous Page Next Page
Version: 93
Jan 25 2021