Typische Einsatzszenarien von XProc

Im Folgenden werden drei Szenarien vorgestellt, bei denen XProc zum Einsatz kommen könnte. Dabei werden die jeweiligen Quelltexte schrittweise besprochen. Da alle Szenarien ordnerweise XML-Daten einlesen und sie somit diesen Aspekt gemeinsam haben, soll dieses Vorgehen vorab erläutert werden:

Ordnerweises Einlesen und Übergabe in eine Schleife

Durch den Step <p:directory-list> wird der gesamte Inhalt eines Ordners ausgelesen. Um sicherzustellen, dass nur XML-Dokumente ausgelesen werden, wird dem Step als Option noch eine entsprechende Filteranweisung mitgegeben. Der Ordnername mit den Dokumenten heißt hier “input“ und wird in der Option “path“ angegeben.

<p:directory-list include-filter=".*xml" path="input"/>

Das Ausgabedokument dieses Steps umfasst sämtliche Elemente in einem <c:directory>-Element mit den dazugehörigen <c:file>-Kindelementen.

<c:directory name = string>
 (c:file |
  c:directory |
  c:other)*
</c:directory>

Da nur die <c:file>-Elemente von Interesse sind, weil sie die Dateinamen der XML-Dokumente beinhalten, müssen diese mit <p:filter> extrahiert werden.

<p:filter select="//c:file"/>

<p:filter> erhält einen entsprechenden XSLT-Ausdruck, der <c:file> adressiert. Somit werden nun alle <c:file>-Elemente dem nächsten Step übergeben.

<c:file name="dokument.xml" xmlns:c="http://www.w3.org/ns/xproc-step"/>
<c:file name="dokument2.xml" xmlns:c="http://www.w3.org/ns/xproc-step"/>
<c:file name="dokument3.xml" xmlns:c="http://www.w3.org/ns/xproc-step"/>
<c:file name="dokument4.xml" xmlns:c="http://www.w3.org/ns/xproc-step"/>
 

Der Step “for-each“ erzeugt eine Schleife, welche für jeden Durchlauf ein <c:file>-Element verarbeitet. Also so viele Schleifen-Iterationen durchführt, wie es XML-Dokumente im angegebenen Ordner gibt.

Zunächst wird innerhalb der Schleife eine Variable mit der Bezeichnung “filename“ angelegt, die den Namen der aktuellen Datei als Wert speichert. Der Name befindet sich im Attribut “name“ von <c:file> und wird durch einen XPath-Ausdruck ausgelesen.

<p:variable name="filename" select="c:file/@name"/>

Diese Variable ist für die spätere Verarbeitung relevant. Da in diesem “name“-Attribut lediglich der Dateiname aber keine Pfadangaben stehen, müssen diese durch den Step <p:make-absolute-uris> nachträglich angebracht werden, da die Dokumente im darauf folgenden Step sonst nicht weiterverarbeitet werden können.

<p:make-absolute-uris match="c:file/@name">
  <p:with-option name="base-uri" select="'input/'"/>
</p:make-absolute-uris>

Durch Hinzufügen der Option “base-uri“ mit dem Inhalt “input/“ wird den Dokumenten jeweils der korrekte Pfad angebracht. Die Option “base-uri“ repräsentiert den Pfad im Dateisystem, wo sich das XProc-Stylesheet befindet. Durch das Hinzufügen von “input/“, dem Ordner der XML-Dokumente, wird die Angabe vervollständigt und könnte je nach Beschaffenheit des Dateisystems so aussehen:

<c:file name="file:/Users/tg/Documents/Szenario/input/Dokument.xml" xmlns:c="http://www.w3.org/ns/xproc-step"/>

Ohne diese Korrektur kann der nächste Step <p:load>, welcher das Dokument laden wird, um es den folgenden Schritten zur Verfügung zu stellen, nicht finden. Der Step bekommt in seinem Attribut “href“, welches die zu ladende Datei referenziert, den Wert des zuvor durch den Pfadnamen erweiterten “name“-Attributs von <c:file>, in Form eines entprechenden XPath-Ausdrucks, zugewiesen.

<p:load dtd-validate="false">
   <p:with-option name="href" select="c:file/@name"/>
</p:load>

