Nachschlag: XML korrekt ausliefern

Ich bin geneigt, das hier unter Lust und Frust einzusortieren ;)

Nachdem ich die Tage groß und breit von XML, Zeichensätzen und Content-Types erzählt habe, hier ein paar Infos wie man sich solchen Ärger sparen kann.

Testen
Betrifft mich das Problem überhaupt? Und wenn ja, wo muss ich ansetzen? Beide Fragen klärt der iHHC. Nach Eingabe einer URL (ich bitte darum, dieses Tool nicht zu mißbrauchen, sonst verschwindet es ganz schnell wieder) zeigt es die gesamte Antwort des Webservers auf die Anfrage nach der eingegebenen URL. Zum Beispiel hier die URL des WWWorker-Feeds.

Zwei Stellen sind hier wichtig: Erstens die mit Content-type: beginnende Zeile im ersten Teil der Ausgabe, dem HTTP Header. Zweitens die Angabe des XML-Dokuments selbst, zu finden in der ersten Zeile nach dem Header, beginnend mit <?xml (diese Zeile nennt man übrigens XML-Prolog, nur mal so am Rande).

Stimmt die Angabe im XML-Dokument nicht?
Den im Dokument bestimmten Zeichensatz kann man, jedenfalls in den meisten Fällen, leichter ändern als den vom Server mitgeschickten, deswegen fangen wir damit an. Welcher Zeichensatz ist nun eigentlich der Richtige für mein XML-Dokument? Wenn im Dokument nur lateinische Buchstaben ein paar Zahlen vorkommen, kann man ruhig us-ascii nutzen. Kommt aber zum Beispiel das EUR-Zeichen € vor, sollte es iso-8859-15 sein. Zu den Zeichensätzen siehe Teil 1 dieser Trilogie.

Stimmt die Angabe im HTTP Header nicht?
Wie ändere ich den Zeichensatz für meine XML-Dokumente? Per Webserverkonfiguration. Bei Apache httpd geht das per

AddCharset iso-8859-15 .xml

Diese Zeile kann auch in einer .htaccess-Datei definiert werden (siehe Context: in der AddCharset-Doku.

Wenn wir nun schon dabei sind, checken wir doch gleich noch den vom Server angegebenen Content-type. Für RDF sollte dieser application/rdf+xml lauten, für RSS application/rss+xml und für Atom, richtig geraten, application/atom+xml. Das bekommen wir mittels AddType auch problemlos hin.

Fies wirds wenn wir, wie im Fall des WWWorkers, zwei verschiedene Feeds anbieten: einen RSS 2.0- und einen Atom-Feed. Beide haben die Dateiendung .xml. Der RSS-Feed bekommt aber einen anderen Content-Type als sein Atom-Bruder. Dank der Files-Direktive gelingt auch dies. Hier der Einfachheit halber ein Auszug aus dem .htaccess-File des WWWorker:

AddCharset iso-8859-15 .xml
AddType application/rss+xml .xml

<Files atom.xml>
	ForceType application/atom+xml
</Files>

Was geschieht hier: Zunächst bekommen alle Dateien mit der Endung .xml den Zeichensatz ISO-8859-15 verpasst. Außerdem wird all diesen Dateien der Content-Type application/rss+xml zugewiesen. Die Datei atom.xml erfährt eine Spezialbehandlung, ihr wird per ForceType application/rss+xml aufgezwungen.

An dieser Stelle sollte das Dokument mit korrektem Zeichensatz und korrekter Content-Type-Angabe ausgeliefert werden.

Und was sagt der Feedvalidator?
Strenggenommen kann uns dessen Meinung egal sein. Er ist nämlich kein SGML-Parser, und damit eigentlich nicht geeignet, hundertprozentige Aussagen über ein XML-Dokument zu machen. Aber seis drum, er ist das Beste, was wir haben.

URL eingeben, ENTER drücken und warten. Im besten Fall gratuliert er schlicht. Im schlechtesten ist der Feed sowieso nicht wohlgeformt, und wir haben uns all die Mühe für einen kaputten Feed gemacht. Los, reparieren! Im zweitbesten Fall meckert der Feedvalidator nur noch über ein oder zwei Zeichen, die er nicht korrekt auflösen kann. In diesem Fall passt entweder der Zeichensatz nicht 100%ig (zum Beispiel wurde ISO-8859-1 angegeben, das Dokument enthält aber das EUR-Zeichen €, das es nur im -15er gibt), oder die Anwendung, die den Feed erzeugt hat, macht Fehler.

Im Falle des WWWorker ist dem so. Aus unerfindlichen Gründen generiert Movable Type das EUR-Zeichen als XML-Entität, die leider mit dem Zeichensatz ISO-8859-15 nichts zu tun hat. Wer hier eine Idee hat, was falsch läuft oder wo ich krumm denke, her damit.

Sollte ein Eingriff in die Konfiguration des Webservers nicht möglich sein, hier noch ein kleines PHP-Skript, das XML-Dokumente nach außen hin kapselt. Mit Perl, Python, whatever ist das mit Sicherheit auch möglich.

<?php
header('Content-type: application/rss+xml; charset: iso-8859-15');
readfile('index.xml');
?>

Dieses Skript kapselt immer nur ein Dokument, man braucht also für jedes Dokument, das man kaspeln will, ein Skript.

Frühstück, ich komme! Bis demnächst in diesem Theater.

One comment

  1. Sehr schöne Erklärung, toll gemacht. Wollte zwar nur wissen, welchen Header ich für eine normale XML-Datei ausliefern muss, aber das kann ich mir anhand des Textes zusammenreimen. Vielen Dank. :-)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert