XSL - Übersicht / xsl:apply-templates, xsl:next-match

xsl:apply-templates, xsl:next-match

xsl:apply-templates, xsl:next-match

Ein alternativer Ansatz zur Arbeit mit xsl:for-each ist xsl:apply-templates. Hier wird eine stufenweise Auslagerung in separate Templates gepflegt, die sich besonders für textintensive Dokumente mit gemischter Strukturierung der Childelemente (mixed content) eignet.

xsl:apply-templates, xsl:next-match

Im Template match="/" wird der generelle Aufbau des HTML-Zieldokuments definiert; an geeigneter Stelle wird mit "xsl:apply-templates select" wiederum über XPath ein zweites Template aufgerufen, das für alle Ort-Knoten zuständig ist.

Dieses Prinzip können Sie weiter treiben: im Template Ort wird das Template name aufgerufen, das nun endlich die formatierte Ausgabe aus dem aktuellen Knoten (.) erzeugt.


<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <html>
      <body>
        <h3>Erste Transformation aus XML</h3>
        <xsl:apply-templates select="/Orte/Ort"/>
      </body>
    </html>
  </xsl:template>

Erste Auslagerung in ein Template: es wird bei jedem "Ort"-Element aufgerufen, das bei <xsl:apply-templates select="/Orte/Ort"/> angesprochen wird. Dieses Template ruft seinerseits wieder ein anderes auf: das template match="name".


  <xsl:template match="Ort">
    <xsl:apply-templates select="name"/>
  </xsl:template>

Das folgende Template "name" wird durch das vorhergehende Template "Ort" aufgerufen, und es ruft seinerseits ein anderes Template aus, ohne dieses jedoch klar zu bezeichnen.


  <xsl:template match="name">
    <p>Dieser Ort heisst: 
       <b><xsl:apply-templates/></b>
    </p>
  </xsl:template>

Zur Laufzeit stellt sich heraus, daß "name" einen Textnode als Childelement hat, der sich durch xsl:template match="text() ansprechen läßt.


  <xsl:template match="text()">
    <xsl:value-of select="."/>
  </xsl:template>

</xsl:stylesheet>

Der Template-Ansatz bietet die Möglichkeit, dass Sie diverse Templates in externe XSL-Dateien auslagern und diese später über einbinden können. Damit können Sie Stylesheets für diverse Ansätze leichter wieder verwenden. Ob sich die Auslagerung und der Re-Import tatsächlich als vorteilhaft erweisen, sei dahin gestellt.

Der Unterschied liegt in der Ranghierarchie der Templates: während beim include die eingebundenen Templates denselben Rang haben wie die Templates des inkludierenden Stylesheets, haben importierte Variable und Templates einen geringeren Rang als jene des importierenden Stylesheets.

Arbeiten mit xsl:next-match

entfernt vergleichbar, bietet die Arbeit mit xsl:next-match Zugriff auf eine flexible Verarbeitungslogik. Hier können wir mehrere Templates definieren, die dieselben Elemente mit unterschiedlichen Prioritäten ansprechen. (Dieser Effekt ist mit oder nicht erreichbar.)

Das folgende Beispiel soll dies veranschaulichen. xsl:template match="name" trifft sämtliche "name"-Elemente, "name[../name()='Mensch']" dagegen nur jene Elemente, deren Parent-Nodes "Mensch" heißen, und "name[../name()='Ort']" jene Elemente, deren Parentnodes "Ort" heißen. Letztere haben jedoch eine andere Priorität: durch den Aufruf von "xsl:next-match" wird das xsl:template match="name" angesprochen, das jedem generierten Element "STADT" oder "PERSON" ein Attribut "NAME" beifügt.


  <xsl:template match="/Orte">
    <ROOT>
      <xsl:apply-templates 
           select="descendant::name"/>
    </ROOT>
  </xsl:template>
  <xsl:template 
       match="name">
    <xsl:attribute name="NAME">
      <xsl:value-of select="."/>
    </xsl:attribute>    
  </xsl:template>  
  <xsl:template 
       match="name[../name()='Mensch']">
    <PERSON>
      <xsl:next-match/>
    </PERSON>    
  </xsl:template>
  <xsl:template 
       match="name[../name()='Ort']">
    <STADT>
      <xsl:next-match/>
    </STADT>    
  </xsl:template>

xsl:apply-templates bei mixed content

Da die Struktur der mixed-content-Dokumente oft nicht so klar und übersichtlich erkennbar sind, wie das bei datensatzbasierten Dokumenten erwartet werden kann, ist hier eine hohe Flexibilität bei der Behandlung erforderlich.

