Content-Syndication
In den letzten zwei Kapiteln habe ich versucht, Ihnen die Welt aus dem Blickwinkel der Web Services zu zeigen. Mit anderen Worten: Es ging darum, wie man Applikationen schreibt, die miteinander über die verschiedensten Web-Service-Technologien wie WSDL, UDDI und SOAP kommunizieren. Sie haben jedoch auch gesehen, daß einige Dinge in dieser Weltsicht noch auf wackligen Füßen stehen, zum Beispiel die Erzeugung und Unterstützung von WSDL (solange Sie offene Standards wie Apache benutzen). Heute möchten Sie eventuell über andere Standards für die Business-to-Business-Kommunikation nachdenken. In diesem Kapitel möchte ich Ihnen eine Alternative zur Kommunikation über Business-Grenzen hinweg vorstellen und damit Ihre Kenntnisse ein wenig abrunden.
In diesem Kapitel benutze ich andere XML-Spezifikationen, um diese Art der Kommunikation über Anwendungs- und Unternehmensgrenzen hinweg zu gewährleisten. Dazu habe ich extra einige Unternehmen erfunden. Zunächst werde ich die öffentliche Bibliothek »Foobar« vorstellen, die es Ihren Zulieferern erlaubt, zu liefernde Bücher online einzutragen. Diese Angaben werden dann zum Datenbestand der Bibliothek hinzugefügt. Unglücklicherweise verfügt die Bibliothek nicht über gute Java-Programmierer und hat daher eine Perl-basierte CGI-Lösung implementiert. Neue Bücher werden online eingegeben und dann mittels eines Perl-Skripts gespeichert. Sie können hier schon erkennen, daß in diesem Fall Alternativen zu Web Services nützlich wären, da eine gute Perl-SOAP-Implementierung schwer zu finden ist (wenigstens zur Zeit noch).
Ich werde noch eine andere Firma vorstellen – mytechbooks.com. mytechbooks.com verkauft technische Bücher und Computerbücher (wie das vorliegende) online über Partnerschaften mit großen Buchläden. Diese Firma hat kürzlich eine Vereinbarung mit der Bibliothek »Foobar« über den Ankauf von Büchern der Bibliothek geschlossen. mytechbooks.com wird für den Versand und die Lagerkosten aufkommen, und die Bibliothek verpflichtet sich im Gegenzug, zusätzliche Bücher mit Rabatt ein- und diese dann an mytechbooks.com weiterzuverkaufen. mytechbooks.com verkauft diese dann und muß auf die Einträge zu neuen Büchern der Bibliothek zugreifen können, um über neue Angebote informiert zu sein und sie entsprechend zu bewerben.
Jedoch wissen die Mitarbeiter bei mytechbooks.com nicht, wie sie auf das Perl-basierte System der Bibliothek zugreifen sollen. Dazu kommt noch, daß es zwischen den beiden Firmen keine abgeschirmten Netzwerkverbindungen gibt und deshalb normales HTTP zur Kommunikation benutzt werden muß. Und um uns ganz aus der Welt der Web Services herauszudrängen, möchte mytechbooks.com noch abwarten, bis Web Services ausgereifter sind und WSDL fester darin verankert ist und besteht auf einer stabileren Lösung (oder zumindest auf einer, die es schon länger gibt).
Schließlich werfen wir noch einen Blick auf die Kunden von mytechbooks.com. Die Zielgruppe sind Leute, die online aktiv sind, und mytechbooks.com möchte deshalb auf Websites wie Netscapes Netcenter Werbung betreiben. Weiterhin soll es den Kunden möglich sein, sich Informationen online holen zu können, wenn neue Angebote da sind. Jedoch haben die Mitarbeiter auch hier das gleiche Problem wie in der Bibliothek: Sie wissen nicht, wie sie dieses Ziel erreichen sollen. Beim Lesen von O’Reilly-Büchern und Artikeln unter http://www.oreillynet.com haben sie aber mitbekommen, wie der Spezifikations-Co-Autor von RSS, Rael Dornfest, darüber spricht, wie cool RSS ist, und möchten es ausprobieren. Natürlich hat Rael recht. RSS ist es, worüber ich in diesem Kapitel sprechen möchte.
Wir werden uns dieses Szenarios annehmen, indem wir mit der Bibliothek anfangen und ihr Perl-System analysieren. Danach betrachten wir mytechbooks.com und dessen Kunden, und ich werde Ihnen zeigen, wie mittels XML als Kommunikationswerkzeug zwischen jeder Schicht diese Business-to-Business-(-zu-Kunde)-Kommunikation zum Funktionieren gebracht wird.
Die Bibliothek »Foobar«
Um mit der Erstellung des Business-to-Business-Systems zu beginnen, zeige ich zunächst das momentan genutzte System in der Bibliothek »Foobar«. Bevor wir in den Code eintauchen können, ist es nötig, die Bedürfnisse der Bibliothek zu ermitteln, damit Sie nicht ein System erstellen, das gar nicht darauf eingeht.
Erfassen der Bedürfnisse
Allzuoft kommt es vor, daß gute Problemlösungen keine guten Lösungen für das Unternehmen mit dem Problem sind. Die Bibliothek ist ein typisches Beispiel dafür. Natürlich würde ein Java-Servlet, das mit anderen Servlets bei mytechbooks.com kommuniziert, die Probleme beider Unternehmen schnell lösen. Dies jedoch ignoriert die Bedürfnisse der Bibliothek. Vor dem Erstellen der Lösung hat diese ihre Bedürfnisse genau festgelegt:
- Die Lösung muß Perl-basiert sein, da keine Java-Entwickler zur Verfügung stehen.
- Die Lösung darf keine Neuinstallation von Software oder Bibliotheken nach sich ziehen.
- Die Lösung darf das bestehende Bestellsystem nicht beeinflussen (keine Änderungen am Interface).
Obwohl diese Bedürfnisse nicht sehr stringent sind, schließen sie doch eine Lösung aus, die auf Java-Servlets basiert. Sie müssen vermeiden, Java bei der Lösung einzusetzen. Da dies hier ein Buch über XML ist, könnten Sie aber darüber nachdenken, die Daten über neue Bücher in XML-Dokumenten abzulegen. Dieses XML kann man dann über HTTP-Requests den Clients zur Verfügung stellen. Die wiederum würden diese Daten dann benutzen können, wie es ihnen beliebt.
Das ist in der Tat eine viel bessere Lösung als die Kommunikation zwischen Servlets, da XML von jedem Unternehmen oder Client in eigenen Anwendungen benutzt werden kann, anstatt die Bibliothek (und ihre Bücher) an ein spezielles Unternehmen zu binden. Dies definiert dann auch das Ziel der Erneuerung des Systems der Bibliothek: Die eingegebenen Informationen sollen als XML-Daten gespeichert und dann Clients und Kunden über HTTP zur Verfügung gestellt werden.
Eingeben der Bücher
Wir müssen nun das bestehende HTML-Interface analysieren, das zur Eingabe von Informationen zu neuen Büchern in das System dient. Beispiel 14-1 zeigt das dazu benutzte statische HTML-Dokument.
<html> <head> <title>Foobar Public Library: Bücher hinzufügen</title> <style> <!-- body { font-family: Arial } h1 { color: #000080 } --> </style> </head> <body link="#FFFF00" vlink="#FFFF00" alink="#FFFF00"> <table border="0" width="100%" cellpadding="0" cellspacing="0"> <tr> <td width="15%" bgcolor="#000080" valign="top" align="center"> <b><i> <font color="#FFFFFF" size="4">Optionen</font> </i></b> <p><b> <font color="#FFFFFF"> <a href="/javaxml/foobar">Hauptmenü</a> </font> </p></b> <p><b> <font color="#FFFFFF"> <a href="/javaxml/foobar/catalog.html">Katalog</a> </font> </b></p> <p><b> <i><font color="#FFFF00">Bücher hinzufügen</font></i> </b></p> <p><b> <font color="#FFFFFF"> <a href="/javaxml/foobar/logout.html">Log Out</a> </font> </p></td> <td width="*" valign="top" align="center"> <h1 align="center">Die Bibliothek »Foobar«</h1> <h3 align="center"><i>- Bücher hinzufügen -</i></h3> <!-- Das muß auf Ihr CGI-Verzeichnis und Skript zeigen, welches wir uns als nächstes anschauen werden --> <form method="POST" action="/cgi/addBook.pl"> <table border="0" cellpadding="5" width="100%"> <tr> <td width="100%" valign="top" align="center" colspan="2"> Titel <input type="text" name="title" size="20"> <hr width="85%" /> </td> </tr> <tr> <td width="50%" valign="top" align="right">Autor <input type="text" name="author" size="20"> </td> <td width="50%" valign="top" align="left">Thema <select size="1" name="subject"> <option>Fiction</option> <option>Biographie</option> <option>Wissenschaft</option> <option>Industrie</option> <option>Computer</option> </select></td> </tr> <tr> <td width="50%" valign="top" align="right">Verlag <input type="text" name="publisher" size="20"> </td> <td width="50%" valign="top" align="left">ISBN <input type="text" name="isbn" size="20"> </td> </tr> <tr> <td width="50%" valign="top" align="right">Preis <input type="text" name="price" size="20"> </td> <td width="50%" valign="top" align="left">Seiten <input type="text" name="numPages" size="20"> </td> </tr> <tr> <td width="100%" valign="top" align="center" colspan="2"> Beschreibung <textarea rows="2" name="description" cols="20"></textarea> </td> </tr> </table> <p> <input type="submit" value="Buch hinzufügen" name="addBook"> <input type="reset" value="Formular zurücksetzen" name="reset"> <input type="button" value="Abbrechen" name="cancel"> </p> </form> </td> </tr> </table> </body> </html>
Diese als addBooks.html gespeicherte Datei erlaubt es Zulieferern, neue Bücher einzutragen, die sie an die Bibliothek schicken.
In Beispiel 14-1 und auch im Rest des Kapitels sind HTML-Listings und Sourcecode komplett abgedruckt, damit Sie die Beispielanwendungen erzeugen können. Außerdem sollten Sie damit in der Lage sein, den Einbau der XML-Kommunikation zwischen den Anwendungen Schritt für Schritt nachzuvollziehen. Die Code-Beispiele in diesem Kapitel verwenden die in diesem Kapitel benutzten Dateinamen. Wenn Sie eigene Dateinamen benutzen möchten, müssen Sie den Code und die Beispiele entsprechend ändern. Code, der wegen geänderter Dateinamen oder Skripte angepaßt werden muß, ist in den Listings hervorgehoben, um Ihnen die Suche zu erleichtern.
Das in Beispiel 14-1 gezeigte HTML-Dokument führt bei der Anzeige mit einem Web-Browser zu dem in Abbildung 14-1 gezeigten Ergebnis. Wir werden uns die verschiedenen Menüoptionen nicht näher anschauen – der Zulieferer kann mittels des Menüs links am Bildschirmrand den Katalog der Bibliothek einsehen, zum Hauptmenü der Anwendung springen und sich abmelden.
Dieses Formular erlaubt es dem Zulieferer, alle relevanten Daten zu einem Buch einzugeben, das er an die Bibliothek schicken möchte. Der Zulieferer gibt die entsprechenden Informationen (Titel, Autor, Herausgeber, Seitenanzahl und eine Beschreibung) wie auch das Thema des Buches zur Kategorisierung und einige Verkaufsdetails (Preis, ISBN) ein.
Ist das geschehen, werden die Informationen an ein Perl-CGI-Skript übergeben:
<form method="POST" action="/cgi/addBook.pl">
Dieses Skript muß dann die XML-Ausgabe erzeugen. Die einfachste Lösung wäre sicher, eine Perl-Bibliothek, wie zum Beispiel Perl-Xerces, herunterzuladen, die das Parsen des XML übernimmt. Eine der Anforderungen der Bibliothek war jedoch, keine zusätzliche Software oder Bibliothek hinzuzufügen. Das mag verrückt und komisch erscheinen, bedenken Sie aber bitte, daß viele Unternehmen sehr strikte Richtlinien und Einschränkungen im Hinblick auf ihre Produktionssysteme haben. In unserem Fall beginnt die Bibliothek erst damit, ihre Internetpräsenz aufzubauen, und hat keine Ressourcen zur Unterstützung zusätzlicher Software zur Verfügung.
Glücklicherweise muß der Code nur XML ausgeben, und das kann man einfach durch die Brute-force-Erzeugung einer Datei mit den Informationen zu den Büchern erreichen. Die Dinge wären sehr viel komplizierter, wenn neuer XML-Code noch geparst werden müßte. Da die Bibliothek alle schon vorhandenen Informationen behalten muß, werden neue Einträge einfach an die bestehende Datei angehängt, statt bei jedem Request neue Dateien zu erzeugen. Den entsprechenden Perl-Code zu schreiben ist trivial. Beispiel 14-2 zeigt das komplette Perl-Programm zum Lesen der Request-Parameter und zum Anhängen der neuen Information an eine existierende Datei.
#!/usr/local/bin/perl # Verzeichnis, in dem die neuen Dateien abgelegt werden sollen $baseDir = "/home/bmclaugh/javaxml/foobar/books/"; # Zu benutzender Dateiname $filename = "books.txt"; $bookFile = $baseDir . $filename; # Holen der Nutzereingaben use CGI; $query = new CGI; $title = $query->param('title'); $author = $query->param('author'); $subject = $query->param('subject'); $publisher = $query->param('publisher'); $isbn = $query->param('isbn'); $price = $query->param('price'); $numPages = $query->param('numPages'); $description = $query->param('description'); # Schreiben der Buchinformationen in eine XML-Datei if (open(FILE, ">>" . $bookFile)) { print FILE "<book subject=\"" . $subject . "\">\n"; print FILE " <title><![CDATA[" . $title . "]]></title>\n"; print FILE " <author><![CDATA[" . $author . "]]></author>\n"; print FILE " <publisher><![CDATA[" . $publisher . "]]></publisher>\n"; print FILE " <numPages>" . $numPages . "</numPages>\n"; print FILE " <saleDetails>\n"; print FILE " <isbn>" . $isbn . "</isbn>\n"; print FILE " <price>" . $price . "</price>\n"; print FILE " </saleDetails>\n"; print FILE " <description>"; print FILE "<![CDATA[" . $description . "]]>"; print FILE "</description>\n"; print FILE "</book>\n\n"; # Gib dem Benutzer eine Bestätigung print <<"EOF"; Content-type: text/html <html> <head> <title>Bibliothek »Foobar«: Bestätigung</title> </head> <body> <h1 align="center">Buch hinzugefügt</h1> <p align="center"> Danke. Die von Ihnen übergebenen Informationen wurden dem Datenbestand hinzugefügt. </p> </body> </html> EOF } else { print <<"EOF"; Content-type: text/html <html> <head> <title>Bibliothek »Foobar«: Fehler</title> </head> <body> <h1 align="center">Fehler beim Hinzufügen eines Buches</h1> <p align="center"> Tut uns leid. Die von Ihnen eingegebenen Informationen konnten <i>nicht</i> zum Datenbestand hinzugefügt werden. </p> </body> </html> EOF } close (FILE);
Dieses als addBook.pl gespeicherte Programm wird von dem gezeigten Formular aufgerufen, wenn ein Zulieferer ein Buch eingibt. Das Skript definiert die Ausgabedatei und weist die Request-Parameter logischen Variablen zu:
$title = $query->param('title'); $author = $query->param('author'); $subject = $query->param('subject'); $publisher = $query->param('publisher'); $isbn = $query->param('isbn'); $price = $query->param('price'); $numPages = $query->param('numPages'); $description = $query->param('description');
Nun, da leichter auf diese Werte zugegriffen werden kann, öffnet das Skript die weiter oben definierte Datei zum Anhängen (engl.: append; durch »>>« vor dem Dateinamen) und schreibt rohe, mittels XML formatierte Informationen über das Buch an das Ende der Datei:
print FILE "<book subject=\"" . $subject . "\">\n"; print FILE " <title><![CDATA[" . $title . "]]></title>\n"; print FILE " <author><![CDATA[" . $author . "]]></author>\n"; print FILE " <publisher><![CDATA[" . $publisher . "]]></publisher>\n"; print FILE " <numPages>" . $numPages . "</numPages>\n"; print FILE " <saleDetails>\n"; print FILE " <isbn>" . $isbn . "</isbn>\n"; print FILE " <price>" . $price . "</price>\n"; print FILE " </saleDetails>\n"; print FILE " <description>"; print FILE "<![CDATA[" . $description . "]]>"; print FILE "</description>\n"; print FILE "</book>\n\n";
Das subject (Thema, Kategorie) ist dem umgebenden Element book als Attribut zugeordnet, und der Rest der Informationen sind Elemente. Da der Titel, der Autor, die Beschreibung und der Herausgeber eines Buches Anführungszeichen, Hochkommas, Kaufmanns-Unds und andere zu quotende Zeichen enthalten können, werden diese Informationen durch eine CDATA-Sektion eingekapselt. So muß man sich darüber keine Gedanken mehr machen.
Weiterhin ist zu bemerken, daß hier keine XML-Deklaration und auch kein root-Element erzeugt wird, da mehrere Bücher zusammen in einem Dokument stehen. Es ist ein wenig schwierig herauszufinden, ob eine Datei existiert. Wenn nicht, müßten dann die Deklaration und das root-Element und am Ende das schließende Element geschrieben werden (das man auch noch bei jedem neuen Eintrag überschreiben müßte). Aus diesen Gründen stellt das Dokument einfach ein Fragment eines richtigen XML-Dokuments dar. Es folgt nun ein Beispiel für das Aussehen der Datei, nachdem zwei Bücher hinzugefügt wurden:
<book subject="Computer"> <title><![CDATA[Java Servlet Programmierung]]></title> <author><![CDATA[Jason Hunter]]></author> <publisher><![CDATA[O'Reilly & Associates]]></publisher> <numPages>753</numPages> <saleDetails> <isbn>0596000405</isbn> <price>79.95</price> </saleDetails> <description><![CDATA[Dieses Buch ist eine tolle Einführung in Servlets und ihre verschiedenen Kommunikationsmechanismen.]]></description> </book> <book subject="Fiction"> <title><![CDATA[Die zweite Foundation]]></title> <author><![CDATA[Isaac Asimov]]></author> <publisher><![CDATA[Bantam Books]]></publisher> <numPages>279</numPages> <saleDetails> <isbn>0553293362</isbn> <price>5.59</price> </saleDetails> <description><![CDATA[Nachdem die erste Foundation vom Mutanten vernichtet wurde, stand nur noch die zweite Foundation zwischen der Welt und der totalen Zerstörung, die der Mutant bringen würde.]]></description> </book>
Obwohl dieses Fragment kein komplettes XML-Dokument darstellt, ist es dennoch wohlgeformt und könnte in ein XML-Dokument, bei dem Header und root-Element definiert sind, eingesetzt werden. Ich werde, wenn ich im nächsten Abschnitt über eine Auflistung der Bücher spreche, die Ausgabe des Fragments genauso behandeln.
Der Rest des Skripts gibt HTML aus, das anzeigt, ob ein Buch erfolgreich hinzugefügt wurde oder ob Fehler auftraten. Sobald ein Buch erfolgreich als XML gespeichert wurde, erhält der Zulieferer die in Abbildung 14-2 dargestellte einfache Botschaft.
Nachdem wir nun über ein XML-Fragment verfügen, das die Informationen über neue Bücher enthält, müssen Sie es noch Interessierten zur Verfügung stellen.
Eine Liste der Bücher zur Verfügung stellen
Wir können auch hier Perl benutzen, um Clients und Kunden eine XML-Liste neuer Bücher zu bieten. Ich nehme hier einfach einmal an, daß ein anderer Teil der bestehenden Bibliotheksanwendung die Liste periodisch liest, die neuen Bücher zum Katalog hinzufügt und dabei gleichzeitig die entsprechenden Teile der Datei (oder auch die ganze Datei) löscht. Damit sind die Bücher nicht mehr länger Neueinträge. Wenn wir davon ausgehen, muß ein zweites Perl-Skript nur noch das Fragment lesen und die enthaltenen Daten in ein XML-Dokument übertragen, das dann am Bildschirm angezeigt wird.
Wie ich bereits sagte, muß das Perl-Skript außerdem ein root-Element und eine die Daten umschließende XML-Deklaration in die neue Datei aufnehmen. Dieses neue, in Beispiel 14-3 gezeigte Skript liest die vom Skript addBook.pl erzeugte Datei und gibt deren Inhalt innerhalb eines XML-Dokuments aus, wenn ein entsprechender HTTP-Request am Server eingeht.
#!/usr/local/bin/perl # Verzeichnis, in dem die neuen Dateien abgelegt werden sollen $baseDir = "/home/bmclaugh/javaxml/foobar/books/"; # Zu benutzender Dateiname $filename = "books.txt"; $bookFile = $baseDir . $filename; # Zuerst die Datei öffnen open(FILE, $bookFile) || die "Konnte Datei $bookFile nicht öffnen.\n"; # Damit der Browser weiß, was kommt print "Content-type: text/plain\n\n"; # Ausgabe des XML-Headers und root-Elements print "<?xml version=\"1.0\"?>\n"; print "<books>\n"; # Ausgabe der Bücher while (<FILE>) { print "$_"; } # Schließen des root-Elements print "</books>\n"; close(FILE);
Dieses als supplyBooks.pl gespeicherte Skript akzeptiert einen Request, liest die von addBook.pl erzeugte Datei und gibt über einen HTTP-Request XML aus. Wie das Resultat des Requests für dieses Skript in einem Webbrowser (mit einigen Büchern) aussieht, ist in Abbildung 14-3 zu sehen.
Wie Sie sehen, hat das die einfache, Perl-basierte Anwendung der Bibliothek zu einer Komponente gemacht, die ihren Clients (einschließlich unseres Buchhandels mytechbooks.com) nun sinnvolle Informationen zur Verfügung stellen kann. Außerdem haben wir das ohne die Installation neuer Software erreicht und auch ohne die Architektur des Systems zu ändern und ohne eine Zeile Java-Code zu schreiben!
mytechbooks.com
Da nun die Bibliothek »Foobar« den Zugriff auf eine XML-Liste ihrer neuen Bücher gestattet, ist auch mytechbooks.com dem Ziel, den Kunden aktuelle Informationen zu liefern, einen Schritt nähergekommen. Zusätzlich hat mytechbooks.com bereits die Benutzung von Java zur Entwicklung von Anwendungen zum Standard erklärt. Das macht den Prozeß des Zugriffs und der Benutzung der XML-Daten der Bibliothek noch einfacher, da Java die exzellente Unterstützung für XML bietet, die wir uns schon während des gesamten Buches angeschaut haben. Sie müssen der Firma mytechbooks.com zunächst die Möglichkeit geben, online eine Liste neuer Bücher zur Verfügung zu stellen, und anschließend überlegen, wie Sie diese Informationen automatisch zu den Kunden bringen.
Filtern der XML-Daten
Wie Sie sich erinnern, erlaubte es die Bibliothek »Foobar«, Bücher zu verschiedenen Themen in das System einzugeben. mytechbooks.com jedoch ist nur an Büchern über Computer interessiert. Glücklicherweise bietet die Bibliothek diese Information im Attribut subject des Elements book für jedes Buch in den XML-Daten. Die erste Aufgabe besteht also im Ausfiltern jener Bücher, die sich nicht um das Thema »Computer« drehen. Sind die technischen Bücher heraussortiert, sollen Sie den Kunden von mytechbooks.com als HTML-Seite präsentiert werden.
Für dieses Unternehmen und diese Anwendung gibt es kein statisches HTML, da die Seite zur Anzeige der Listen neuer Bücher jedesmal neu generiert werden muß, wenn darauf zugegriffen wird. Ich werde hier ein Servlet benutzen, um dem gerecht zu werden. Apache Cocoon wäre zwar eine gute Wahl zur Konvertierung von XML nach HTML, mytechbooks.com steht aber unter hohem Zeitdruck, diese Bücherlisten zu veröffentlichen, der es nicht erlaubt, eine solch große Änderung im System vorzunehmen, wie es die Einführung von Cocoon wäre. Statt dessen sollen XML-Parser und Prozessoren benutzt und Cocoon erst in einer späteren Phase eingesetzt werden. Das bedeutet, daß Sie sich um das Parsen und Filtern der XML-Daten, die Wandlung in HTML und das Hinzufügen präsentationsspezifischer Teile, wie Logos oder Menüs, kümmern müssen.
Wenn Sie alle Ihnen zur Verfügung stehenden Informationen über XML und XSL überdenken, werden Sie feststellen, daß Sie XSL zur Umwandlung eines XML-Dokuments nach HTML auch ohne Cocoon benutzen können. Die Anwendung einer Transformation würde es auch erlauben, die Bücher auszufiltern, die Themen behandeln, die mytechbooks.com nicht wünscht. Mit diesem Wissen ist es leicht, ein XSL-Stylesheet zu basteln, das dann auf das Dokument von der Bibliothek angewendet wird. Beispiel 14-4 zeigt den Beginn des Stylesheets, das die Erzeugung von HTML passend zum Style der Website von mytechbooks.com erledigt.
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" > <xsl:template match="books"> <html> <head> <title>mytechbooks.com - Ihr Computer-Buchhändler</title> </head> <body background="/javaxml/techbooks/images/background.gif" link="#FFFFFF" vlink="#FFFFFF" alink="#FFFFFF"> <h1 align="center"> <font face="Arial" color="#00659C"> <mytechbooks.com> </font> </h1> <p align="center"> <i><b> Ihre Quelle für Computerliteratur und technische Bücher im WEB. </b></i> </p> <p align="center"> <b><font size="4" color="#00659C"> <u>Neuigkeiten</u> </font></b> </p> <table border="0" cellpadding="5" cellspacing="5"> <tr> <td valign="top" align="center" nowrap="nowrap" width="115"> <p align="center"> <font color="#FFFFFF"><b> <a href="/javaxml/techbooks/">Home</a> </b></font> </p> <p align="center"> <font color="#FFFFFF"><b> <a href="/javaxml/techbooks/current.html">Aktuelle Liste</a> </b></font> </p> <p align="center"> <b><font color="#FFFFFF"> <i>Neuzugänge</i> </font></b> </p> <p align="center"> <font color="#FFFFFF"><b> <a href="/javaxml/techbooks/contact.html">Contact Us</a> </b></font> </p> </td> <td valign="top" align="left"> <table border="0" cellpadding="5" cellspacing="5"> <tr> <td width="450" align="left" valign="top"> <p> <b> Willkommen bei <font face="courier">mytechbooks.com</font>, Ihrer Quelle für Computerliteratur und technische Bücher im WEB. Unsere neuesten Angebote sind links aufgelistet. Um eines dieser wunderbaren Bücher zu kaufen, klicken Sie bitte den Link "Dieses Buch kaufen!" an. Das bringt Sie zum Warenkorb. Viel Spaß! </b> </p> <p> <b> Sie können natürlich auch die aktuelle Liste ansehen, sich über uns informieren und uns Fragen stellen. Benutzen Sie dafür die Links im Menü links. Danke für Ihren Einkauf! </b> </p> </td> <td align="left"> <!-- Erzeugung des Inhalts für jedes neue »Computer«-Buch --> </td> </tr> </table> </td> </tr> </table> </body> </html> </xsl:template> </xsl:stylesheet>
Das filtert zwar die eingehenden Daten noch nicht, stellt aber bereits das Nutzer-Interface dar. Es ist oft einfacher, sich zuerst um diese präsentationsspezifischen Details zu kümmern und die transformationsspezifische Logik später hinzuzufügen.
Wenn Sie XSL-Stylesheets, speziell solche für Web-Anwendungen, entwickeln, sollten Sie die Resultate zunächst mit der Kommandozeilenversion Ihres XSLT-Prozessors testen. Das hilft Ihnen sicherzustellen, daß das Stylesheet Ihr Dokument in jeder Phase der Entwicklung korrekt transformiert. Die Fehler in einem großen Stylesheet zu finden, wenn es komplett ist, ist sehr viel schwieriger. Für dieses Beispiel könnten Sie das Skript supplyBooks.pl mittels eines Webbrowsers anzeigen und das Ergebnis in eine Textdatei speichern und dieses und das Stylesheet dann den Beispielen folgend testen.
Ähnlich wie die Anwendung für die Bibliothek »Foobar« ergibt auch dieses Stylesheet im Browser ein Menü mit Hyperlinks zu anderen Teilen der Anwendung auf der linken Seite. Es enthält einige Informationen über das Unternehmen und seine Angebote und läßt rechts noch eine Spalte für neue Bücherangebote.
Bevor der Inhalt der Liste gefiltert wird, müssen Sie noch ein Template zur Ausgabe des HTML-Inhalts für ein einzelnes Buch angeben. Wie Sie sich erinnern werden, sieht ein Eintrag für ein Buch wie folgt aus:
<book subject="Computer"> <title><![CDATA[Running Linux]]></title> <author><![CDATA[Matt Welsh]]></author> <publisher><![CDATA[O'Reilly & Associates]]></publisher> <numPages>729</numPages> <saleDetails> <isbn> 156592469X</isbn> <price>39.95</price> </saleDetails> <description><![CDATA[In guter O'Reilly-Tradition enthält Running Linux verständliche Schritt-für-Schritt-Anweisungen, die immer gerade die richtige Menge an Informationen bieten.]]></description> </book>
Dies können Sie dann mittels des folgenden XSL-Templates in HTML umwandeln:
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" > <xsl:template match="books"> <!-- Präsentation des User-Interfaces --> </xsl:template> <xsl:template match="book"> <table border="0" cellspacing="1" bgcolor="#000000"> <tr> <td> <table border="0" cellpadding="3" cellspacing="0"> <tr> <td width="100%" bgcolor="#00659C" nowrap="nowrap" align="center"> <b><font color="#FFFFFF"> <xsl:value-of select="title" /> </font></b> </td> </tr> <tr> <td width="100%" align="center" nowrap="nowrap" bgcolor="#FFFFFF"> <font color="#000000"><b> Autor: <xsl:value-of select="author" /><br /> Herausgeber: <xsl:value-of select="publisher" /><br /> Seiten: <xsl:value-of select="numPages" /><br /> Preis: <xsl:value-of select="saleDetails/price" /><br /> <br /> </b></font> <xsl:element name="a"> <xsl:attribute name="href">/servlets/BuyBookServlet?isbn= <xsl:value-of select="saleDetails/isbn" /> </xsl:attribute> <font color="#00659C">Das Buch kaufen!</font> </xsl:element> </td> </tr> </table> </td> </tr> </table> <br /> </xsl:template> </xsl:stylesheet>
Dieses Template paßt auf ein Element book und generiert eine Tabelle mit einer Zeile als Kopf und den Angaben zum Buch in einer zweiten Zeile. Diese Tabelle sitzt ihrerseits wiederum in einer zweiten Tabelle mit schwarzem Hintergrund. Das Ganze macht dann den Eindruck eines hervorgehobenen schwarzen Rahmens. Der Titel wird in den Kopf der Tabelle eingefügt, und die Informationen über das Buch (Autor, Herausgeber, Seitenanzahl und Preis) stellen den Körper der Tabelle dar. Schließlich wird noch ein Link zu einem Servlet BuyBookServlet eingefügt, über den ein einfacher Kaufauftrag für dieses Buch erteilt werden kann. Der Wert des Elements isbn wird als Argument für dieses Servlet benutzt, um einfach das zu kaufende Buch zu kennzeichnen.
Sie sollten in Ihrem XSL-Stylesheet sicherstellen, daß die Anweisung, das Servlet BuyBookServlet zu benutzen, und das Element xsl:value-of, das die ISBN des Buches selektiert, auf einer Zeile stehen. Ist dem nicht so, könnten Leerzeichen oder Zeilenvorschübe in die resultierende URL eingefügt und damit falsche Informationen an das Servlet übergeben werden. Das Beispiel zeigt diese Informationen nur wegen des Formats des gedruckten Buches auf verschiedenen Zeilen.
Die letzte Änderung, die Sie am Stylesheet vornehmen müssen, ist sicherzustellen, daß das Template auch benutzt wird und nur Einträge mit dem Thema »Computer« an dieses Template übergeben werden. Sie können über das Symbol @ in Ihrem Stylesheet auf den Wert des Elements subject verweisen und die Requests mittels des Attributs select des Elements xsl:apply-templates filtern:
</td> <td align="left"> <!-- Erzeugung des Inhalts für jedes neue Buch zum Thema Computer --> <xsl:apply-templates select="book[@subject='Computer']" /> </td> </tr> </table>
Das greift auf den Wert des Attributs zu und vergleicht es mit einem angegebenen String in Hochkommata, da der gesamte XPath-Ausdruck in Anführungszeichen eingeschlossen ist. Da hier ein Attribut eines eingebetteten Elements benutzt wird, müssen Sie mittels des Namens auf das Element zugreifen und den auf das Attribut des Elements bezogenen Ausdruck in Klammern einschließen. Das stellt sicher, daß die Templates nur auf Bücher zum Thema »Computer« angewendet werden und daß auch nur solche Bücher im HTML-Ergebnis auftauchen. Wenn das Stylesheet fertig ist, kann es unter computerBooks.xsl gespeichert und vom Java-Servlet angesprochen werden. Im nächsten Abschnitt werde ich zeigen, wie es geschrieben wird.
XSLT von einem Servlet aus
Wenn Ihr Stylesheet erstellt ist, müssen Sie noch ein wenig Java-Code schreiben, um es auf die von der Bibliothek »Foobar« gelieferten Daten anwenden zu können. Mittels der Klasse java.net.URL können Sie einfach auf diese Daten zugreifen, indem ein HTTP-Request an das System der Bibliothek gestellt wird. Ist all dies getan, bleibt nur noch die Anwendung der XSL-Transformation aus dem Programm heraus. Beispiel 14-5 zeigt den Code eines Java-Servlets, der die Daten von der Bibliothek holt, und zeigt, wo der Code für die Transformation eingesetzt werden müßte:
package com.techbooks; import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; import java.io.PrintWriter; import java.net.URL; import javax.servlet.*; import javax.servlet.http.*; public class ListBooksServlet extends HttpServlet { /** Host, der die Bücherliste liefern soll */ private static final String hostname = "newInstance.com"; /** Portnummer zum Holen der Bücherliste */ private static final int portNumber = 80; /** Datei (URI-Pfad) zum Zugriff auf die Bücherliste */ private static final String file = "/cgi/supplyBooks.pl"; /** Anzuwendendes Stylesheet */ private static final String stylesheet = "/home/bmclaugh/javaxml/techbooks/XSL/computerBooks.xsl"; public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); // Verbindung herstellen und Bücherliste holen URL getBooksURL = new URL("http", hostname, portNumber, file); InputStream in = getBooksURL.openStream(); // Transformieren des XML aus InputStream in HTML } }
Dieses einfache Servlet greift mittels eines HTTP-Requests auf die Anwendung der Bibliothek zu und bekommt die XML-Antwort in Form eines InputStreams.1 Dieser Stream dient ebenso wie das im Servlet als Konstante definierte Stylesheet als Argument für den XSLT-Prozessor.
Es existiert zur Zeit keine Java-API, die definiert, wie XSLT-Transformationen aus Programmen heraus auszuführen sind. Trotzdem sollte jeder Hersteller eines Prozessors Klassen zur Verfügung stellen, die es gestatten, eine Transformation aus Java-Code heraus zu starten. Ich werde mich hier weiterhin auf den Apache Xalan-Prozessor konzentrieren; Sie sollten in der Dokumentation Ihres Prozessors nachlesen, welche Methode oder Methoden Sie in Ihren Programmen aufrufen müssen.
Unter Apache Xalan ist die Klasse XSLTProcessor in dem org.apache.xalan.xslt-Package für die Transformation verantwortlich. Sie erwartet eine XSLTInputSource, die die zu bearbeitende XML-Datei einkapselt, eine XSLTInputSource, die das zu benutzende XSL-Stylesheet einkapselt, und ein XSLTResultTarget, das das Resultat der Transformation als Parameter entgegennimmt. Alle drei erwähnten Hilfsklassen befinden sich ebenfalls in dem Package org.apache.xalan.xslt.
Sie können bequemerweise durch Angabe eines InputStream (für XSLTInputSource) oder eines OutputStream (für XSLTResultTarget) erzeugt werden. Sie haben das XML-Dokument bereits als InputStream und können das XSL-Stylesheet in einen FileInputStream kapseln. Das Servlet-API schließlich bietet mittels der Methode getOutputStream() einfachen Zugriff auf das ServletOutputStream-Objekt an der Instanz der Klasse HttpServletResponse.
Zuletzt muß noch festgelegt werden, wie man Zugriff auf eine Instanz der Klasse XSLTProcessor erlangt. Da es verschiedene Mechanismen gibt, die für die Transformierung benutzt werden können, wird diese Klasse nicht direkt, sondern durch Benutzung der Klasse XSLTProcessorFactory, die ebenfalls im Package org.apache. xalan.xslt zu finden ist, instantiiert. Sie sollten inzwischen mit Factory-Klassen vertraut sein, und so müssen lediglich die entsprechenden Import-Anweisungen und der Aufruf der entsprechenden Methoden zur Verarbeitung zum Servlet hinzugefügt werden:
package com.techbooks; import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; import java.io.PrintWriter; import java.net.URL; import javax.servlet.*; import javax.servlet.http.*; // Import der Komponenten des Xalan XSLT-Prozessors import org.apache.xalan.xslt.XSLTInputSource; import org.apache.xalan.xslt.XSLTProcessor; import org.apache.xalan.xslt.XSLTProcessorFactory; import org.apache.xalan.xslt.XSLTResultTarget; public class ListBooksServlet extends HttpServlet { /** Host für die Bücherlisten */ private static final String hostname = "newInstance.com"; /** Portnummer zum Zugriff auf die Bücherlisten */ private static final int portNumber = 80; /** Datei (URI-Pfad) zum Zugriff auf die Bücherlisten */ private static final String file = "/cgi/supplyBooks.pl"; /** anzuwendendes Stylesheet */ private static final String stylesheet = "/home/bmclaugh/javaxml/techbooks/XSL/computerBooks.xsl"; public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); // Holen der XML-Bücherliste URL getBooksURL = new URL("http", hostname, portNumber, file); InputStream in = getBooksURL.openStream(); // Transformieren des XML-InputStreams in die HTML-Ausgabe try { XSLTProcessor processor = XSLTProcessorFactory.getProcessor(); // Transformieren des XML-Codes durch ein XSL-Stylesheet processor.process(new XSLTInputSource(in), new XSLTInputSource( new FileInputStream(stylesheet)), new XSLTResultTarget( res.getOutputStream())); } catch (Exception e) { PrintWriter out = res.getWriter(); out.println("Fehler: " + e.getMessage()); out.close(); } } }
Ich könnte auch die TrAX-API aus JAXP Version 1.1 zur Durchführung der Transformation benutzen. JAXP 1.1 ist zu dem Zeitpunkt, da ich dies schreibe, noch ziemlich neu, und ich kenne nur wenige Menschen, die es (bisher) benutzen. Außerdem werden die meisten Servlet-Engines (auch Tomcat) mit JAXP 1.0 ausgeliefert. Viele verlassen sich auf diese Tatsache, anstatt eine neuere Version von JAXP anzubieten.
Wenn dieses Servlet angefordert wird, holt es seinerseits die Liste von der Bibliothek »Foobar«. Diese Daten (eine Liste neu verfügbarer Bücher) wird dann transformiert und als HTML am Bildschirm dargestellt. Die Antwort des Servlets sollte ähnlich aussehen, wie in Abbildung 14-4 dargestellt.
Zusammen mit den Menü-Links am linken Rand (in diesem Beispiel nicht implementiert) werden die neuesten Bücher hübsch formatiert und mit aktuellen Informationen (dank der Bibliothek »Foobar«) sowie mit einem Link zum Auslösen des Kaufauftrags mittels weniger Mausklicks dargestellt. Nun können sich Kunden von mytechbooks.com einfach online über neue Bücher informieren. Alles, was jetzt noch zu tun bleibt, ist, diese Information automatisch zu den Kunden zu bringen, damit diese nicht ständig die URL eingeben müssen. Ich werde mich als nächstes mit der Lösung dieses Problems befassen.
Push versus Pull
Bisher habe ich die Erzeugung von Anwendungen immer unter dem Apekt betrachtet, daß sich Clients aktiv Daten und Inhalte holen (»pullen«). Mit anderen Worten: Ein Nutzer muß eine URL in den Browser eingeben (im Fall der Bücherlisten von mytechbooks.com), oder eine Anwendung wie das Servlet von mytechbooks.com mußte einen HTTP-Request nach XML-Daten stellen (im Fall der Bibliothek »Foobar«). Das ist zwar nicht wirklich ein Problem, es ist jedoch nicht immer die beste Methode für Unternehmen wie mytechbooks.com, die ja Bücher verkaufen wollen. Kunden, die Bücher kaufen möchten, müssen sich daran erinnern, wieder einmal auf der Site vorbeizuschauen und tun das manchmal tage-, wochen- oder gar monatelang nicht. Auch wenn diese Kunden große Mengen kaufen, wenn sie sich einmal daran erinnern, ergeben diese sporadischen Einkäufe größerer Mengen nicht so viel Umsatz, wie es oft getätigte Einkäufe kleinerer Posten tun würden.
mytechbooks.com hat den aktuellen Trend erkannt und möchte die Möglichkeit wahrnehmen, Daten aktiv an seine Kunden zu senden (zu »pushen«). Dazu gehört es, den Kunden (ohne daß er etwas dazu tun müßte) wissen zu lassen, daß neue Waren verfügbar oder neue Angebote geschaltet sind. Das ermöglicht es dem Kunden, häufiger einzukaufen, ohne sich an eine URL erinnern oder eine Website besuchen zu müssen. Jedoch ist das Senden von Informationen in einer Web-Infrastruktur schwierig, da sich Webbrowser nicht wie vollwertige Clients verhalten: Es ist schwieriger, Pop-up-Botschaften zu verschicken oder Signale an die Nutzer zu generieren. mytechbooks.com hat aber von der Popularität von personalisierten »Start-Pages« wie Netscapes My Netscape oder Yahoos My Yahoo pages gehört. In Gesprächen mit Netscape hat mytechbooks.com von einer neuen Technologie namens Rich Site Summary (RSS) gehört und denkt, daß das eine Lösung des Problems sein könnte.
Rich Site Summary
Rich Site Summary (RSS) ist eine spezielle Ausprägung von XML. Es hat eine eigene DTD und definiert einen sogenannten channel (engl. Kanal). Ein Channel ist eine Möglichkeit, um Daten über ein spezifisches Thema zu repräsentieren. Es ist damit unter anderem möglich, für einen solchen Channel Titel und Beschreibung wie auch ein Bild oder Logo und dann verschiedene sogenannte Items innerhalb des Channels zu definieren. Jedes Item wiederum stellt irgend etwas Besonderes für diesen Channel dar, was auch ein spezielles Produkt oder ein spezieller Service sein kann. Da die erlaubten Elemente eines Items ziemlich allgemein gehalten sind (title, description, hyperlink), kann eigentlich alles durch ein Item in einem Channel dargestellt werden.
Ein RSS-Channel ist nicht dafür gedacht, den kompletten Inhalt einer Site zu enthalten. Statt dessen repräsentiert er eine kurze Zusammenfassung von Informationen über ein Unternehmen oder einen Dienst, die zum Beispiel in einem portal-ähnlichen Framework oder als Sidebar einer Website angezeigt werden können. In der Tat sind alle »Widgets« in Netscapes Netcenter RSS-Channels. Netscape erlaubt auch die Erzeugung neuer Channels, die dann beim Netcenter registriert werden können. Netscape verfügt außerdem über eine eingebaute Unterstützung der Anzeige von RSS-Cannels im HTML-Format, was natürlich gut zu den Netcenter-Seiten paßt.
An diesem Punkt könnten Sie sich sorgenvoll fragen, ob RSS für Netscape dasselbe ist wie Microsofts XML-Parser für Microsoft: nämlich schwierig mit anderen Werkzeugen verschiedener Hersteller zu integrieren. Obwohl RSS ursprünglich von Netscape speziell für Netcenter entwickelt wurde, erlaubt es seine XML-basierte Struktur dennoch, es in jeder Anwendung einzusetzen, die DTDs lesen kann. Tatsächlich beginnen viele Portal-ähnliche Sites und Anwendungen, RSS zu benutzen – so zum Beispiel auch das Apache Jetspeed-Projekt (http://jakarta.apache.org/jetspeed), ein Open-Source-Enterprise-Information-Portal-System. Jetspeed benutzt dasselbe RSS-Format wie auch Netscape und stellt es in völlig anderer Form dar. Wegen der sehr präzisen Grammatik von RSS ist das kein Problem.
Da viele Benutzer Startseiten, Homepages oder ähnliche Plätze im WEB haben, die sie oft besuchen, möchte mytechbooks.com einen RSS-Channel bauen. Dieser Channel soll eine Liste neuer Bücher zeigen und die Gelegenheit bieten, schnell zum Kauf von Waren zu springen, die interessant sind. Das stellt ein effektives Mittel zum Pushen von Daten dar, da Produkte wie Netcenter RSS-Channels automatisch so oft aktualisieren, wie es der Nutzer möchte.
Erzeugen eines XML-RSS-Dokuments
Um RSS zu benutzen, müssen Sie zunächst eine RSS-Datei anlegen. Das ist fast zu einfach, um wahr zu sein: Außer dem Verweis auf die korrekte DTD und dem Befolgen der DTD gibt es nichts Kompliziertes an einem RSS-Dokument. Beispiel 14-6 zeigt eine Beispiel-RSS-Datei, die mytechbooks.com erstellt hat.
<?xml version="1.0" encoding="ISO-8859-1"?> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" > <channel> <title>mytechbooks.com Liste von Neuigkeiten</title> <link>http://www.newInstance.com/javaxml2/techbooks</link> <description> Ihre Online-Quelle für technische Materialien, Computer, und Computerliteratur! </description> <image rdf:resource="http://newInstance.com/javaxml2/logo.gif" /> <items> <rdf:Seq> <rdf:li resource="http://www.newInstance.com/javaxml2/techbooks" /> </rdf:Seq> </items> </channel> <image rdf:about="http://newInstance.com/javaxml2/logo.gif"> <title>mytechbooks.com</title> <url>http://newInstance.com/javaxml2/logo.gif</url> <link>http://newInstance.com/javaxml2/techbooks</link> </image> <item rdf:about="http://www.newInstance.com/javaxml2/techbooks"> <title>Java Servlet Programmierung</title> <link> http://newInstance.com/javaxml2/techbooks/buy.xsp?isbn=156592391X </link> <description> Dieses Buch ist eine tolle Einführung in die Servlet-Programmierung und deren verschiedene Kommunikationsmechanismen. </description> </item> </rdf:RDF>
Das root-Element muß RDF im RDF-Namensraum sein, wie es das Beispiel zeigt. Innerhalb des root-Elements muß ein einziges Element channel auftauchen. Dieses hat Elemente, die den Channel beschreiben (title, link und description), ein optionales Bild, das dem Channel zugeordnet werden kann (wie auch Informationen über dieses Bild) und bis zu 15 item-Elemente,2 von denen jedes ein dem Channel zugeordnetes Item näher beschreibt.
Jedes Item hat Elemente vom Typ title, link und description (Titel, Verknüpfung und Beschreibung), die selbsterklärend sein dürften. Eine optionale Textbox und eine Schaltfläche zum Übermitteln von Informationen über das Buch können ebenfalls hinzugefügt werden – das Beispiel macht davon jedoch keinen Gebrauch. Die RSS 1.0-Spezifikation unter http://groups.yahoo.com/group/rss-dev/files/specification.html gibt einen vollständigen Überblick über die erlaubten Elemente und Attribute.
Wie die Dokumente in den vorhergehenden Beispielen sollten auch RSS-Channel-Dokumente es vermeiden, Whitespaces in den link- und url-Elementen zu enthalten. Es ist besser, die jeweilige Information in einer einzigen Zeile zusammenzufassen. Auch hier spiegelt dies die Formatierung aus Platzgründen nicht wider.
Es gibt dennoch eine Schwierigkeit, die beachtet werden sollte. Sie werden bemerken, daß das Element (oder die Elemente) item nicht im Element channel eingebettet ist (bzw. sind). Um eine Verbindung zwischen einem Channel und zugehörigen Items herzustellen, müssen Sie ein RDF-Konstrukt (das Resource Description Framework, von dem RSS abstammt) benutzen:
<items>
<rdf:Seq>
<rdf:li resource="http://www.newInstance.com/javaxml/techbooks" />
</rdf:Seq>
</items>
Das Element items ist hier in das Element channel eingebettet. Dann wird dem Konstrukt li aus dem RDF-Namensraum mittels des Attributs resource eine URI zugeordnet. In jedem Item, das Sie diesem Channel zuordnen möchten, müssen Sie das Attribut about (wieder im RDF-Namensraum) angeben und ihm die gleiche URI zuweisen, die Sie im Ressource-Deskriptor des Channels benutzt haben:
<item rdf:about="http://www.newInstance.com/javaxml/techbooks"> <!-- Item Inhalt --> </item>
Für jedes Item mit dieser URI kann eine Zuordnung zwischen diesem Item und dem Channel mit derselben URI angelegt werden. Mit anderen Worten: Sie haben gerade eine Verknüpfung zwischen dem Channel im RSS-Dokument und den Items angelegt. Derselbe Ansatz wird zur Zuordnung eines image-Elements zu einem channel-Element benutzt. Hier wird die URL des Bildes als Wert des Attributs rdf:resource verwendet. Sie sollten dann ein Element image, aber nicht innerhalb des Elements channel, definieren und eine URL, eine Beschreibung und eine Verknüpfung angeben. Schließlich benutzen Sie das Attribut rdf:about (wie im Element item), um die gleiche URL anzugeben wie im Element image des Channels.
Haben Sie das alles getan? Das unterscheidet sich deutlich von RSS 0.9 und RSS 0.91 (die in der ersten Auflage dieses Buches behandelt wurden), daher sollten Sie darauf achten, daß Sie nicht Teile aus der alten mit Teilen der neueren Spezifikation vermischen.
Es ist einfach, RSS-Dokumente aus Programmen heraus zu erzeugen. Die Prozedur ähnelt der, die benutzt wurde, um das HTML für die Website von mytechbooks.com zu erzeugen. Die Hälfte der RSS-Datei (die Information über den Channel und das Bild) ist statisch. Nur die item-Elemente müssen dynamisch erzeugt werden. Aber gerade, als Sie soweit waren, vi zu starten und ein weiteres XSL-Stylesheet anzulegen, wird Ihnen eine weitere Anforderung mitgeteilt: Der Rechner, der den RSS-Channel beherbergen soll, ist ein anderer Server als der, den wir für unser letztes Beispiel benutzt haben, und auf ihm sind sehr veraltete Versionen der Apache Xalan-Bibliotheken installiert.
Wegen einiger Hochverfügbarkeitsanwendungen, die auf dieser Maschine laufen, wie zum Beispiel einem Billing-System, hat es mytechbooks.com untersagt, diese Bibliotheken zu aktualisieren, solange kein Change-Control durchgeführt wurde – ein wochenlanger Prozeß. Glücklicherweise hat mytechbooks.com aber aktuelle Versionen der Xerces-Bibliotheken verfügbar (da ein XML-Parsing im Billing-System benutzt wird), und daher sind Java-APIs zum Arbeiten mit XML verfügbar.3 In diesem Beispiel benutze ich JDOM, um das XML von der Bibliothek »Foobar« in das RSS-Channel-Format zu konvertieren. Beispiel 14-7 zeigt genau das.
package com.techbooks; import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; import java.io.PrintWriter; import java.net.URL; import java.util.Iterator; import java.util.List; import javax.servlet.*; import javax.servlet.http.*; // JDOM import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; public class GetRSSChannelServlet extends HttpServlet { /** Host für die Bücherlisten */ private static final String hostname = "newInstance.com"; /** Portnummer der Bücherlisten */ private static final int portNumber = 80; /** Datei (URI-Pfad) für Zugriff auf die Bücherlisten*/ private static final String file = "/cgi/supplyBooks.pl"; public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); // Verbindung herstellen und XML-Bücherlisten holen URL getBooksURL = new URL("http", hostname, portNumber, file); InputStream in = getBooksURL.openStream(); try { // Anfordern von SAX-Implementierung und Default-Parser SAXBuilder builder = new SAXBuilder(); // Erzeugen des Dokuments Document doc = builder.build(in); // Ausgabe von XML out.println(generateRSSContent(doc)); } catch (JDOMException e) { out.println("Fehler: " + e.getMessage()); } finally { out.close(); } } /** * <p> * Das erzeugt ein RSS-Dokument unter Benutzung des * JDOM-<code>Document</code>. * </p. * * @param doc – das als Eingabe zu benutzende <code>Document</code>. * @return <code>String</code> - RSS-Ausgabedatei. * @throws <code>JDOMException</code> wenn Fehler auftauchen. */ private String generateRSSContent(Document doc) throws JDOMException { StringBuffer rss = new StringBuffer(); rss.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") .append("<rdf:RDF ") .append("xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n") .append(" xmlns=\"http://purl.org/rss/1.0/\"\n") .append(">\n") .append(" <channel>\n") .append(" <title>mytechbooks.com Neuerscheinungen</title>\n") .append(" <link>http://www.newInstance.com/javaxml2/techbooks") .append("</link>\n") .append(" <description>\n") .append(" Ihre Online-Quelle für technisches Material, Computer, \n") .append(" und Computerliteratur!\n") .append(" </description>\n\n") .append(" <image ") .append("rdf:resource=\"http://newInstance.com/javaxml2/logo.gif\"") .append(" />\n\n") .append(" <items>\n") .append(" <rdf:Seq>\n") .append(" <rdf:li ") .append("resource=\"http://www.newInstance.com/javaxml2/techbooks\"") .append(" />\n") .append(" </rdf:Seq>\n") .append(" </items>\n") .append(" </channel>\n\n") .append(" <image ") .append("rdf:about=\"http://newInstance.com/javaxml2/logo.gif\">\n") .append(" <title>mytechbooks.com</title>\n") .append(" <url>http://newInstance.com/javaxml2/logo.gif</url>\n") .append(" <link>http://newInstance.com/javaxml2/techbooks</link>\n") .append(" </image>\n\n"); // Hinzufügen eines Items für jeden neuen Titel zum Thema Computer List books = doc.getRootElement().getChildren("book"); for (Iterator i = books.iterator(); i.hasNext(); ) { Element book = (Element)i.next(); if (book.getAttribute("subject") .getValue() .equals("Computers")) { // Ausgabe eines Items rss.append("<item rdf:about=\"http://www.newInstance.com/") .append("javaxml2/techbooks\">\n") // Titel .append(" <title>") .append(book.getChild("title").getContent()) .append("</title>\n") // Link zum Kaufen des Buches .append(" <link>") .append("http://newInstance.com/javaxml2") .append("/techbooks/buy.xsp?isbn=") .append(book.getChild("saleDetails") .getChild("isbn") .getContent()) .append("</link>\n") .append(" <description>") // Beschreibung .append(book.getChild("description").getContent()) .append("</description>\n") .append("</item>\n"); } } rss. append("</rdf:RDF>"); return rss.toString(); } }
Zu diesem Zeitpunkt sollte Sie nichts in diesem Code mehr überraschen. Ich habe die erforderlichen JDOM- und I/O-Klassen importiert und auf die Anwendung der Bibliothek wie schon im Servlet ListBooksServlet zugegriffen. Der als Ergebnis entstandene InputStream wurde benutzt, um ein JDOM-Document zu erzeugen, wobei der Default-Parser (Apache Xerces) und der auf SAX basierende JDOM-Builder die Arbeit erledigten.
Dann wird das JDOM-Document an die Methode generateRSSContentMethod() übergeben, die alle statischen Anteile des RSS-Dokuments ausgibt. Diese Methode holt anschließend alle book-Elemente aus dem XML von der Bibliothek und iteriert über diese, wobei alle Elemente ignoriert werden, deren Attribut subject nicht den Wert »Computer« hat.
Wieder habe ich einige Dinge zu Illustrationszwecken ein wenig geändert. Zum Beispiel gibt dieser Code XML direkt aus – Sie könnten ebenso einen JDOM-Baum konstruieren und ihn mittels eines geeigneten XMLOutputters ausgeben. Sie könnten auch DOM für das ganze Servlet benutzen. All das sind mögliche und völlig legitime Optionen.
Schließlich wird jedes Element, das den Vergleich übersteht, zum RSS-Channel hinzugefügt. Es geschieht nichts wirklich Aufregendes hier, oder? Abbildung 14-5 zeigt eine Beispielausgabe des als GetRSSChannelServlet.java gespeicherten Servlets beim Zugriff mittels eines Webbrowsers.
Mit diesem nun benutzbaren RSS-Channel hat mytechbooks.com seinen Inhalt jedem Service-Provider zur Verfügung gestellt, der RSS benutzt. Um die Sache ins Rollen zu bringen, würde mytechbooks.com nunmehr gern sicherstellen, daß das RSS-Dokument gültig ist, und eine Beispielausgabe in HTML sehen (und Sie auch – könnte ich mir vorstellen).
Wir machen eine Testfahrt
Lassen Sie uns dieses Ding jetzt in Aktion erleben. Surfen Sie mit Ihrem Browser zu http://www.redland.opensource.ac.uk/rss. Diese Site verfügt online über ein nettes Testwerkzeug mit Namen Redland RSS Viewer. Damit ist es möglich, Ihren RSS-Channel zu validieren und als HTML darzustellen. Sie müssen sicherstellen, daß auf das RSS irgendwo online zugegriffen werden kann (zum Beispiel durch das eben besprochene Servlet). Geben Sie die URL des Servlets oder einer anderen RSS-Quelle an, und wählen Sie »YES« (»JA«) bei der Option »Format output as a box« (Formatiere Ausgabe als Box). Das weist den Viewer an, Ihren Channel als HTML-Box zu formatieren, wie man ihn auch in Netscapes Netcenter oder unter http://www.oreilly.com (wo einige RSS-Streams verwendet werden) sehen würde. Die Ausgabe des RSS-Channels, den wir gerade erzeugt haben, zeigt Abbildung 14-6.
Sie können auch verschiedene andere RSS-Quellen vom Viewer aus auswählen und sich ansehen, wie diese als HTML-Ausgabe wirken. Der Channel Meerkat ist besonders interessant, da er fast alle RSS-Optionen benutzt, die zur Zeit verfügbar sind. Haben Sie irgendwelche Fehler in Ihrem RSS-Dokument, sagt Ihnen dieser Viewer, welche das sind. Das macht das Debuggen von RSS-Channeln sehr viel leichter, bevor sie wirklich online gehen.
Ich werde in diesem Kapitel keinen Code vorstellen, der RSS parst oder formatiert. Erstens ist das inzwischen ein Kinderspiel für Sie, und zweitens wird jede Site RSS unterschiedlich formatieren. Einige Beispiele für die Möglichkeiten der Formatierung sind unter http://www.servlets.com (unten rechts), http://www.oreilly.com und http://www.xml.com zu finden. Die Formate der angegebenen Sites unterscheiden sich mitunter erheblich. Beim Lesen eines RSS-Channels werden Sie die Daten wahrscheinlich wie XML behandeln und SAX, DOM oder JDOM zum Lesen der Daten benutzen. Es besteht kein Grund, eine RSS-Quelle anders zu behandeln als ordinäre XML-Dokumente. Sie wissen lediglich ein wenig im voraus, wie die Formatierung aussehen wird. Mit diesem Wissen sind Sie in der Lage, RSS in eigenen Websites zu benutzen.
Was ist mit Netcenter passiert?
Leser der ersten Auflage könnten sich fragen, was mit dem Abschnitt über das Anschauen von RSS-Channels mit Netscapes Netcenter geworden ist. Sollten Sie dieses Buch nicht kennen – Netscape bot einen Mechanismus zum Hinzufügen von Channels zu seiner Website my.netscape.com an. Das war cool, da Sie so Ihr RSS einfach im gut aussehenden Netscape-Interface formatieren und anschauen konnten. Als jedoch RSS 1.0 vorgestellt wurde und RSS 0.91 ersetzte, hat Netscape all seine Links dafür entfernt und erlaubt diese Art der Veröffentlichung nicht mehr. Wenn Sie also nach einer Möglichkeit suchen, Ihre modifizierten Channels in Ihrer Netcenter-Homepage darzustellen, haben Sie kein Glück.
Sie haben jetzt einen guten Einblick in RSS bekommen und – was am wichtigsten ist: Sie haben wahrscheinlich bemerkt, daß es, ählich wie bei SOAP und Web Services, tonnenweise Möglichkeiten gibt, mit RSS zu kommunizieren. Passen Sie die Beispiele und Konzepte dieses Kapitels entsprechend an Ihre eigenen Erfordernisse an, und fügen Sie Formatierungen und Geschäftslogik hinzu, die Ihren Bedürfnissen entsprechen. Nun haben Sie eine klarere Vorstellung, wie das zu tun ist, und mehr Zeit, nachts Gitarre zu spielen (hoppla, das bin ja ich ... na, Sie wissen schon, was ich meine!).
Und was kommt jetzt?
Sie haben nun verschiedene Möglichkeiten für die Zusammenarbeit gesehen – so zum Beispiel die Veröffentlichung von Inhalten für Clients, die Benutzung von SOAP zur Kommunikation zwischen entfernten Anwendungen und B2B-Kommunikation. Nun wende ich mich Code-Interna zu. Im nächsten Kapitel werde ich einige Zeit über XML-Data-Binding sprechen, was es einfacher macht, mit XML-Dokumenten und Java-Objekten zu arbeiten. Ich werde außerdem erläutern, wie sich das auf Persistenz und Konfiguration auswirkt, zwei oft bemühte Tasks in der Enterprise-Programmierung.
- 1)
- Nähere Informationen zur Klasse URL und zum Java-I/O-Framework sind in dem Buch Java I/O von Elliotte Rusty Harold (O’Reilly & Associates) enthalten.
- 2)
- Das ist keine Begrenzung von RSS 1.0, sondern sorgt für Abwärtskompatibilität mit RSS 0.9 und 0.91.
- 3)
- Ja, das ist ein komischer Fall und tritt wahrscheinlich unter realen Bedingungen selten auf. Er gibt mir jedoch die Möglichkeit, eine andere Alternative zur Erzeugung von XML aus Programmen heraus zu erläutern. Rümpfen Sie nicht zu sehr die Nase über die Absurdität dieses Beispiels – alle Beispiele in diesem Buch, einschließlich der komischen, stammen aus realen Erfahrungen bei der Beratung realer Unternehmen. Wenn Sie darüber lachen, könnte das bedeuten, daß Ihr nächstes Projekt dieselben Anforderungen stellt!