Adventures in XHTML

Veröffentlicht am Samstag, 31. Januar 2009, von infinity auf Alphane Moon

Beim Einsatz von XHTML kann man viele Überraschungen erleben. Ich verwende zum Beispiel auf jeder Seite SVG, das inline in das Markup eingebettet ist. Damit die Grafiken im Browser auch zu sehen sind, muß die Seite mit dem richtigen MIME-Type ausgeliefert werden: application/xhtml+xml. Der für normale HTML-Seiten übliche MIME-Type text/html funktioniert nicht, das ist jedoch der einzige, den der Internet Explorer versteht. Eine Lösung muß gefunden werden: eine Content Negotiation, die auf dem ACCEPT-Header basiert.

Internet Explorer und application/xhtml+xml

XHTML muß in manchen Fällen mit einem bestimmten MIME-Type ausgeliefert werden. Das kann man ja irgendwie einstellen. Warum ist das ganze eigentlich ein Problem? Das Problem liegt darin, daß der Internet Explorer mit dem benötigten MIME-Type application/xhtml+xml nichts anfangen kann. Ich kann mir das auch nicht erklären, warum das so ist, denn andere Browser haben damit keine gravierenden Schwierigkeiten.

Internet Explorer verstand schon vorher kein application/xhtml+xml. Neu in Version 8: Jetzt mit totalem Absturz nach der Fehlermeldung.

Je nach den verwendeten Sicherheitseinstellungen zeigt der Internet Explorer ein faszinierend unerwartetes Verhalten: Es erscheint ein Download-Prompt oder eine Fehlermeldung. Beiden ist gemeinsam, daß die XHTML-Seite überhaupt nicht angezeigt wird.

Internet Explorer 8 konfrontiert mit dem MIME-Type application/xhtml+xml.

Whoa, sind die schön! Mausgraue Download-Pop-Ups und Fehlermeldungen. Na, wenn das mal beim Besucher kein tiefes Vertrauen weckt! Da fragt man sich manchmal schon, ob das nicht Sabotage ist. Auch der neue Internet Explorer 8 kann es nicht besser. Schrecklich.

Der ACCEPT-Header

Die meisten User-Agents und Browser senden bei einem Request einen ACCEPT-Header an den Server. Er enthält Informationen darüber, welche Dateiarten überhaupt akzeptiert werden.

Der ACCEPT-Header von Opera enthält zum Beispiel folgendes:

text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1

Der q-Wert aus dem ACCEPT-Header ist eine Zahl zwischen 0.0 und 1.0. Er beschreibt die besonderen Vorlieben eines User-Agents für bestimmte MIME-Typen.

Die Tatsache, daß ein Browser in der Regel einen ACCEPT-Header sendet, kann man für eine Content Negotiation ausnutzen.

Content Negotiation mit PHP

Die einfachste Variante einer Content Negotiation mit PHP ist ziemlich geradeaus: Es wird überprüft, ob die Zeichenkette application/xhtml+xml im HTTP_ACCEPT vorkommt. Ist das der Fall, wird mit der Funktion header() der entsprechende MIME-Type ausgegeben.

<?php
if (stristr($_SERVER["HTTP_ACCEPT"],"application/xhtml+xml") ) {
  header("Content-type: application/xhtml+xml"; charset=UTF-8");
}
else {
  header("Content-type: text/html"; charset=UTF-8");
}
?>

Eine ausgefeiltere Umsetzung berücksichtigt den q-Wert aus dem ACCEPT-Header:

<?php
$charset = "UTF-8";
$mime = "text/html";

if(stristr($_SERVER["HTTP_ACCEPT"],"application/xhtml+xml")) {

if(preg_match("/application\/xhtml\+xml;q=([01]|0\.\d{1,3}|1\.0)/i",
  $_SERVER["HTTP_ACCEPT"],$matches)) {
  
   $xhtml_q = $matches[1];
   
    if(preg_match("/text\/html;q=q=([01]|0\.\d{1,3}|1\.0)/i",
	$_SERVER["HTTP_ACCEPT"],$matches)) {
	
      $html_q = $matches[1];
      if((float)$xhtml_q >= (float)$html_q) {
      $mime = "application/xhtml+xml";
                 }
                }
        } else {
           	$mime = "application/xhtml+xml";
                }
}

if(stristr(getenv('HTTP_USER_AGENT'), "W3C_Validator")){
$mime = "application/xhtml+xml";
}

header("Content-Type: $mime; charset=$charset");
header("Vary: Accept");

?>

Auch für den Markup-Validator des W3C wird bei der zweiten Umsetzung der MIME-Type auf application/xhtml+xml gesetzt. Der ACCEPT-Header des Validators ist leer, über seinen User-Agent-String W3C_Validator kann man ihn trotzdem identifizieren. Und wenn sich nun ein User-Agent als Validator ausgibt, aber kein application/xhtml+xml versteht? Ja, dann hat er eben Pech gehabt. So it goes.

Content Negotiation mit .htaccess

Falls man statische .xhtml-Dateien in Abhängigkeit vom ACCEPT-Header als text/html oder application/xhtml+xml losschicken möchte, kann man auch über die Datei .htaccess des Apache-Webservers eine Content Negotiation einrichten:

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_ACCEPT} application/xhtml\+xml
RewriteCond %{HTTP_ACCEPT} !application/xhtml\+xml\s*;\s*q=0
RewriteCond %{REQUEST_URI} \.xhtml$
RewriteCond %{THE_REQUEST} HTTP/1\.1
RewriteRule .* - [T=application/xhtml+xml]

all content copyright © 2007-2010 Alphane Moon