Das nun geladene Dokument wird einem <p:try>-Step übergeben. Das bedeutet, das alle nun folgenden Operationen in einem geschützten Zustand ausgeführt werden. Im Falle eines Fehlers, wird dieser durch <p:catch> aufgefangen, die Verarbeitung entsprechend abgeschlossen und die nächste Iteration der Schleife, respektive die nächste Datei, angegangen.

Diese Grundfunktionalität haben alle Szenarien gemeinsam.

SZENARIO 1: Cross Media Publishing

Eine Firma im Publishing-Bereich vertreibt ihre Veröffentlichungen in mehreren Formaten. So werden die Dokumente im PDF-, XHTML- und EPUB-Format vertrieben.

Während die Formate XHTML und PDF weitestgehend geläufig sind, ist EPUB nicht sonderlich populär. Aus diesem Grund wird das Format kurz vorgestellt.

EPUB (Electronic Publication) ist ein Standard für E-Books, welcher vom IDPF (International Digital Publishing Forum) herausgegeben wird. Es ist ein XML-basiertes Format, welches sich aus drei offenen Standards (Open Publication Structure, Open Packaging Format und OEBPS Container Format) zusammensetzt. Die Dateiendung einer EPUB-Datei trägt die Bezeichnung *.epub. Es ist im Wesentlichen ein ZIP-Container, der eine bestimmte Ordnerhierarchie beinhaltet, welche den eigentlichen Inhalt des Dokuments bereitstellt.

META-INF/
  container.xml
Mimetype
opf/
ops/

In den jeweiligen Unterordnern befinden sich die relevanten Dateien, die den Inhalt des EPUB-Dokuments beschreiben. Für mehr Informationen bezüglich EPUB ist die Homepage des IDPF zu empfehlen.

Als Grundlage für das gewünschte Cross Media Publishing-Verfahren werden die Rohinformationen in Form von XML-Dokumenten bereitgestellt. Diese XML-Dokumente durchlaufen diverse Qualitätssicherungsprozesse. So werden sie gegen ein XML-Schema und eine Schematron-Datei validiert. Erst danach werden sie durch entsprechende XSLT-Transformationen in die gewünschten Formate umgewandelt.

Mit XProc können diese Abläufe in einem Workflow definiert werden. So sollen die XML-Dokumente zunächst ordnerweise eingelesen werden. Diese werden dann einzeln innerhalb einer Schleife verarbeitet. Jedes Dokument muss zunächst gegen das vorgegebene XML Schema-Dokument validiert werden. Im Falle einer erfolgreichen Validierung, wird mit dem nächsten Schritt (Step) fortgefahren.

Verläuft die Validierung negativ, so wird eine Datei mit dem Namen des XML-Dokuments in einen entsprechend dafür vorgesehenen Ordner gelegt. Diese Datei enthält die entsprechende XProc-Fehlermeldung, die Rückschlüsse auf das zugrundeliegende Problem gibt. Danach wird mit dem nächsten Dokument weiter gearbeitet. Im zweiten Schritt wird eine Schematron-Validierung durchgeführt. Hier wird genauso vorgegangen wie im ersten Schritt. Ist das Resultat fehlerfrei, so wird der Prozess fortgesetzt. Ist es nicht fehlerfrei, so wird eine Datei mit Namen des XML-Dokuments und die Fehlerinformationen im entsprechenden Ordner abgelegt und mit dem nächsten Dokument weitergearbeitet.

Sind die Validierungsarbeiten erfolgreich abgeschlossen, kann das XML-Dokument in die gewünschten Formate durch eine XSLT-Transformation umgewandelt werden. Gesetzt den Fall, dass die Transformationen ebenfalls Fehler verursachen (z.B. durch einen Fehler im XSLT-Stylesheet), wird hier ebenfalls eine gleichnamige Fehlerdatei erzeugt.

Die folgende Grafik zeigt den Ablauf des XProc-Skripts.

Abbildung Szenario Publishing

Abb. Szenario Publishing

Da das ordnerweise Einlesen bereits besprochen wurde, steigt diese Erklärung direkt im <p:try>-Step ein. Weil das Verhalten im <p:catch>-Bereich bei allen Szenarien identisch ist, wird dies einmalig am Ende des Textes (siehe p:catch in den Szenarien) besprochen.

