Dienstag, 17. Juli 2007

Eine selbstbezügliche XSLT-Transformation

Für das Web stellen XSL Stylesheets einen grossen Schritt auf dem Wege zu einer immer besseren Trennung von Präsentation und Inhalt dar. Services liefern Daten in Form von XML-Dokumenten, und mit einem passenden Stylesheet können diese Daten in XHTML transformiert und so für die Präsentation aufbereitet werden. Dieses Geschäft, XML-Daten mittels einer XSLT-Transformation in XHTML zu transformieren, können mittlerweile die Internet-Browser erledigen.

Wenn Daten und deren Aufmachung getrennt sind, sollte es auch möglich sein, dass das Stylesheet und die XML-Daten von zwei verschiedenen Quellen kommen, wie es das folgende Schema zeigt:




Hier trägt der für meinen Webauftritt zuständige Webserver das Stylesheet bei, also die XSLT-Transformation, die Datenquelle ist aber eine andere (etwa die URL eines Weblogs, das ich in meine Inhalte einbinden will).

So geht es aber nicht. XML und zugeordnetes XSL sind aus Sicht des Datenflusses nicht wirklich getrennt! Damit ein XML-Dokument in einem bestimmten Stil dargestellt wird, muss dieses XML-Dokument eben diese Stil-Information tragen, indem es eine <?xml-stylesheet...?> Verarbeitungsanweisung enthält. Das XML-Dokument vermischt also wieder Stil mit Inhalt. Es enthält nicht nur die Daten, sondern gibt auch noch genau eine Art und Weise an, wie diese Daten darzustellen sind. Zwar stellt das Stylesheet physisch eine andere Datei dar, und auch logisch kann man es so einrichten, dass der Dateninhalt im XML-, die Präsentierungsinformation dagegen im XSL-Stylesheet steht. Die Verknüpfung dieser beiden Einheiten erfolgt aber innerhalb des XML-Dokuments - wodurch sie eben doch wieder zusammengeführt werden!

Wenn ich das XML-Dokument auf eine andere Weise darstellen will, muss ich erst meinen Webserver in der Clientrolle auftreten lassen, das XML-Dokument mit einem HTTP-Request abholen und manipulieren: Der Server muss entweder die eigene XSLT-Transformation ausführen (ade clientside rendering), oder er muss das XML-Dokument vor dem Weitersenden an den Client bearbeiten: Statt der vom Autor vorgesehenen <?xml-stylesheet...?> Anweisung muss ich eine eigene <?xml-stylesheet...?> in das Dokument einbauen. Das so manipulierte XML-Dokument sendet dann mein Webserver an den Client. Das ist ineffizient und unschön:




Das folgende XML-Dokument wäre eine Möglichkeit, dieses Problem zu umgehen. Sie scheitert jedoch in der Praxis an der "Browser dürfen nur nach Haus' telefonieren"-Regel. Sie ist daher nur anwendbar, wenn XML-Dokumente vom eigenen Server dynamisch beschafft, aber ebenfalls auf dem eigenen Server mit unterschiedlichen Stylesheets aufbereitet werden sollen. Dennoch will ich die Lösung vorstellen, da sie eine etwas ungewöhnliche Art ist, XSL-Stylesheets einzusetzen.

Das folgende XML-Dokument heisst my_atom.xml. Wie man an der <?xml-stylesheet...?>-Anweisung erkennt, ist es somit sein eigenes Stylesheet: es wendet sich bei Aufruf im Browser auf sich selbst an. Das ist jedoch nur ein Trick, um den XSLT-Prozessor auf ein anderes XML-Dokument anzuwenden. Das Template zum Wurzelknoten enthält in Wirklichkeit ein Stylesheet, das für das Dokument
http://ruediger-plantiko.blogspot.com/feeds/posts/default gedacht ist. Dieses kann mit der XPath-Funktion document() innerhalb des Templates herangezogen werden. So liefert das Dokument my_atom.xml in Wirklichkeit eine Item-Liste meines Weblogs, wobei die Aufbereitung in my_atom.xml codiert ist.


<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="my_atom.xml"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:a='http://www.w3.org/2005/Atom'>
<xsl:template match="/">
<html>
<head>
</head>
<body>
<ul>
<xsl:for-each select="document('http://ruediger-plantiko.blogspot.com/feeds/posts/default')/a:feed/a:entry/a:title">
<li><xsl:value-of select="."/></li>
</xsl:for-each>
</ul>
</body>
</html>
</xsl:template>
</xsl:stylesheet>


Dieser Trick würde es erlauben, erst im Browser XML mit dem gewünschten XSL zusammenzuführen, statt des normalen Wegs, das gewünschte XML auf dem Server zu manipulieren. Würde - wenn es keine "Same Origin Policy" in Browsern gäbe. Die gibt es aber. Und daher werden wir weiter fummeln müssen: Mit einem kleinen Perlscript oder Servlet müssen wir auf dem Webserver das XML beschaffen und die eigene XSL-Stylesheet-Anweisung einspleissen.

Eine nette Alternative bietet übrigens Google mit seiner Google Feed API. Google stellt seine gewaltige Serverleistung zur Verfügung um für uns die XML-Services dieser Welt abzufragen und das Ergebnis an den Browser zu senden. Im Grunde umgeht Google jedoch nicht die Same Origin Policy, sondern nutzt nur die Tatsache aus, dass das <script src="..."> nicht dieser Policy unterliegt. So werden für jedes angeforderte XML-Feed dynamisch JavaScript <script>-Elemente in die im Browser angezeigte Webseite gesetzt. Diese Script-Elemente zeigen auf den Google-Server, der die Feeds dann in einer für JavaScript geeigneten Weise aufbereitet. Auch hier gibt es also viel zusätzliche Arbeit, den meisten Teil haben uns das GWT und die Google-Server jedoch bereits abgenommen.

Keine Kommentare :