XHTML1.1とXHTML1.0の両立

ページ情報
制作日
2004-02-06
最終更新日
2004-02-06
参照用URI
http://www.arielworks.net/articles/2004/0206a
分野

Another HTML-lintに対応する

Another HTML-lintでXHTML1.1をチェックするとHTML内のmeta要素とHTTPレスポンスヘッダ内のContent-typeフィールドの値が「text/html」だった場合に減点されるようになった。これはXHTMLのメディアタイプに関するW3Cのノートに基づいた判定で、本来ならXHTML1.1では「application/xhtml+xml」が最も適した値とされている。

以前Mozillaの仕様とIE6の仕様(「application/xhtml+xml」だとダウンロードダイアログが表示されてしまう)を両立するためにUAが送信してきたAcceptフィールドに合わせて変化させる方法を紹介したが、HTML-lintはAcceptフィールドに「application/xhtml+xml」を含めていないため、困ったことにXHTML1.1の文章が「text/html」で送信されてしまう。

Content-typeの条件分岐をもう少し高度にしても対応できるがXHTML1.0なら「text/html」で送信してもよいことになっているので、Acceptフィールドに「application/xhtml+xml」が含まれていない場合はXSLTでXHTML1.0に変換してから送信すればよい。XHTMLがXMLである利点を使わない手はない。

XHTML1.1のXHTML1.0からの変更点は以下の通りだ。マイナーバージョンアップなのでそれほど変更点は多くない。

以上よりXHTML1.1をXHTML1.0へ変換する際に必要なことは

である。まずはPHP側のコードを書く。

$ha = explode(",", $_SERVER["HTTP_ACCEPT"]);
if (in_array("application/xhtml+xml", $ha)) {
    $version_xhtml = 1.1;
} else {
    $version_xhtml = 1.0;
}

単純にAcceptフィールドを取得してカンマで分割し「application/xhtml+xml」が含まれていれば使用するXHTMLのバージョンを1.1に、それ以外の場合は1.0として変数に格納している。Content-typeの送信やXSL変換の条件分岐にはこの数字を使うと後々XHTMLがバージョンアップを重ねたときも便利だと思われる。

xslt_process()関数を呼び出すときは5番目の引数(配列)にバージョンを格納しておくとXSLの中で<xsl:param name="version_xhtml"/>で呼び出せる。

$info_xml["version_xhtml"] = $version_xhtml;

$handle_xslt = xslt_create();
$data_proceeded = xslt_process($handle_xslt, "foo.xml", "bar.xsl", null,  null, $info_xml);
xslt_free($handle_xslt);

呼び出されるbar.xslには以下のようなコードを追加しておく。これだけでは動かないので注意。

<xsl:param name="version_xhtml"/>

<xsl:template match="a/@id|map/@id">
    <xsl:attribute name="id"><xsl:value-of select="."/></xsl:attribute>
    <xsl:if test="$version_xhtml = 1.0">
        <xsl:attribute name="name"><xsl:value-of select="."/></xsl:attribute>
    </xsl:if>
</xsl:template>

<xsl:template match="@xml:lang">
    <xsl:attribute name="xml:lang"><xsl:value-of select="."/></xsl:attribute>
    <xsl:if test="$version_xhtml = 1.0">
        <xsl:attribute name="lang"><xsl:value-of select="."/></xsl:attribute>
    </xsl:if>
</xsl:template>

<xsl:template match="ruby">
    <xsl:choose>
        <xsl:when test="$version_xhtml = 1.0">
            <xsl:value-of select="."/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

一応DOCTYPE宣言とContent-typeフィールドの送信方法も書いておく。

DOCTYPE宣言
if ($version_xhtml == 1.1) {
    $data_proceeded = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">' . "\n" . $data_proceeded;
} elseif ($version_xhtml == 1.0) {
    $data_proceeded = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . "\n" . $data_proceeded;
}
Content-typeフィールド
if ($version_xhtml == 1.1) {
    header("Content-Type: application/xhtml+xml; charset=UTF-8");
} elseif ($version_xhtml == 1.0) {
    header("Content-Type: text/html; charset=UTF-8");
}

DOCTYPEはバージョンに合わせて単純に先頭に追加するだけなのでXSLTで出力しても良いかもしれない。

元々PHP+XML+XSLTという組み合わせでサイトを構築していた場合は数行のコードを追加すればいいだけなのでこういった処理も比較的簡単だ。

連絡先、リンク、転載や複製などについては「サイト案内」をご覧ください。Powered by HIMMEL