Der erste Schritt innerhalb des “Try-Blocks“ ist nun die Validierung gegen ein XML Schema-Dokument. Dies wird durch den Step <p:validate-with-schema> realisiert. Zuvor wird noch ein <p:group>-Element eröffnet, was alle im <p:try> vorkommenden Steps umschließt. Dies ist eine Vorgabe von <p:try>. Als nächstes folgt die XML Schema-Validierung.

<p:validate-with-xml-schema assert-valid="true" mode="strict">
   <p:input port="schema">
      <p:document href="xml_schema.xsd"/>
   </p:input>
</p:validate-with-xml-schema>

Innerhalb dieses Schritts wird das zu verwendende XML Schema-Dokument angegeben. Verläuft die Validierung erfolgreich, so wird das ursprünglich eingelesene XML-Dokument an den nächsten Step weitergereicht. Dieser kümmert sich um die Schematron-Validierung.

<p:validate-with-schematron assert-valid="true" name="schematron">
  <p:input port="parameters">
    <p:empty/>
  </p:input>
  <p:input port="schema">
    <p:document href="schematron.sch"/>
  </p:input>
</p:validate-with-schematron>

Auch hier wird analog zum vorherigen Step das Schematron-Schema-Dokument angegeben. Verläuft auch diese Validierung erfolgreich, so wird in den nächsten Schritten die Umwandlung in die entsprechenden Formate vorgenommen.

Die Umwandlungen werden allesamt durch den Step <p:xslt> durchgeführt. Da drei unterschiedliche Formate aus demselben XML-Dokument erzeugt werden sollen, müssen dementsprechend drei <p:xslt>-Steps ausgeführt werden. Sie alle bekommen als initialen Wert an ihrem jeweiligen Input-Port den Output-Port des zuvor durchgeführten Schematron-Validierungs-Steps zugewiesen.

Direkt darauf folgend wird, je nach Format, ein passender Folgeschritt durchgeführt. Im Fall von HTML wird ein <p:store>-Step ausgeführt, welcher das zuvor transformierte Dokument abspeichert. Hierbei kommt wiederum die eingangs angelegte Variable “filename“ zum Tragen, welche dem <p:store>-Step mitteilt, wie der Name des zu erstellenden Dokuments heißen soll.

<p:xslt>
   <p:input port="source">
      <p:pipe port="result" step="schematron"/>
   </p:input>
   <p:input port="stylesheet">
      <p:document href="xslt_stylesheet.xsl"/>
   </p:input>
   <p:input port="parameters">
      <p:empty/>
   </p:input>
</p:xslt>
<p:store>
   <p:with-option name="href" select="concat('./output/success/html/',$filename,'.html')"/>
</p:store>

Dem Input-Port “source“ von <p:xlst> wird der Output-Port des <p:validate-with-schematron>-Steps zugewiesen. Am Input-Port “stylesheet“ wird das zu verwendende XSLT-Stylesheet angegeben. Nach der Durchführung des Steps wird sein Resultat am Output-Port an den darauf folgenden <p:store>-Step übergeben. Dieser speichert das Resultat in einer Datei mit demselben Namen des initalen XML-Dokuments im Ordner “output/success/html“ ab. Allerdings mit der Extension “.html“. Dies wird durch die Funktion “concat“ realisert. Mit dieser Funktion ist es möglich, mehrere String-Elemente zu einem String zusammenzuführen. Im Beispiel also die Pfadangabe und der Inhalt der Variablen “filename“.

Dieses Vorgehen wird noch zwei mal für die anderen Formate wiederholt. Jedoch mit dem Unterschied, dass die XSLT-Transformationen unterschiedliche Stylesheets hinterlegt bekommen. Während das erste eine XHTML-Transformation durchgeführt hat, wird durch die anderen beiden eine PDF- und EPUB-Transformation realisiert. Das Stylesheet, welches für die EPUB-Realisierung zuständig ist, erstellt die EPUB-typische Ordnerstruktur, damit diese im nächsten Schritt entsprechend weiterverarbeitet werden kann. Um ein PDF zu erzeugen, muss für einen XSL-FO Formatierer ein FO-Dokument erzeugt werden. Dies wird durch das Stylesheet umgesetzt.

Für das Erstellen der EPUB-Ausgabe wird im Folgeschritt der Step <p:exec> aufgerufen. Durch diesen ist es möglich, externe Programme in XProc zu verwenden. Für die weitere Verarbeitung wird mit diesem Step ein Perl-Skript aufgerufen.

