ヒント: XSLT の識別テンプレートを使って XHTML を変換する

XHTML タグを適切に閉じる

XHTML は単なる整形式の HTML ではありません。XHTML では特定のタグを適切に閉じなければなりません。適切に閉じられていないタグは妥当な XML ですが、ブラウザーはそれらのタグを適切に構文解析することができないため、動的な Web 2.0 機能で問題が発生する可能性があります。XML を XHTML に変換する場合であれ、単に XHTML をフィルタリングする場合であれ、その XHTML が W3C 推奨のプラクティスに従った適切な XHTML になるようにするには、どんな XSLT テンプレートが必要であるかを学びましょう。

Doug Domeny, Senior Software Engineer, Freelance

Doug Domeny は、ブラウザー・ベースで多言語対応、ビジネス・ユーザー向けの XML エディターを、XSLT、W3C XML Schema、DHTML、JavaScript、jQuery、正規表現、CSS を使って開発した経験があります。彼はマサチューセッツ州 Wenham の Gordon College でコンピューター・サイエンスおよび数学の学位を取得しており、XLIFF (XML Localization Interchange File Format) や OAXAL (Open Architecture for XML Authoring and Localization) など、OASIS の技術委員会で長年委員を務めてきました。彼はソフトウェア・エンジニアとして業務を行う中で、ソフトウェア・エンジニアリングやアーキテクチャー、UI 設計、テクニカルライティングで高いスキルを身に付けています。



2010年 12月 21日

よく使われる頭文字語

  • HTML: Hypertext Markup Language
  • W3C: World Wide Web Consortium
  • XHTML: Extensible Hypertext Markup Language
  • XML: Extensible Markup Language

XHTML は、整形式の XML として作成された HTML です。この説明が一般的に意味することは、その HTML は XML の規則に従わなければならないということです。XML の規則は HTML の規則よりも厳格です。XML の規則には、例えば以下のようなものがあります。

  • タグ名はすべて小文字にします。例えば <P> ではなく、<p> にします。
  • 属性の値は、引用符で囲みます。例えば <input type=checkbox> ではなく、<input type="checkbox"> のようにします。
  • 属性を適用する場合には、値を指定します。値が定義されていない HTML 属性の場合には、その属性の名前を属性の値として使用します。例えば <input selected> ではなく、<input selected="selected"> のようにします。値がない属性には、以下のようなものがあります。
    • checked
    • disabled
    • selected
    • nowrap
  • タグは適切にネストされるようにします。例えば <b><i>…</b></i> ではなく、<b><i>…</i></b> のようにします。
  • オプションの終了タグは省略してはなりません。例えば <p>…<p>… ではなく、<p>…</p><p>…</p> のようにします。

しかし XML が HTML ほど厳密ではない点が 1 つあり、それがタグの閉じ方です。XML の場合、空の要素 (つまり内部にテキストも他のタグも含まない要素) を閉じるには、以下のように短縮形 (自己終了タグ) を使うことも、開始タグとは別に終了タグを持つ長形式を使用することもできます。

  • 短縮形でスラッシュ (/) の前に半角スペースがある場合とない場合: <tag/> または <tag />
  • 長形式の場合: <tag></tag>

一方、HTML では、終了タグが必要なものもあれば、終了タグが禁止されているものもあります。

終了タグが必要なタグとしては、<a><abbr><acronym><address><b><big><blockquote><button><code><dir><div><em><font><form><h1><i><label><li><map><ol><pre><script><span><strong><style><sub><table><tt><ul><xml> などがあります。終了タグが禁止されているタグとしては、<area><base><br><col><frame><img><isindex><link><meta><param> などがあります。

HTML の自己終了タグ

HTML の自己終了タグとしては、<area /><base /><basefont /><bgsound /><br /><col /><frame /><hr /><img /><input /><isindex /><keygen /><link /><meta /><param /> などがあります。

また W3C は、ブラウザー間での互換性を高めるために、自己終了タグの末尾のスラッシュの前に以下のように半角スペースを追加することを推奨しています。

  • 推奨の形式: <input type="checkbox" />
  • 推奨されない形式: <input type="checkbox"/>