Diese wird häufig durch eine Auslagerung in Subroutinen implementiert, die sich durch apply-templates gegenseitig aufrufen. Dadurch entstehen gegenseitige Abhängigkeiten, deren Pflege mit steigender Anzahl bzw. Umfang (mehrere Tausend Codezeilen) unverhältnismäßig aufwändig und teuer werden kann.

Betrachten wir das folgende XML Dokument:


<?xml version="1.0" encoding="iso-8859-1"?>
<Abschnitt>
  <title>Namespaces</title>
  <para>Die enorme Gestaltungsflexibilität 
der <kursiv>XML Dokumente</kursiv> 
zwingt zu <fett>systematischer 
Strukturierung</fett>, damit die 
<kursiv>XML Dokumente</kursiv> 
systematisch ausgewertet werden können.</para>
  <para>Aber auch eine klare systematische Strukturierung von 
<kursiv><fett>Element- und Attributnamen</fett></kursiv> 
sowie deren <kursiv>Datentypen</kursiv> 
(etwa durch <link l="http://www.w3.org/2001/XMLSchema">XML Schema</link>) 
reicht nicht immer aus, begriffliche Kollisionen zu vermeiden. </para>
</Abschnitt>

Das XML Dokument weist eine gemischte Struktur aus Textinhalt und Formatierungsanweisungen auf, die zudem teilweise auch noch verschachtelt sind und deren Abfolge kaum vorhersehbar ist. Um dieses Dokument in HTML transformieren zu können, zeigt sich die Verwendung von xsl:template match-Anweisungen, die sich bei Bedarf gegenseitig aufrufen, als sehr flexibel:


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" indent="yes" />
  <xsl:template match="Abschnitt">
    <html>
      <body>
        <xsl:apply-templates />
      </body>    
    </html>
  </xsl:template>

  <xsl:template match="title">
    <h2>
      <xsl:apply-templates/>
    </h2>
  </xsl:template>

  <xsl:template match="para">
    <p>
      <xsl:apply-templates/>
    </p>
  </xsl:template>

  <xsl:template match="fett">
    <b>
      <xsl:apply-templates/>
    </b>
  </xsl:template>

  <xsl:template match="kursiv">
    <i>
      <font color="green">
        <xsl:apply-templates/>
      </font>
    </i>
  </xsl:template>

  <xsl:template match="link">
    <a href="{@l}">
      <xsl:apply-templates/>
    </a>
  </xsl:template>

  <xsl:template match="text()">    
    <xsl:value-of select="." />    
  </xsl:template>
</xsl:stylesheet>

Wie Sie unschwer feststellen können, gibt es nur ein einziges Template (xsl:template match="text()"), das Textinhalt ausgibt; sämtliche anderen Templates rufen andere Templates auf. So wird die Eingangsstruktur <kursiv><fett>Element- und Attributnamen</fett></kursiv> in der Weise verarbeitet, daß xsl:template match="kursiv" zuerst das xsl:template match="fett", und dieses wiederum xsl:template match="text()" aufruft. Das Ergebnis der XSL-Transformation mit einem üblichen Prozessor sieht wie folgt aus:


<html>
<body>  
<h2>Namespaces</h2>
<p>Die enorme Gestaltungsflexibilit&auml;t der 
<i><font color="green">XML Dokumente</font></i> 
zwingt zu <b>systematischer Strukturierung</b>, 
damit die <i><font color="green">XML Dokumente</font></i> 
systematisch ausgewertet werden k&ouml;nnen.</p>
<p>Aber auch eine klare systematische Strukturierung
von <i><font color="green"><b>Element- und 
Attributnamen</b></font></i> sowie deren 
<i><font color="green">Datentypen</font></i> (etwa durch 
<a href="http://www.w3.org/2001/XMLSchema">XML Schema</a>) 
reicht nicht immer aus, begriffliche Kollisionen 
zu vermeiden. </p>
</body>
</html>

was im Browser wie folgt interpretiert wird:

file:///#C:/wg/GoodPractise/Gesamtdokumentation/documentation/pic/HTML_Namespaces.png

Mehr zum Thema:

wg / 17. Januar 2018



Fragen? Anmerkungen? Tips?

Bitte nehmen Sie Kontakt zu mir auf:

Vorname
Nachname
Mailadresse







Vielen Dank für Ihr Interesse an meiner Arbeit.


V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info2018@wilfried-grupe.de

www.wilfried-grupe.de/XSL_apply_templates.html