<p:make-absolute-uris name="absolute" match="perl">
   <p:input port="source">
    <p:inline>
       <uris>
         <perl>epub.perl</perl>
       </uris>
    </p:inline>
   </p:input>
</p:make-absolute-uris>
<p:exec command="perl" result-is-xml="false" source-is-xml="false" name="Zip">
   <p:log port="errors" href="error.txt"/>
   <p:with-option name="args" select="substring-after(uris/perl,'file:')"/>
   <p:input port="source">
     <p:empty/>
   </p:input>
</p:exec>

Um den <p:exec>-Step bedienen zu können, muss zuvor die Angabe der Perl-Datei aufbereitet werden. Da <p:exec> absolute Pfadangaben benötigt, müssen diese durch den Step <p:make-absolute-uris> entsprechend absolut gemacht werden. Ansonsten kann die Datei nicht gefunden werden, da der Step immer im Verzeichnis des auszuführenden Programms sucht. Anschließend wird das Perl-Skript ausgeführt. Die Angabe der Datei erfolgt im Attribut “args“ durch den Befehl “substring-after“. Dieser passt den Rückgabewert von <p:make-absolute-uris> entsprechend an, indem das voranstehende “file:“, was im Rückgabewert enthalten ist, ausgelassen wird. So kann <p:exec> das Perl-Skript finden und ausführen.

Dieses Perl-Skript erzeugt aus den durch die XSLT-Transformation erstellten EPUB-Ordnern ein ZIP-Dokument und ersetzt die Dateiendung mit *.epub. Abschließend wird das neu-erstellte EPUB-Dokument noch mit dem frei erhältlichen Programm “epubcheck“ validiert. So wird sichergestellt, dass die Datei auf allen gängigen EPUB-Readern gelesen werden kann. Ist das Dokument valide, wird es in den Ordner “output/sucess/epub“ kopiert.

Anstatt eines Perl-Skripts hätte z.B. auch eine “Batch“-File oder ein “Shell-Skript“ verwendet werden können. Denkbar ist auch, dass durch <p:exec> ein kommandozeilenbasiertes (oder unterstützendes) Zip-Tool (z.B. mit dem Programm “tar“) angesprochen wird, um die ZIP-Datei zu erstellen. Darauf müssten zwei weitere <p:exec>-Steps folgen, um das File zunächst in eine “*.epub“-Datei umzubenennen (z.B. durch den Linux-Befehl mv) und anschließend mit dem “epubcheck“-Programm zu validieren. Im Beispiel werden diese Schritte mit einem Perl-Skript zusammengefasst, da das Erstellen von EPUB-Dokumenten nicht der primäre Kern des Szenarios ist.

Um ein PDF zu erzeugen, wird das durch die XSLT-Transformation generierte XSL-FO Dokument dem Step <p:xsl-formatter> übergeben. Dieser wandelt es in ein PDF um und legt eine Datei im Ordner “output/sucess/pdf/“ an. Als Dateiname wird hier ebenfalls der ursprüngliche Name des XML-Dokuments (allerdings mit der Erweiterung *.pdf) verwendet.

<p:xslt name="XSl">
   <p:input port="source">
      <p:pipe port="result" step="schematron"/>
   </p:input>
   <p:input port="stylesheet">
      <p:document href="xslt_zu_fo.xsl"/>
   </p:input>
   <p:input port="parameters">
      <p:empty/>
   </p:input>
</p:xslt>
<p:xsl-formatter name="XSl2" content-type="application/pdf">
   <p:with-option name="href" select="concat('./output/success/pdf/',$filename,'.pdf')"/>
   <p:input port="source">
      <p:pipe port="result" step="XSl"/>
   </p:input>
   <p:input port="parameters">
      <p:empty/>
   </p:input>
</p:xsl-formatter>

Der zu erstellende Dateiname des PDFs wird durch <p:with-option> und einem weiteren “concat“-Befehl realisiert. Es wird ein String erzeugt, der zunächst den gewünschten Zielordner und abschließend den Dateinamen mit der Endung *.pdf erhält.

Am Ende des kompletten Pipeline-Durchlaufs steht dem Benutzer also eine Ordnerstruktur zur Verfügung, die sämtliche erfolgreich durchgeführten Umwandlungen beinhaltet. Aber auch alle fehlgelaufenen Transformationen, inklusive der entsprechenden Diagnoseinformationen, werden im Ordner “output/fail“ bereitgestellt.

SZENARIO 2: Datenmigration

Zwei Firmen möchten fusionieren. Beide Unternehmen haben in den Jahren ihrer Existenz eine enorme Menge an XML-Daten, in den jeweiligen Unternehmensstrukturen, angesammelt. Diese Daten müssen zusammengefasst werden.

Dies wird mit diversen XSLT-Transformationen realisiert. Basierend auf einem neu-definierten, gemeinsamen Regelwerk (z.B. XML Schema) wird durch entsprechende Transformationen aus den vorhandenen XML-Dokumenten, neues, ebenfalls XML-basiertes Datenmaterial geschaffen.

Vor der Transformation werden die initalen XML-Dokumente gegen ein XML-Schema und anschliessend ein Schematron-Schema überprüft. Dies soll sicherstellen, dass die Transformation ordnungsgemäß durchgeführt werden kann. Da die Daten der beiden Firmen stellenweise jedoch zu unterschiedlich sind, müssen sie zuvor noch durch das Einsetzen von regulären Ausdrücken und Suchen/Ersetzen-Aktionen mittels eines Perl-Skripts aufbereitet werden. Erst danach können sie transformiert werden.

Nach der Umwandlung via XSLT wird das neu-erzeugte XML-Dokument ein weiteres Mal gegen ein Schematron-Schema überprüft. Ist diese Validierung erfolgreich, so wird das neue Dokument in einem entsprechenden Ordner abgespeichert.

Auch diesen Ablauf gilt es in einer XProc-Pipeline zu definieren. Verläuft das Dokument den kompletten Durchgang ohne Fehler, so wird es abgespeichert. Im Falle eines Fehlers, wird ein Dokument mit demselben Namen angelegt. Dieses enthält jedoch die entsprechende XProc-Fehlermeldung. Somit können Rückschlüsse auf die Ursache des Problems geschlossen werden.

Die folgende Grafik repräsentiert den Ablauf des XProc-Skripts.

Abbildung Szenario Datenmigration

Abb. Szenario Datenmigration

Da das ordnerweise Einlesen bereits besprochen wurde, steigt diese Erklärung direkt im <p:try>-Step ein. Da das Verhalten im <p:catch>-Bereich bei allen Szenarien identisch ist, wird dies am Ende des Textes erklärt (siehe p:catch in den Szenarien).

Der erste Schritt innerhalb des Try-Blocks ist nun die Validierung gegen ein XML Schema-Dokument. Dies wird durch den Step <p:validate-with-schema> realisiert. Zuvor wird noch ein <p:group>-Element eröffnet, was alle im <p:try> vorkommenden Steps umschließt. Dies ist eine Vorgabe von <p:try>. Als nächstes folgt die XML Schema-Validierung.

<p:validate-with-xml-schema assert-valid="true" mode="strict">
   <p:input port="schema">
     <p:document href="xml_schema.xsd"/>
   </p:input>
</p:validate-with-xml-schema>

Innerhalb dieses Schritts wird das zu verwendende XML Schema-Dokument angegeben. Verläuft die Validierung erfolgreich, so wird das initial eingelesene XML-Dokument an den nächsten Step weitergereicht. Dieser kümmert sich um die Schematron-Validierung.

<p:validate-with-schematron assert-valid="true" name="schematron">
  <p:input port="parameters">
    <p:empty/>
  </p:input>
  <p:input port="schema">
    <p:document href="schematron.sch"/>
  </p:input>
</p:validate-with-schematron>

Am Input-Port “schema“ wird das Schematron-Dokument angegeben. Gegen dieses Schema wird das eingelesene XML-Dokument validiert. Ist diese Validierung erfolgreich, wird das XML-Dokument an den nächsten Step (<p:store>) weitergereicht. Hier wird eine temporäre Kopie namens “temp.xml“ des XML-Dokuments angelegt. Dies ist für das spätere Ausführen des Perl-Skripts relevant.

<p:store href="temp.xml">
   <p:input port="source">
     <p:pipe port="result" step="schematron"/>
   </p:input>
</p:store>

Da das Perl-Skript durch den Step <p:exec> ausgeführt wird, müssen weitere Vorbereitungen getroffen werden.