参考文献」に挙げた、HTML の互換性に関するガイドラインへのリンクを参照してください。

XHTML は XML であるため、XSLT を使用して XHTML を変換することができます。XSLT は本来、XML データを HTML に変換するための柔軟で強力な手段でした。XML 技術 (特に XHTML) が広く採用されるにつれ、XSLT によって解決可能なアプリケーションの幅も広がっています。XHTML は、変換の入力にすることも、変換によって生成することも、あるいはその両方も可能です。XSLT を使用して XHTML を生成すると、HTML に準拠する形で空のタグを閉じるにはどうすればよいか、という問題が発生します。

XHTML タグを適切に閉じる

空のタグが不適切な方法で閉じられた場合にはどうなるのでしょう。

  • JavaScript ファイルをダウンロードするためのスクリプト・タグが短縮形で閉じられていると、その JavaScript ファイルを取得することができません。

    失敗する場合: <script type="text/javascript" href="myfile.js" />

    成功する場合: <script type="text/javascript" href="myfiles.js"></script>

  • <div> タグが、空の自己終了タグの場合、開始タグとして扱われます。従って自己終了タグの <div> 要素は、次の開始 <div> タグまでの間に含まれる要素やテキストを、その <div> 要素の内容とみなします。例えば以下の場合、

    <div id="mydiv1" />
    
    <p>This paragraph will be
    contained within mydiv1</p>
    
    <div id="mydiv2"></div>
    
    <p>This paragraph will NOT be
    contained in either 'div'</p>

    ブラウザーはマークアップを以下のように解釈して暗黙的に終了 <div> タグを追加し、またそのことをコメントとして追加します。



    <div id="mydiv1">
    
    <p>This paragraph is
    contained within mydiv1</p>
    
    </div> <!-- implied closing tag -->
    
    <div id="mydiv2"></div>
    
    <p>This paragraph is NOT
    contained in either 'div'</p>
  • 長形式の <br></br> で表現された 1 つの <br> 要素は <br><br> という 2 つの要素として解釈されます。そのため、改行の数が 2 倍になってしまいます。

タグの処理とコピー

XHTML タグを適切に閉じるためのソリューションは、開発環境に応じて 3 つの種類があります。そのうちの 1 つであるシリアライズでは、XML 文書オブジェクトをストリングに変換するためのコード (例えば C# コードや Java™ コード) を作成します。シリアライズは最も複雑なソリューションですが、最も柔軟なソリューションでもあります。残る 2 つのソリューションは XSLT のバージョンに依存します (XSLT 2.0 が最も容易なソリューションです)。


ソリューション: XHTML へのシリアライズを行う

シリアライズというのは、メモリー内のバイナリー・オブジェクトを変換し、ファイルシステムへの保存またはネットワーク上への送信に適したストリングにするプロセスです。オブジェクト・モデルを XHTML にシリアライズするためのコードを作成する場合であれ、XSLT 変換の結果が既にストリングとして得られている場合であれ、空の XHTML タグが適切に閉じられるようにするためには、シリアライズを制御する必要があります。

変換の結果がオブジェクトの場合には、終了タグが禁止されているタグは、以下のように短縮形の自己終了タグへとシリアライズします。

"<" tag-name [ attributes ] " />"

それ以外の空のタグはすべて、以下のように別の終了タグを使って終了します。

"<" tag-name [ attributes ] "></" tag-name ">"

以下に C# の場合の例を 2 つ挙げます。1 つは XmlTextWriter の場合、もう 1 つは StringWriter の場合です。リスト 1XhtmlTextWriterXmlTextWriter から派生しており、WriteEndElement メソッドをオーバーライドして短縮形または長形式で要素を閉じています。

リスト 1. XhtmlTextWriter
public class XhtmlTextWriter : System.Xml.XmlTextWriter
{
    private string tagName = string.Empty;
    private string elementNamespace = string.Empty;

    public XhtmlTextWriter(System.IO.TextWriter w)
        : base(w)
    {
    }

    public override void WriteEndElement()
    {
        bool isShortNotation = true;

        // Check if XHTML Namespace
        if (string.IsNullOrEmpty(this.elementNamespace) || 
            (this.elementNamespace.Contains("www.w3.org") && 
                this.elementNamespace.Contains("xhtml")))
        {
            switch (this.tagName)
            {
                case "area":
                    isShortNotation = true;
                    break;
                case "base":
                    isShortNotation = true;
                    break;
                case "basefont":
                    isShortNotation = true;
                    break;
                case "bgsound":
                    isShortNotation = true;
                    break;
                case "br":
                    isShortNotation = true;
                    break;
                case "col":
                    isShortNotation = true;
                    break;
                case "frame":
                    isShortNotation = true;
                    break;
                case "hr":
                    isShortNotation = true;
                    break;
                case "img":
                    isShortNotation = true;
                    break;
                case "input":
                    isShortNotation = true;
                    break;
                case "isindex":
                    isShortNotation = true;
                    break;
                case "keygen":
                    isShortNotation = true;
                    break;
                case "link":
                    isShortNotation = true;
                    break;
                case "meta":
                    isShortNotation = true;
                    break;
                case "param":
                    isShortNotation = true;
                    break;
                default:
                    isShortNotation = false;
                    break;
            }
        }

        if (isShortNotation)
        {
            base.WriteEndElement();
        }
        else
        {
            base.WriteFullEndElement();
        }
    }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        this.tagName = localName.ToLower();
        this.elementNamespace = ns;
        base.WriteStartElement(prefix, localName, ns);
    }

    public override void WriteStartDocument()
    {
        // Don't emit XML declaration
    }

    public override void WriteStartDocument(bool standalone)
    {
        // Don't emit XML declaration
    }
}

