Samstag, 4. August 2007

XSLT in BSP-Anwendungen und in ABAP

Am 17. Juli schrieb ich hier: "Dieses Geschäft – XML in HTML zu konvertieren – können mittlerweile Webbrowser erledigen." Für Intranet-Anwendungen wird oft eine überschaubare Menge an Browsern eingesetzt. Besonders dort ist es sinnvoll, die Präsentierung gewisser Seiten auf XML und clientseitiges Rendering umzustellen: Etwa für Seiten, die zu 90 % aus festem HTML-Code bestehen und nur zu 10 % dynamische Information enthalten.

Um auf "Nummer sicher" zu gehen, kann man die Möglichkeit vorsehen, als Fallback die Anwendung eben doch bereits auf dem Server in HTML-Code umzuwandeln. Man vergibt damit zwar die Vorteile des clientseitigen Renderns, da wieder immer gleiche HTML-Bestandteile durchs Netz geschickt werden und der Server die Last der Präsentierung hat. Aber sollte es für gewisse Browserversionen zu Problemen kommen, kann man wenigstens diese Browsertypen mit dem fertigen HTML bedienen, so dass die Anwendung verwendbar bleibt.

Es empfiehlt sich, einen regulären Ausdruck als Applikationsparameter vorzusehen. Der reguläre Ausdruck wird zur Laufzeit auf den User-Agent-String des Browsers angewendet. Trifft er zu, soll serverseitig gerendert werden.

Nun kann ABAP zwar XSLT-Transformationen mit der Anweisung call transformation ausführen, jedoch nur, wenn die Transformationen in der Workbench als Repository-Objekt angelegt wurden. Es ist nicht möglich, eine XSLT-Transformation auszuführen, die beispielsweise als String (oder als Objekt vom Typ if_ixml_document) vorliegt. Wenn man die XSLT-Transformation als BSP-Seite entwirftt, enthält sie in der Regel auch Scripting - und sei es nur die Beschaffung sprachabhängiger Texte mit <%=otr(...)>. Das macht eine ABAP-seitige Ausführung der Transformation mit der Anweisung call transformation vorerst unmöglich (so lange bis sich auf diesem Feld im ABAP etwas tut).

An diesem Punkt könnte man nun aufgeben und den Abteilungen mit debilen Browsern einfach zu einem Upgrade raten. Sicher keine verwerfliche Entscheidung. Wenn man aber trotzdem auf dem Fallback-Mechanismus beharrt, bleibt einem nichts anderes übrig, als die Transformation in die Workbench zu kopieren und das Scripting durch entsprechende SAP-Funktionsaufrufe zu ersetzen. Nun ist Kopieren der Todfeind aller robusten und wiederverwendbaren Programmierung. Mindestens bin ich in einer solchen Situation verpflichtet, einen Unit Test schreiben, der prüft, dass in beiden Fällen dasselbe Resultat entsteht: Sowohl bei Anwendung der in der BSP-Applikation als Seite enthaltenen Transformation als auch beim Workbench-Objekt.

Letzteres kann nun - das war ja der Sinn der Sache - mit der Anweisung call transformation ausgeführt werden, ersteres mit ABAP-Mitteln nicht. Wie aber dann einen ABAP Unit Test schreiben?

Lösung: Verwendung eines XSLT-Prozessors via externes Betriebssystemkommando!

Auf unserem Applikationsrechner, einer HP-UX Maschine, ist ein Java Development Kit 1.4.2 installiert (ein relativ moderates Release und keine besonders spannende Info, zugegeben). Nun enthält Java 4 einen eingebauten XSLT-Prozessor - den Xalan-Prozessor von Apache. Dieser lässt sich für eine solche Aufgabe nutzen.

Leider erwies sich der in die Java Runtime eingebaute Xalan-Prozessor in dieser Java-Version als fehlerbehaftet: Er verschluckte sich an einigen meiner XPath-Angaben , obwohl diese durchaus dem Standard entsprachen. Ich konnte mein XSLT-Stylesheet erst mit der aktuellen Xalan-Version 2.7.0 korrekt ausführen, wie ich auf meinem Notebook mit einer Java 5 Installation verifizierte. Da org.apache.xalan irgendwo in den Tiefen der Java 1.4.2-Installation versteckt ist, war es nicht so einfach, die Java Runtime davon zu überzeugen, statt der eingebauten Version die neuesten, von xml.apache.org/xalan-j heruntergeladenen JAR-Files zu verwenden. Hier hat sich das FAQ-Studium für einmal ausgezahlt: Man muss den "Endorsed Directory" Mechanismus von Java verwenden: Die alternativ zu verwendenden Jar-Files werden in einem Verzeichnis abgelegt, und der Pfad auf dieses Verzeichnis wird zum Beispiel in der Kommandozeile mittels des Zusatzes java -Djava.endorsed.dirs=... bekanntgegeben.

Ist diese Hürde genommen, so steht einem ein Up-To-Date XSLT-Prozessor zur Verfügung: Man kann in Transaktion SM69 ein externes Betriebssystemkommando Z_XSLT definieren, das die Pfade auf eine XML- und eine XSLT-Datei entgegennimmt und das Resultat in einer dritten Datei zurückgibt. Der Rest ist dann einfach: Das Xalan-Resultat wird mit dem CALL TRANSFORMATION-Resultat verglichen. Wenn die Ergebnisse nicht übereinstimmen, ist der Unit Test nicht bestanden. Da die Unit Tests in unseren Entwicklungssystemen täglich automatisch ausgeführt werden, kann ich auf diese Weise gut absichern, dass die XSLT-Transformation und die BSP-Seite auch in Zukunft stets synchron gehalten werden.

Für den Einsatz in Tests ist gegen die Verwendung eines externen Betriebssystemkommandos sicher überhaupt nichts einzuwenden. In produktiven Anwendungen sollte man sich nur in äussersten Notfällen auf solche Wege begeben. Vor allem aus Effizienzgründen. Es muss ein neuer Prozess des Betriebssystems erzeugt werden, die Java Laufzeit muss hochgefahren werden (was ätzend lange dauert - und pro Release immer länger), Daten müssen auf dem Umweg über temporäre Dateien hin- und hergeschaufelt werden. In der Regel ist der ins SAP-System eingebaute XSLT-Prozessor ja auch voll ausreichend. Ausser eben in Spezialfällen wie dem hier geschilderten.

Vielleicht kann der XSLT-Prozessor der ABAP Runtime in einer nahen Zukunft auch einmal XSLT-Transformationen ausführen, die ihm als String oder XML-Dokument gegeben werden. Dann kann die redundante Transformation der Workbench wieder verschwinden (und ebenso der Unit Test), und auch meine Fallbacklösung "serverseitiges XSLT" kann direkt die in der BSP-Applikation entworfene XSLT-Transformation ausführen.

Nachtrag am 4.7.2008:
Die Ausführung von nur dynamisch gegebenen XSLT-Transformationen in ABAP ist tatsächlich möglich mit der Klasse CL_XSLT_PROCESSOR, siehe das Beispielprogramm SDN-Thread https://forums.sdn.sap.com/thread.jspa?forumID=50&threadID=947687
Bei Pastebin findet sich dieses Beispielprogramm unter http://pastebin.com/Cj19qtJi

Keine Kommentare :