- 1 Intro
- 2 Anwendungsgebiete
- 2.1 XSLT - die Programmiersprache im XML Bereich
- 2.2 Aktuelle und vergangene Anwendungen
- 2.3 Professionelle XML Verarbeitung
- 2.4 Technische Dokumentation
- 3 Wichtige Konzepte
- 3.1 Push vs. Pull Stylesheets
- 3.2 Eindeutigkeit der Regelbasis
- 3.3 Namespaces
- 3.4 Schemata
- 3.5 Standards
- 3.5.1 DITA
- 3.5.2 DITA Inhaltsmodell
- 3.5.1 DITA
- 4 Ausgewählte Themen
- 4.1 Transformationen mit XSLT
- 4.1.1 Vortransformationen
- 4.1.2 Komplexe XML-2-XML Transformationen
- 4.1.2.8 Vererbung
- 4.1.2.8 Vererbung
- 4.1.3 XSLT Streaming
- 4.1.3.1 XSLT Akkumulator
- 4.1.3.2 XSLT Iterator
- 4.1.4 Reguläre Ausdrücke
- 4.1.5 Modus vs. Tunnel Lösung
- 4.1.6 Identifikation mit
generate-id()
- 4.1.6.4 XPath-Achsenbereich selektieren
- 4.1.6.4.1 Funktionen und Module
- 4.1.6.4.1 Funktionen und Module
- 4.1.6.4 XPath-Achsenbereich selektieren
- 4.1.7 Webservice Calls mit doc() und unparsed-text()
- 4.1.8 Stylesheet-Parameter auf der Kommandozeile
- 4.1.9 Leerzeichenbehandlung
- 4.1.10 Mit
translate
Zeichen ersetzen
- 4.1.10.1 Spass mit dem Sequenzvergleich
- 4.1.11 Character Mappings in der Ausgabe
- 4.1.12 JSON mit XSLT 1.0 und Python lxml
- 4.1.1 Vortransformationen
- 4.2 Abfragen mit XQuery
- 4.2.5 XQuery als Programmiersprache
- 4.2.5.3
if..then..else
Ausdrücke
- 4.2.5.3.2 SQL Views in MarkLogic
- 4.2.5.3
if..then..else
Ausdrücke
- 4.2.6 Hilfreiche XQuery Schippsel
- 4.2.5 XQuery als Programmiersprache
- 4.3 XML Datenbanken
- 4.3.1 Connector zu Marklogic in Oxygen
- 4.3.2 Bi-Temporale Dokumente
- 4.3.2.1 Anlegen des Testszenarios auf der ML Konsole
- 4.3.2.2 Ausführen einiger Beispiel-Queries
- 4.3.3 Webapps mit MarkLogic
- 4.3.3.5 Wikipedia Scrapper Applikation
- 4.3.3.5 Wikipedia Scrapper Applikation
- 4.3.4 Dokument-Rechte in MarkLogic
- 4.3.5 MarkLogic Tools
- 4.3.5.1 EXPath Konsole
- 4.3.5.2 mlcp - MarkLogic Content Pump
- 4.3.5.3 Deployment-Tools
- 4.4 XSL-FO mit XSLT1.x
- 4.5 Testing
- 4.5.1 Validierung mit Schematron
- 4.5.2 Erste Schritte mit XSpec
- 4.5.1 Validierung mit Schematron
- 4.6 Performanz-Optimierung
- 4.1 Transformationen mit XSLT
- 5 Zusätzliches Know-How
- 5.1 XML Editoren
- 5.2 Quellcode-Versionskontrolle
- 5.2.1 Kurze Geschichte zur Versionskontrolle Test
- 5.2.2 GIT Kommandos
- 5.2.1 Kurze Geschichte zur Versionskontrolle Test
- 5.1 XML Editoren
- 6 Glossary
- 7 Tektur CCMS
4.1.1 Vortransformationen
Bei einer komplexen Transformation ist es ratsam und sogar manchmal unabdingbar die Konvertierung in einzelne Stufen aufzuteilen. Das hat folgende Vorteile:
-
Der Prozess ist transparenter, da die einzelnen Stufen leichter überschaubar sind.
-
Die Zwischenergebnisse können für Debug-Zwecke ausgewertet werde oder dienen als Eingabe für andere Prozesse.
-
Nicht-relevante oder invalide Teilbäume können aus der Eingabeinstanz gefiltert werden, um so die weitere Verarbeitung zu beschleunigen.
-
Hilfskonstrukte können erzeugt werden. Diese erleichtern die weitere Verarbeitung.
Es gibt zwei Möglichkeiten, wie eine Vortransformation eingebunden werden kann:
-
In einem separaten File bzw. einer XML Instanz, die vom XSLT Prozessor vor der eigentlichen Transformation aufgerufen wird und einen Zwischenstand produziert. Dieser kann dann als Eingabe für den Haupttransformationsschritt dienen.
-
Innerhalb des eigentlichen XSLT Stylesheets. Hier wird das Ergebnis der Vortransformation in einer Variablen erzeugt.
Den zweiten Punkt möchte ich anhand eines Beispiel XSLT Skripts vorführen. Betrachten wir folgende Input Daten:
<education-system> <administrative-regions> [...] <dministrative-region id="31" name="Bavaria"> <shools> <school id="45"> <teachers> <teacher id="576"/> <teacher id="345"/> <teacher id="12"/> </teachers> </school> <school id="36"> <teachers> <teacher id="576"/> <teacher id="8"/> </teachers> </school> [...] </shools> </dministrative-region> [...] </administrative-regions> </education-system>
Die erste Datei beinhaltet eine Zuordnung von Lehrern zu Schulen in verschiedenen Regierungsbezirken. Um die Daten zu den beiden referenzierten Objekten einzusehen, müssen zwei weitere Dateien konsultiert werden. Die Datei, welche die Lehrer auflistet:
<teachers> [...] <teacher id="576"> <first-name>Alfons</first-name> <last-name>Blimetsrieder</last-name> <subjects> <subject>Biology</subject> <subject>Math</subject> <subject>Sport</subject> </subjects> <suspended>2017-12-31</suspended> [...] </teacher> [...] </teachers>
Und die Datei, welche die Schulen auflistet:
<schools> [...] <school id="45"> <name>Gymnasium Bad Aibling</name> <type>Oberschule</type> [...] </school> [...] </schools>
Um diese Daten verarbeiten zu können ist es sinnvoll, die drei Dateien in einem ersten "Resolver" Schritt zusammenzuführen und ggf. irrelevante Strukturen zu entfernen. Lehrer aus obigem Beispiel können beispielsweise suspendiert worden sein. Das folgende Skript erledigt dies mittels einer zusätzlichen Transformation in eine Variable:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="#all"> <xsl:output indent="yes" method="xml"/> <xsl:strip-space elements="*"/> <xsl:param name="file-1" required="yes"/> <xsl:param name="file-2" required="yes"/> <xsl:param name="file-3" required="yes"/> <xsl:variable name="files" select="(doc($file-1), doc($file-2), doc($file-3))"/> <xsl:variable name="bavaria-region-ids" select="(31, 58)"/> <xsl:key name="teachers" match="teacher" use="@id"/> <xsl:key name="schools" match="school" use="@id"/> <xsl:template name="main"> <xsl:variable name="resolve-result"> <xsl:apply-templates select="$files/administrative-regions" mode="resolve"/> </xsl:variable> <xsl:apply-templates select="$resolve-result/administrative-regions"/> </xsl:template> <xsl:template match="administrative-region[not(@id = $bavaria-region-ids)]" mode="resolve"/> <xsl:template match="school" mode="resolve"> <xsl:copy> <xsl:copy-of select="key('schools',@id, $files/schools[1]/root())/node()"/> <xsl:apply-templates select="node()|@*" mode="resolve"/> </xsl:copy> </xsl:template> <xsl:template match="teacher" mode="resolve"> <xsl:copy-of select="key('teachers',@id, $files/teachers[1]/root())/node()"/> </xsl:template> <xsl:template match="teacher[suspended/xs:date(.) le current-date()]"/> <xsl:template match="node()|@*" mode="#all"> <xsl:copy> <xsl:apply-templates mode="#current"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Im ersten Resolve-Schritt werden die Referenzen zu den Lehrer- und Schul-Objekten aufgelöst, d.h. die Attribute des Schul-Objekts werden in die Struktur aus der ersten Datei kopiert.
Die Liste der Lehrer an diesen Schul-Objekten bleibt erhalten und wird mit dem Inhalt aus der zweiten Datei bestückt.
Zusätzlich werden alle Regierungsbezirke entfernt, die nicht zu Bayern gehören - was die weitere Verarbeitung wesentlich beschleunigen wird. Lehrer die suspendiert worden sind fliegen ebenfalls raus ...
4.1.1.1 In-Situ Vortransformation
Als ich mir kürzlich meinen Code vor zehn Jahren zu Gemüte führte, fiel mir ein sehr seltsames Stück XSLT auf, sinngemäss:
Datei: common/semantic-tables.xsl <xsl:template name="maintenance-table"> <cals-table-structure> [...] <<xsl:apply-templates select="maint-int"/> [...] </cals-table-structure> </xsl:template> <xsl:template match="maintenance-table"> <xsl:variable name="maintenance-table"> <xsl:call-template name="maintenance-table"/> </xsl:variable> <xsl:apply-templates select="$maintenance-table"/> </xsl:template>
Was hat mich denn da geritten? Ich bin ich dann
schon darauf gekommen... Der Clou ist hier eine Vortransformation innerhalb einer
Match-Regel.
Die Transformation innerhalb der Variablen rendert die semantischen Elemente der
Wartungstablle, wie z.B. das Wartungsintervall
maint-int
, in eine CALS-Tabelle.
Diese wird dann im nächsten Transformationsschritt entweder nach XSL-FO oder nach HTML
transformiert, je nachdem welche Haupt-Datei
main.xsl
das Modul
semantic-tables.xsl
importiert.
Datei html/main.xsl <xsl:import href="common/semantic-tables.xsl"/> <xsl:template match="cals-table-structure"> <html-tabllen-struktur> [...] </html-tabllen-struktur> </xsl:template> Datei pdf/main.xsl <xsl:import href="common/semantic-tables.xsl"/> <xsl:template match="cals-table-structure"> <pdf-tabllen-struktur> [...] </pdf-tabllen-struktur> </xsl:template>
Dieser Ansatz ist sehr flexibel, denn im herausfaktorisierten Tabellenalgorithmus können leicht Sonderfälle,
wie Duplikat-Eliminierung oder spezielle Merge-Operation, abgefangen werden. Zudem können sowohl das Named-Template
bzgl. der Wartungstabelle als auch die Match-Regel im importierenden Stylesheet überschrieben werden, was der Kreativität
keine Grenzen setzt.
4.1.1.2 Mehrstufige Transformationen
Bei manchen Kovertierungen reichen ein oder zwei hintereinander geschaltete Transformationsschritte nicht aus.
Vielleicht hat man es mit einer Struktur zu tun, die gar nicht zum Zielformat passt... Sei es, weil auf ein sehr restriktives Inhaltsmodel transformiert wird, sei es weil ERROR! Linktarget does not exist erst schrittweise erschlossen wird, da der Überblick über die Daten noch fehlt.
In jedem Fall muss für manche Elemente in einem späteren Schritt entschieden werden, wohin sie umsortiert werden sollten, weil sie jetzt gerade stören.
Beispiele:
1. | Transformationen auf ein restriktiveres Inhaltsmodell |
-
Das XHTML eines Webeditors, bei dem der User willkürlich die unterschiedlichsten Strukturen eingeben kann, wird auf die restrikte DTD eines XML Redaktionssystems gemappt.
2. | Ein restriktives, strukturiertes Inhaltsmodell soll in ein freieres, strukturiertes Inhaltsmodell konvertiert werden: |
-
Diese Form der Transformation findet man oft bei den Ausgabestrecken eines XML Redaktionssystems. Hier kommt man gut mit 2-3 Transformationsschritten aus. Diese werden dazu verwendet, um die Konvertierung zu erleichtern, und nicht aus "Platzgründen" wie in Punkt 1.)
3. | Transformationen von relativ unstrukturierten Daten. Hier muss man die Strukturen erst bilden. Das kann durch Einsammeln gleichartiger Elemente passieren, die dann hierarchisch in einer Baumstruktur geordnet werden. |
-
Baumstrukturen kann man z.B. auch aus Dateipfaden generieren, die dann mittels anderer Datenquellen noch angereichert werden, bspw. CSV-Dateien.
Mehrstufige Transformationen werden in Migrationen eingesetzt.