リスト 2XhtmlStringWriter クラスを示しています。このクラスは StringWriter から派生したもので、Write メソッドをオーバーライドし、長形式から短縮形への変換が必要なタグの場合には長形式を短縮形に変換しています。同じようなメソッドを Java 言語などの他のプログラミング言語でも作成することができます。

リスト 2. XhtmlStringWriter
public class XhtmlStringWriter : System.IO.StringWriter
{
    public override void Write(string value)
    {
        bool isShortNotation = false;
        switch (value)
        {
            case "></area>":
                isShortNotation = true;
                break;
            case "></base>":
                isShortNotation = true;
                break;
            case "></basefont>":
                isShortNotation = true;
                break;
            case "></bgsound>":
                isShortNotation = true;
                break;
            case "></br>":
                isShortNotation = true;
                break;
            case "></col>":
                isShortNotation = true;
                break;
            case "></frame>":
                isShortNotation = true;
                break;
            case "></hr>":
                isShortNotation = true;
                break;
            case "></img>":
                isShortNotation = true;
                break;
            case "></input>":
                isShortNotation = true;
                break;
            case "></isindex>":
                isShortNotation = true;
                break;
            case "></keygen>":
                isShortNotation = true;
                break;
            case "></link>":
                isShortNotation = true;
                break;
            case "></meta>":
                isShortNotation = true;
                break;
            case "></param>":
                isShortNotation = true;
                break;
        }

        if (isShortNotation)
        {
            base.Write(" />");
        }
        else
        {
            base.Write(value);
        }
    }
}

ソリューション: XSLT 1.0 を使用する

まず、XSLT の出力形式 (xsl:output の method) が html ではなく xml になっていることを確認します。method が html の場合、XHTML は出力されません。また、HTMLは XML ではないので、XSLT プロセッサーも XML パーサーも HTML を処理することはできません。

変換の結果がストリングまたはファイルの場合には、空のタグを適切に閉じるように強制する XSLT テンプレートをコーディングすることで、間接的にシリアライズを制御します。どちらの形式で空のタグを閉じるかは、XSLT プロセッサーの実装に依存します。

識別テンプレート

入力も XHTML の場合には、識別テンプレートを使用して、変更のないタグを出力にコピーします。識別テンプレートは入力要素と属性を処理して出力にコピーします。識別テンプレートを使用しない場合には、タグの間にあるテキストのみが出力にコピーされます。

