XHTML - HTML
Typy MIME dokumentów XHTML
Co to są typy MIME dokumentów i dlaczego są tak ważne w języku XHTML? W jaki sposób automatycznie dobrać typ MIME, tak aby nie powodować błędów w starszych przeglądarkach?
(interpretuje: Chrome 4, Firefox 2, Edge 12, Opera 10, Safari 3.1, Internet Explorer 9.0)
Typ MIME w Internecie wskazuje format pliku, z jakim mamy do czynienia. Nietrudno się domyślić, że określa on również typ dokumentów HTML oraz XHTML, ponieważ jak sama nazwa wskazuje nie są one zwykłym tekstem ale hipertekstem. Oto spis typów MIME, z jakimi mogą być przesyłane dokumenty HTML i XHTML:
MIME | HTML 4 | XHTML 1.0 (kompatybilność wstecz) | XHTML 1.0 | XHTML 1.1 |
---|---|---|---|---|
text/html | powinien | może | nie powinien | nie powinien |
application/ xhtml+xml | nie może | powinien | powinien | powinien |
application/ xml | nie może | może | może | może |
text/xml | nie może | może | może | może |
Źródło: XHTML Media Types
- text/html
- Typ odpowiedni dla dokumentów HTML oraz XHTML 1.0, których autorzy pragną, aby mogły być wyświetlane w przeglądarkach, które nie obsługują języka XHTML w pełni. Dokumenty tego typu nie będą przetwarzane zgodnie z wymogami języka XML. Będzie to miało wpływ również na zachowanie skryptów JavaScript, korzystających ze standardu DOM oraz reguły arkuszy CSS. Domyślnym kodowaniem znaków - tzn. jeśli nie określimy inaczej - zwykle jest UTF-8, jednak może to zależeć od ustawień przeglądarki.
- application/xhtml+xml
- Typ specjalnie zaprojektowany dla dokumentów XHTML i najbardziej dla nich odpowiedni. Dokumenty tego typu są przetwarzane zgodnie z wymogami języka XML. Strona kodowania znaków podlega tym samym ograniczeniom i regułom, co dla typu application/xml.
- application/xml
- Ogólny typ języka XML. Dokumenty XHTML mogą być również serwowane z tym typem, jednak w takim przypadku niektóre przeglądarki mogą ich nie wyświetlić zgodnie z regułami języka XHTML, tzn. np. linki mogą nie być "klikalne"! Domyślny system kodowania znaków to UFT-8 lub UTF-16. Inne kodowanie można określić za pomocą nagłówka HTTP lub deklaracji XML. Deklaracja strony kodowej za pomocą znacznika META nie jest rozpoznawana (w tego typu dokumentach XHTML nie powinno się jej wstawiać)!
- text/xml
- Inny ogólny typ przeznaczony dla języka XML. Jest on preferowany dla dokumentów XML, które w formie nieprzetworzonej, tzn. czystego kodu źródłowego, mogą być bez większych trudności odczytane przez zwykłego użytkownika. W przeciwnym wypadku zaleca się stosowanie application/xml. Serwowanie dokumentów XHTML z tym typem również jest możliwe, jednak mogą wystąpić dokładnie te same problemy, co w przypadku application/xml. Dlatego zaleca się stosowanie application/xhtml+xml!
Jak można łatwo zauważyć, najodpowiedniejszym typem MIME dla dokumentów HTML jest text/html. Dokumenty XHTML 1.0 mogą być przesyłane z tym samym typem zwłaszcza, jeśli są napisane w sposób, umożliwiający ich wyświetlenie przez przeglądarki, które obsługują tylko podstawowy język HTML. Natomiast dokumenty XHTML 1.1 powinny być przesyłane z typem application/xhtml+xml - w tym przypadku text/html nie jest zalecane.
Ponadto trzeba zdawać sobie sprawę, że sama deklaracja strony kodowej nie wystarczy do określenia typu MIME! Konieczne jest przesłanie odpowiedniego nagłówka HTTP, poprzedzającego właściwą treść dokumentu. W języku HTML (ani XHTML) nie ma takiej możliwości. W przypadku dokumentów HTML lub XHTML 1.0 kompatybilnych wstecz, nie trzeba się jednak tym martwić. Wystarczy nadać plikowi odpowiednie rozszerzenie - zwykle *.html. Z dokumentami XHTML 1.1 może być jednak większy kłopot. Teoretycznie ten sam mechanizm moglibyśmy uzyskać, nadając plikom rozszerzenie *.xhtml. Niestety nie wszystkie przeglądarki obsługują pliki z typem MIME application/xhtml+xml. Przykładowo: zamiast wyświetlić stronę, przeglądarka może próbować pobrać plik na dysk, co oczywiście uniemożliwia wyświetlenie zawartości strony! Wyniki testu rozpoznawania typów MIME przez różne przeglądarki można obejrzeć na stronie organizacji W3C: XHTML media type test.
Z problemem można sobie poradzić poprzez tzw. negocjację zawartości, która polega na wysłaniu takiego typu MIME, który jest obsługiwany przez przeglądarkę. Niestety statyczny język XHTML na to nie pozwala. Można to natomiast osiągnąć np. przy pomocy PHP:
Aby poniższy skrypt działał poprawnie, konieczna jest obsługa języka PHP na serwerze!
- Utwórz katalog o nazwie mime, a w nim plik pod nazwą mime.inc.php i zapisz w nim następujący kod (na początku można podać własne ustawienia):
<?php /** * XHTML MIME Negotiation * @version 2.2.3 * @author Sławomir Kokłowski {@link https://www.kurshtml.edu.pl} * @copyright NIE usuwaj tego komentarza! (Do NOT remove this comment!) */ //////////////////// SETTINGS //////////////////// /** * Strona kodowa. * @global string $CHARSET */ $CHARSET = 'utf-8'; /** * Preferowana wersja DTD (XHTML 1.1, XHTML 1.0 Strict, XHTML 1.0 Transitional, XHTML 1.0 Frameset). * @global string $DTD */ $DTD = 'XHTML 1.1'; /** * Wersja DTD w przypadku braku pełnej interpretacji XHTML 1.1 (XHTML 1.0 Strict, XHTML 1.0 Transitional, XHTML 1.0 Frameset). * @global string $DTD2 */ $DTD2 = 'XHTML 1.0 Strict'; /** * Czy brać pod uwagę typy MIME języka XML (true - tak, false - nie). * MOŻE SPOWODOWAĆ PROBLEMY Z WYŚWIETLENIEM DOKUMENTU! * @global bool $XML */ $XML = false; /** * Arkusze CSS wraz z mediami (opcjonalnie). * Przykłady: * - 'style.css', * - 'style.css"all', * - 'style.css print.css"print'. * @global string $CSS */ $CSS = ''; ////////////////////////////////////////////////// if (defined('CSS')) $CSS .= ' '.CSS; $CSS = trim($CSS); if ($CSS == '') $CSS = array(); else { $CSS = preg_split('/\s+/', $CSS); foreach ($CSS as $i => $css) $CSS[$i] = explode('"', $css); } $MIME = 'text/html'; if (array_key_exists('HTTP_ACCEPT', $_SERVER)) { if (preg_match_all('/application\/xhtml\+xml(?![+a-z])([^,]*;\s*q\s*=\s*([0-9.]+))?/i', $_SERVER['HTTP_ACCEPT'], $matches) && (count($matches) < 3 || $matches[2] > 0)) $MIME = 'application/xhtml+xml'; else if ($XML) { if (preg_match_all('/application\/xml(?![+a-z])([^,]*;\s*q\s*=\s*([0-9.]+))?/i', $_SERVER['HTTP_ACCEPT'], $matches) && (count($matches) < 3 || $matches[2] > 0)) $MIME = 'application/xml'; else if (preg_match_all('/text\/xml(?![+a-z])([^,]*;\s*q\s*=\s*([0-9.]+))?/i', $_SERVER['HTTP_ACCEPT'], $matches) && (count($matches) < 3 || $matches[2] > 0)) $MIME = 'text/xml'; } } else if (array_key_exists('HTTP_USER_AGENT', $_SERVER) && preg_match('/W3C[^a-z]Validator/i', $_SERVER['HTTP_USER_AGENT'])) $MIME = 'application/xhtml+xml'; if ($MIME == 'text/html' && $DTD == 'XHTML 1.1') $DTD = $DTD2; header("Content-Type: $MIME; charset=$CHARSET"); echo "<"."?xml version=\"1.0\" encoding=\"$CHARSET\"?".">\n"; if ($MIME != 'text/html' || !array_key_exists('HTTP_USER_AGENT', $_SERVER) || !preg_match('/\sMSIE\s*([0-9])/', $_SERVER['HTTP_USER_AGENT'], $matches) || $matches[1] > 6) foreach ($CSS as $css) echo "<"."?xml-stylesheet href=\"".$css[0]."\" type=\"text/css\"".(empty($css[1]) ? "" : " media=\"".$css[1]."\"")."?".">\n"; require_once dirname(__FILE__)."/$DTD.inc.php"; echo "\n"; if ($MIME == 'text/html') { echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$CHARSET\" />\n"; foreach ($CSS as $css) echo "<link rel=\"stylesheet\" href=\"".$css[0]."\" type=\"text/css\"".(empty($css[1]) ? "" : " media=\"".$css[1]."\"")." />\n"; } ?>
- W tym samym katalogu (mime) utwórz następujące pliki:
- XHTML 1.1.inc.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head>
- XHTML 1.0 Strict.inc.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="pl"> <head>
- XHTML 1.0 Transitional.inc.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="pl"> <head>
- XHTML 1.0 Frameset.inc.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="pl"> <head>
- XHTML 1.1.inc.php
- Każdemu dokumentowi XHTML nadawaj rozszerzenie *.php, a nie *.html.
- Wszystkie dokumenty XHTML buduj w następujący sposób (na początku należy podać lokalizację utworzonego przed momentem pliku mime.inc.php):
<?php require_once 'mime/mime.inc.php'; ?> <title>Tytuł dokumentu</title> </head> <body> <p>Treść dokumentu...</p> </body> </html>
Natomiast, aby w określonym dokumencie lub kilku dokumentach wstawić dodatkowe arkusze stylów CSS - inne niż dla całości serwisu - użyj następującej składni:<?php // Dodatkowe arkusze CSS rozdzielone spacjami: define('CSS', 'css/style3.css css/style4.css'); require_once 'mime/mime.inc.php'; ?> <title>Tytuł dokumentu</title> </head> <body> <p>Treść dokumentu...</p>
Można również podać media:
</body> </html><?php // Dodatkowe arkusze CSS rozdzielone spacjami: define('CSS', 'css/style.css css/print.css"print'); require_once 'mime/mime.inc.php'; ?> <title>Tytuł dokumentu</title> </head> <body> <p>Treść dokumentu...</p>
</body> </html>
Jeżeli uda Ci się już przekonwertować wszystkie dokumenty do standardu XHTML i pomyślisz o wysyłaniu ich z typem MIME application/xhtml+xml, może zaskoczyć Cię pewien sposób zachowania przeglądarek (np. Firefox, Opera, Chrome). Mianowicie żaden dokument XHTML przetwarzany zgodnie regułami języka XML (tzn. z typem MIME innym niż text/html) nie wyświetli się, jeżeli będzie zawierał błędy XML! Takim błędem może być np. przeplatanie znaczników:
<p>To jest przykład błędnego kodu XML: wewnątrz paragrafu jest <em>emfaza.</p></em>
Po wpisaniu takiego kodu, zamiast spodziewanej strony, ujrzymy komunikat błędu ze wskazaniem linii, w której on wystąpił. Pozornie takie działanie może być niewygodne, ale tak naprawdę to jest mechanizm, na który od dawna czekali bardziej zaawansowani webmasterzy. Dzięki niemu po prostu wszystkie poważne błędy składniowe mogą zostać wyeliminowane na wczesnym etapie. W dokumencie HTML (lub XHTML 1.0 z typem MIME text/html) taki błąd w ogóle nie dałby o sobie znać, a zatem najprawdopodobniej pozostałby niezauważony. Każda przeglądarka HTML stara się "korygować" tego typu pomyłki webmasterów tak, aby strona mogła się wyświetlić. Jednak nigdy nie ma pewności, że dany rodzaj błędu zostanie identycznie skorygowany w każdej możliwej przeglądarce, a co za tym idzie, strona może się wyświetlać na różne sposoby - niekoniecznie tak, jak w zamierzeniu życzył sobie tego autor.
Innym skutkiem używania typu MIME innego niż "text/html" jest zaprzestanie działania metody document.write(...)
we wszystkich skryptach JavaScript osadzonych na stronie. Metoda ta została zaprojektowana do dynamicznego generowania całości lub części zawartości podczas ładowania dokumentu. Takie działanie jest wykluczone w języku XML, ponieważ dokumenty XML zawsze najpierw są parsowane, a dopiero potem renderowane. Obejściem tej niedogodności może być dynamiczne generowanie zawartości po załadowaniu, np. poprzez własności i metody zawarte w specyfikacji DOM. Zwykle możliwe jest także użycie nieustandaryzowanej właściwości innerHTML
.