<p:make-absolute-uris name="absolute" match="perl">
   <p:input port="source">
   <p:inline>
      <uris>
        <perl>perl_skript.pl</perl>
        <perl>temp.xml</perl>
      </uris>
   </p:inline>
   </p:input>
</p:make-absolute-uris>

Das Perl-Skript hat den Dateinamen “perl_skript.pl“. Es soll die Zwischenkopie des initalen, sich aktuell in der Schleife befindenden XML-Dokuments “temp.xml“ verarbeiten. Dem Step <p:exec> wird später mittgeteilt, dass er das Programm “perl“ ausführen soll. Der entsprechende Befehl auf der Kommandozeile würde so aussehen:

perl perl_skript.pl temp.xml

In XProc, respektive der aktuellen Pipeline, sieht dieser Befehl folgendermaßen aus:

<p:exec command="perl" result-is-xml="true" source-is-xml="false" name="exec">
  <p:log port="errors" href="error.txt"/>
  <p:with-option name="args" select="concat(substring-after(uris/perl[1],'file:'),' ',substring-after(uris/perl[2],'file:'))"/>
  <p:input port="source">
    <p:empty/>
  </p:input>
</p:exec>

XProc geht davon aus, dass das aktuelle Arbeitsverzeichnis, in dem sich die angegeben Daten befinden, dasselbe ist, wie das Verzeichnis des auszuführenden Programms. Da dies selten der Fall ist, wird durch den Step <p:make-absolute-uris> eine absolute Pfadangabe der gewünschten Dokumente realisiert. Dem Attribut “args“ von <p:exec> wird nun ein String übergeben. Dieser beinhaltet die vollständigen Pfadangaben zu “perl_skript.pl“, ein Leerzeichen als Trennzeichen und “temp.xml“. Der String wird durch die Befehle “concat“ und “substring-after“ zusammengefasst. Letzterer gibt seinen Inhalt erst ab einer bestimmten Stelle aus. Im Beispiel nach “file:“. Da <p:make-absolute-uris> sämtlichen Einträgen ein “file://“ voranstellt, kann Perl nicht ordnungsgemäß ausgeführt werden. Es würde die Datei nicht finden können (entspricht nicht der Eingabesyntax). Durch den Einsatz von “substring-after“ wird der String entsprechend manipuliert, sodass Perl die Dateien finden kann.

Somit kann der Step erfolgreich durchgeführt werden. Vorausgesetzt die betroffenen Dokumente befinden sich im selben Verzeichnis wie das XProc-Stylesheet (denn darauf bezieht sich <p:make-absolute-uris>).

Ein weiterer Ansatz wäre eine Angabe des aktuellen Arbeitsverzeichnisses (zu definieren im Attribut “cwd“). Allerdings ist hier eine dynamische Angabe durch XProc-Hausmittel nicht möglich, da sämtliche Methoden, um Pfadangaben zu erhalten (<p:base-uri()>, <p:make-absolute-uris>, <p:resolve-uri>), sich auf Elemente beziehen oder als abschließende Angabe den Dateinamen des XProc-Stylesheets an die Pfadangabe anhängen.

Nach dem Durchführen des <p:exec>-Steps wird das Resultat mit einem <c:result>-Wrapper umschlossen.

<c:result>string</c:result>

Da dies jedoch nicht gewünscht ist, wird durch <p:filter> der Inhalt von <c:result> extrahiert und dem nächsten Step übergeben.

<p:filter name="filter" select="c:result/*"/>