リスト 3 の XSLT には識別テンプレートがないため、プレーン・テキストのみが出力されます。

リスト 3. 結果はプレーン・テキストのみです
<?xml version='1.0' ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>
</xsl:stylesheet>

リスト 4 の XSLT には識別テンプレートがあり、他のテンプレートによって処理されることのない要素を識別テンプレートによってコピーしています。識別テンプレートはノードを突き合わせ、そのノードをコピーします。要素をコピーするための選択肢は 2 つあります。この例では xsl:copy を使用しています。もう 1 つの選択肢としては xsl:element を使用しますが、これについては後ほど説明します。

リスト 4. 結果にはタグが含まれていますが、適切に閉じられていない可能性があります
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" omit-xml-declaration="yes"/>

    <!-- put your templates here -->

    <!-- identity templates -->
    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|text()|comment()|processing-instruction()">
        <xsl:copy/>
    </xsl:template>

</xsl:stylesheet>

タグの閉じ方を制御する

タグを適切に閉じるためには、短縮形を必要とするタグを識別テンプレートによって選択する必要があります。テンプレートの match 式でタグを選択するためには、タグの名前空間を認識するか、あるいは名前空間が使用されていないことを認識する必要があります。空のタグを短縮形として表示するか長形式として表示するかを制御する方法では、(短縮形の場合には) 子ノードを処理せず、(長形式の場合には) 子ノードを処理するようにします。これは処理対象の子ノードがない場合も同じです。ここで XSLT プロセッサーを活用することができます。Microsoft のプロセッサー (Microsoft® .NET と MSXML) は、短縮形でタグを出力する場合には子ノードを処理しないという方法を使います。他のプロセッサー (Saxon など) は、空のタグに対して必ず短縮形を使用します。そのため、終了タグを必要とする HTML 要素の場合には、何らかのテキストを挿入する必要があります。ほとんどの要素では、半角スペースを挿入するのが適切です。<script> タグの場合には、JavaScript のコメント・トークン (つまり //) によって開始タグと終了タグとを分離することができます。幸いなことに、Microsoft のプロセッサーならばこの方法を使うこともできます。

Microsoft .NET プロセッサーまたは MSXML プロセッサー

入力文書に名前空間が使用されていない場合 (リスト 5)、XSLT にも名前空間は必要ありません。

リスト 5. 名前空間を使用しない入力 XHTML 文書
<html>
...
</html>

リスト 6 の XSLT はタグの突き合わせを行い、タグが自己終了でなければならないかどうかを判断しています。自己終了タグは、Microsoft の XSLT プロセッサーで短縮形が使われるように処理されます。名前空間は使われていないため、タグ名には名前空間接頭辞はありません。

リスト 6. 名前空間を使用しない XSLT
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes"/>
    <!-- identity templates -->
    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="area[not(node())]|base[not(node())]|
        basefont[not(node())]|bgsound[not(node())]|br[not(node())]|
        col[not(node())]|frame[not(node())]|hr[not(node())]|
        img[not(node())]|input[not(node())]|isindex[not(node())]|
        keygen[not(node())]|link[not(node())]|meta[not(node())]|
        param[not(node())]">
        <!-- identity without closing tags -->
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|text()|comment()|processing-instruction()">
        <xsl:copy/>
    </xsl:template>
</xsl:stylesheet>

入力文書に名前空間が使われている場合 (リスト 7) には、XSLT には名前空間が必要であり、タグ名には接頭辞が必要になります。

リスト 7. 名前空間を使用する XHTML 入力文書
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
...
</html>

リスト 8 の XSLT はタグの突き合わせを行い、タグが自己終了でなければならないかどうかを判断しています。名前空間が使用されているため、タグ名には名前空間接頭辞が必要です。接頭辞がない場合には、タグが一致することはありません。XHTML の名前空間宣言が xmlns:htm で開始されていることに注意してください。接頭辞 (htm) は任意です。

リスト 8. 名前空間を使用する XSLT
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:htm="http://www.w3.org/1999/xhtml" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes"/>
    <!-- identity templates -->
    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="htm:area|htm:base|htm:basefont|
        htm:bgsound|htm:br|htm:col|htm:frame|htm:hr|htm:img|
        htm:input|htm:isindex|htm:keygen|htm:link|htm:meta|
        htm:param">
        <!-- identity without closing tags -->
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|text()|comment()|processing-instruction()">
        <xsl:copy/>
    </xsl:template>
</xsl:stylesheet>

他の XSLT プロセッサー

入力文書に名前空間が使用されていない場合 (リスト 9)、XSLT にも名前空間は必要ありません。

リスト 9. 名前空間を使用しない入力 XHTML 文書
<html>
...
</html>

リスト 10 の XSLT はタグの突き合わせを行い、タグが自己終了でなければならないかどうかを判断しています。別途終了タグが必要でありながら空のタグは、短縮形を使ってシリアライズされることがないように、半角スペースを付けて出力されます。例外は空の script 要素であり、この要素には JavaScript のコメント記号 (//) が追加されています。名前空間は使用されていないため、タグ名には名前空間接頭辞はありません。

リスト 10. 自己終了タグかどうかを突き合わせる XSLT
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes"/>

    <!-- identity templates -->
    <xsl:template match="*[not(node())]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:text> </xsl:text>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="script[not(node())]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:text>//</xsl:text>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="area[not(node())]|base[not(node())]|
        basefont[not(node())]|bgsound[not(node())]|br[not(node())]|
        col[not(node())]|frame[not(node())]|hr[not(node())]|
        img[not(node())]|input[not(node())]|isindex[not(node())]|
        keygen[not(node())]|link[not(node())]|meta[not(node())]|
        param[not(node())]">
        <!-- identity without closing tags -->
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|text()|comment()|processing-instruction()">
        <xsl:copy/>
    </xsl:template>
</xsl:stylesheet>

リスト 11 の XHTML 文書のように入力文書に名前空間が使われている場合、XSLT には名前空間が必要であり、またタグ名には接頭辞が必要です。

リスト 11. 名前空間を使用する入力 XHTML 文書
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
...
</html>

リスト 12 の XSLT はタグの突き合わせを行い、タグが自己終了でなければならないかどうかを判断しています。別途終了タグが必要でありながら空のタグは、短縮形を使ってシリアライズされることがないように、半角スペースを付けて出力されます。例外は空の script 要素であり、この要素には JavaScript のコメント記号 (//) が追加されています。名前空間が使用されているため、タグ名には名前空間接頭辞が必要です。接頭辞がない場合には、タグが一致することはありません。XHTML の名前空間宣言が xmlns:htm で開始されていることに注意してください。接頭辞 (htm) は任意です。

また、テンプレートにマイナスの優先度を指定することで、自己終了タグのための match 式を持つテンプレートの方がマイナスの優先度を指定したテンプレートよりも高い優先度を持つようになります。マイナスの優先度を指定しない場合には、自己終了タグのためのテンプレートは無視されます。

リスト 12. 名前空間を使用して自己終了タグかどうかを突き合わせる XSLT
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:htm="http://www.w3.org/1999/xhtml" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes"/>

    <!-- identity templates -->

    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="htm:area|htm:base|htm:basefont|
        htm:bgsound|htm:br|htm:col|htm:frame|htm:hr|htm:img|
        htm:input|htm:isindex|htm:keygen|htm:link|htm:meta|
        htm:param">
        <!-- identity without closing tags -->
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[not(node())]" priority="-0.5">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:text> </xsl:text>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="htm:script[not(node())]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:text>//</xsl:text>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|text()|comment()|processing-instruction()">
        <xsl:copy/>
    </xsl:template>
</xsl:stylesheet>

出力される名前空間を制御する

別の XML フォーマットに変換する場合など、出力から XHTML 名前空間を取り除くためには、<xsl:copy> ではなく <xsl:element> を使います (リスト 13)。

リスト 13. 出力の名前空間を取り除く XSLT テンプレート
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:htm="http://www.w3.org/1999/xhtml" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- identity templates -->
    <xsl:output method="xml" omit-xml-declaration="yes"/>

    <xsl:template match="*">
        <xsl:element name="{name()}">
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="htm:area|htm:base|htm:basefont|
            htm:bgsound|htm:br|htm:col|htm:frame|htm:hr|
            htm:img|htm:input|htm:isindex|htm:keygen|
            htm:link|htm:meta|htm:param">
        <!-- identity without closing tags -->
        <xsl:element name="{name()}">
            <xsl:apply-templates select="@*"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="*[not(node())]" priority="-0.5">
        <xsl:element name="{name()}">
            <xsl:apply-templates select="@*"/>
            <xsl:text> </xsl:text>
        </xsl:element>
    </xsl:template>

    <xsl:template match="htm:script[not(node())]">
        <xsl:element name="{name()}">
            <xsl:apply-templates select="@*"/>
            <xsl:text>//</xsl:text>
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*|text()">
        <xsl:copy/>
    </xsl:template>

    <xsl:template match="comment()">
        <xsl:comment xml:space="preserve">
            <xsl:value-of select="."/>
        </xsl:comment>
    </xsl:template>

    <xsl:template match="processing-instruction()">
        <xsl:processing-instruction name="{name()}">
            <xsl:value-of select="."/>
        </xsl:processing-instruction>
    </xsl:template>
</xsl:stylesheet>

ソリューション: XSLT 2.0 を使用する

XSLT 2.0 の場合には、xhtml という別のメソッドを利用することができます。xhtml は名前からもわかるように、適切に閉じられた空の XTHML タグを生成するという問題を解決することができます。入力文書に名前空間が適用される場合には、その名前空間を xpath-default-namespace 属性の中で指定する必要があります。リスト 14xsl:output タグの method 属性と xpath-default-namespace 属性を示しています。

XSLT 2.0 を使用するためには、XSLT 2.0 をサポートする XSLT プロセッサー (Saxon など) を使用します。現時点では、Microsoft のプロセッサーは XSLT 2.0 をサポートしていません。

リスト 14. XSLT 2.0
<?xml version="1.0" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xhtml" 
            xpath-default-namespace="http://www.w3.org/1999/xhtml"/>

    <!-- put your templates here -->

    <!-- identity templates -->

    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|text()|comment()|processing-instruction()">
        <xsl:copy/>
    </xsl:template>
</xsl:stylesheet>

XSLT 2.0 において出力の名前空間を制御する

別の XML フォーマットに変換する場合など、出力から XHTML 名前空間を取り除くためには、<xsl:copy> タグではなく <xsl:element> タグを使います (リスト 15)。

リスト 15. 出力の名前空間を取り除く XSLT 2.0 テンプレート
<?xml version="1.0" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xhtml" 
            xpath-default-namespace="http://www.w3.org/1999/xhtml"/>

    <!-- put your templates here -->

    <!-- identity templates -->

    <xsl:template match="*">
<xsl:element name="{name()}">
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="node()"/>
</xsl:element>
    </xsl:template>

    <xsl:template match="@*|text()|comment()|processing-instruction()">
        <xsl:copy/>
    </xsl:template>
</xsl:stylesheet>

まとめ

開始タグの種類に応じて、別の終了タグを使うか、自己終了タグにすることで、XHTML のタグを適切に閉じる必要があります。XSLT 変換によって XHTML を生成する場合、タグの閉じ方を制御する方法は XSLT プロセッサーに依存します。複雑ではあっても汎用のソリューションとしては、シリアライズ・メソッドを作成します。他のソリューションとして、XSLT 1.0 を使用する場合には、特定の方法で XSLT テンプレートをコーディングします。何と言っても最も容易なソリューションは、XHTML をネイティブでサポートしている XSLT 2.0 を使用する方法です。

参考文献

学ぶために

製品や技術を入手するために

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Web development
ArticleID=651193
ArticleTitle=ヒント: XSLT の識別テンプレートを使って XHTML を変換する
publish-date=12212010