Durch die Angabe des XPath-Ausdrucks “c:result/*“ im Attribut “select“, wird festgelegt, dass sämtliche Inhalte innerhalb von “c:result“ ausgegeben werden sollen. Diese werden nun dem Step <p:xslt> übergeben, welcher die entsprechende Transformation durchführt.

<p:xslt name="transformer">
  <p:input port="source">
    <p:pipe port="result" step="filter"/>
  </p:input>
  <p:input port="stylesheet">
    <p:document href="xslt_stylesheet.xsl"/>
  </p:input>
  <p:input port="parameters">
    <p:empty/>
  </p:input>
</p:xslt>

Verläuft diese Transformation erfolgreich, wird das Ergebnis einer weiteren Schematron-Überprüfung übergeben. Diese soll sicherstellen, dass die neuen Daten den vorgegebenen Qualitätsmerkmalen gerecht werden. Abschließend wird das Dokument abgespeichert (durch <p:store>). Als Dateiname wird der Wert der eingangs angelegten Variablen “filename“ verwendet.

<p:validate-with-schematron assert-valid="true" name="schematron2">
  <p:input port="parameters">
    <p:empty/>
  </p:input>
  <p:input port="schema">
    <p:document href="schematron_2.sch"/>
  </p:input>
</p:validate-with-schematron>
<p:store>
 <p:with-option name="href" select="concat('./output/success/',$filename)"/>
 <p:input port="source">
   <p:pipe port="result" step="schematron2"/>
 </p:input>
</p:store>

Am Ende des kompletten Durchlaufs (also sämtlicher Schleifendurchgänge) steht dem Benutzer eine Ordnerstruktur zur Verfügung, die alle erfolgreich absolvierten und fehlgeschlagenen Prozesse bereitstellt.

SZENARIO 3: Round-Tripping

Ein Verlag produziert Dokumente in mehreren Formaten (Cross Media Publishing). Da die jeweiligen Autoren nicht mit XML-Editoren arbeiten möchten, wird Microsoft Word verwendet.

Die daraus produzierten Dokumente (das *.docx-Format von Word ist XML-basiert) werden durch entsprechende XSLT-Transformationen in Docbook-Dokumente (ein spezielles XML-bezogenes Format, welches für Print optimiert wurde) umgewandelt. Darauf aufbauend werden durch erneute Transformationen Konvertierungen in die gewünschten Formate (z.B. PDF) vorgenommen.

Die erzeugten Docbook-Dokumente müssen wieder in ihren ursprünglichen Zustand (Word) zurückgeführt werden können. Dazu ist eine weitere XSLT-Transformation, mit einem entsprechenden Stylesheet, notwendig. Diesen Vorgang bezeichnet man als Round-Tripping. Somit könnte beispielsweise ein Lektor, der nachträglich XML-bezogene Veränderungen im Docbook-Dokument vorgenommen hat (z.B. Satzänderungen), die neue Version anschließend wieder nach Word konvertieren. Diese würde dann dem entsprechenden Autor zugesendet werden, um es dann für die kommende Auflage weiterverwenden zu können.

Im folgenden Workflow wird innerhalb einer Pipeline ein Word-Dokument zunächst gegen XML Schema und Schematron validiert. Danach wird es zu DocBook transformiert. Dieses neu entstandene Docbook-Dokument wird nun wiederum zu Word zurücktransformiert.

Abschließend wird dieses neu entstandene Dokument mit dem eingangs eingelesenen Word-File verglichen. Sind sie identisch, ist sichergestellt, dass der Erhalt der Daten-Struktur gewährleistet ist. Dieser letzte Vorgang dient der Sicherstellung der einwandfreien Rücktransformierung und ist vorwiegend während der Entwicklungsphase relevant.

Die folgende Grafik repräsentiert den Ablauf des XProc-Skripts.

Abbildung Szenario Round-Tripping

Abb. Szenario Round-Tripping

Da das ordnerweise Einlesen bereits besprochen wurde, steigt diese Erklärung direkt im <p:try>-Step ein. Weil das Verhalten im <p:catch>-Bereich bei allen Szenarien identisch ist, wird dies im am Ende des Textes beschrieben (siehe <p:catch> in den Szenarien).

<p:validate-with-xml-schema assert-valid="true" mode="strict">
   <p:input port="schema">
     <p:document href="xml_schema.xsd"/>
   </p:input>
</p:validate-with-xml-schema>

Zunächst wird das eingelesene Dokument gegen eine XML Schema-Datei im Step <p:validate-with-xml-schema> validiert. Im Input-Port “schema“ wird das zu verwendende Schema-Dokument definiert. Verläuft diese Validierung erfolgreich, wird im nächsten Step eine Validierung gegen ein Schematron-Dokument vorgenommen.

<p:validate-with-schematron assert-valid="true" name="schematron">
  <p:input port="parameters">
    <p:empty/>
  </p:input>
  <p:input port="schema">
    <p:document href="schematron.sch"/>
  </p:input>
</p:validate-with-schematron>

Im Step <p:validate-with-schematron> wird das vom vorherigen Step ausgegebene Dokument eingelesen und gegen ein Schematron-Schema validiert. Das Schematron-File wird am Input-Port “schema“ angegeben. Verläuft die Validierung erfolgreich wird das eingelesene Dokument an den nächsten Step weitergegeben.

<p:xslt name="transformer">
 <p:input port="stylesheet">
   <p:document href="xslt_stylesheet_1.xsl"/>
 </p:input>
 <p:input port="parameters">
   <p:empty/>
 </p:input>
</p:xslt>

Die Transformation durch <p:xslt> erzeugt basierend auf den Eingangsdaten ein DocBook-Dokument. Das XSLT-Stylesheet wird am Input-Port “stylesheet“ angegeben. Verläuft der Prozess erfolgreich, wird das neu-erstellte Dokument an einen weiteren Transformierungsschritt übergeben.

<p:xslt name="transformer_2">
<p:input port="source">
  <p:pipe port="result" step="transformer"/>
</p:input>
<p:input port="stylesheet">
  <p:document href="xslt_stylesheet_2.xsl"/>
</p:input>
<p:input port="parameters">
  <p:empty/>
</p:input>
</p:xslt>

In dieser zweiten Transformierung wird das zuvor erstellte DocBook-Dokument zurück zu Word gewandelt. Das Resultat wird dann weitergegeben.

<p:compare fail-if-not-equal="true">
  <p:input port="source">
    <p:pipe port="result" step="transformer"/>
  </p:input>
  <p:input port="alternate">
    <p:pipe port="result" step="transformer_2"/>
  </p:input>
</p:compare>

Im nun folgenden Step <p:compare> wird das zurückgewandelte Dokument mit dem eingangs Eingelesenen verglichen. Am Port “source“ wird das erste Dokument angegeben. Am Port “alternate“ wird das zweite zu vergleichende Dokument festgelegt. Ist das Attribut “fail-if-not-equal“ auf “true“ gesetzt, veranlasst es den Step, mit einem Fehler abzubrechen, sollten die Dokumente nicht identisch sein.

Abschließend wird das DocBook-Dokument durch den <p:store>-Step gespeichert.

<p:store>
  <p:with-option name="href" select="concat('./output/success/',$filename)"/>
    <p:input port="source">
      <p:pipe port="result" step="transformer"/>
    </p:input>
</p:store>

Der Name des erzeugten Dokuments ergibt sich durch den Wert aus der eingangs angelegten Variablen “filename“.

Am Ende des kompletten Pipeline-Durchlaufs steht dem Benutzer ein Ordner mit sämtlichen gewandelten DocBook-Dokumenten zur Verfügung. Alle fehlgeschlagenen Vorgänge werden in einem entsprechenden Ordner mit den jeweiligen Fehlermeldungen angelegt.

<p:catch> in den Szenarien

Da bei allen Szenarien das Verhalten von <p:catch> identisch ist, wird dies hier einmalig beschrieben.

Wenn im <p:try>-Bereich ein dynamischer Fehler entsteht, beispielsweise durch einen Validierungsfehler innerhalb eines <p:validate-xml-schema>-Steps, so wird dieser Bereich direkt verlassen. Normalerweise würde ein dynamischer Fehler den Abbruch einer Pipeline bedeuten. Da aber in den Szenarien schleifenweise gearbeitet wird, müssen Fehler abgefangen und entsprechend protokolliert werden, um dann mit der nächsten Datei fortfahren zu können.

Dies wird im <p:catch>-Bereich realisiert. Die entstandenen Fehler werden aufgefangen (to catch) und von einem <p:store>-Step gespeichert. Als Input-Port dient hierbei der sogenannte “error“-Port. Er wird von <p:catch> bereitgestellt.

<p:store>
  <p:with-option name="href" select="concat('./output/fail/',$filename)"/>
    <p:input port="source">
      <p:pipe port="error" step="catch"></p:pipe>
    </p:input>
</p:store>

Der Dateiname entsteht durch die Variable “filename“. Sie wird bei jedem Szenario anfangs angelegt und enthält als Wert den Dateinamen vom aktuellen XML-Dokument. Ein aufgetretener Fehler wird also in einem entsprechenden Verzeichnis (fail) mit demselben Dateinamen wie das derzeit bearbeitete Dokument abgespeichert.

Nach dem Verlassen des <p:catch>-Bereichs wird die Schleife fortgeführt oder, falls es sich um den letzten Durchlauf handelte, beendet.

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