第20回 DTDで指定範囲の有効/無効を切り替える

XML 1.0は、1998年にW3Cから勧告として公開された。当然中身は英語で、しかもEBNFと呼ばれる式によって重要な部分が記述してある。この連載では、XML 1.0を深く理解するために、そのXML 1.0勧告の最新版「Extensible Markup Language (XML) 1.0 (Third Edition)」をだれでも分かるように、やさしく読み解きながら解説していくことを目指している。(編集局)

川俣 晶
株式会社ピーデー
2004/4/7



条件付きセクションの用途
今回の主な内容
条件付きセクションの用途
条件付きセクションの概要
条件付きセクションの定義
条件付きセクションのEBNF定義
条件付きセクションのEBNF定義(妥当性制約)
条件付きセクションの解説文
条件付きセクションの使用例

 前回は、「3.3.3 Attribute-Value Normalization(3.3.3 属性値の正規化)」について読んだ。ここは、知らないと落とし穴になる可能性のある重要な個所である。例えば、要素の内容として記述した文字列と、属性値として記述した文字列の扱いは常に同じではない。XMLによって作られた言語では、属性で記述しても要素で記述しても同じ、と見なして扱う場合もあるのだが、すべてのケースでうまくいくわけではない。また、属性の型を変更するだけで、同じXML文書から取得される属性値が変わってしまうケースもある。

 さて今回は、「条件付きセクション」を解説する。これはベテランが作成したDTDにしばしば顔を出す機能で、DTDの一部の有効、無効を容易に切り替えられる。しかし、この切り替えは、条件付きセクションだけでは実現されず、パラメタ実体との併用が不可欠である。それ故に、XML勧告の条件付きセクションの部分を読んでも使い方がよく分からず、取っつきにくい機能の1つといえる。今回は、そのあたりの問題を解消するために、XML勧告に書かれていないバックグラウンドなどの説明も多めに入れてみた。これで、多少なりとも条件付きセクションへの理解が進むことを願うものである。

編集注:この連載では、XML 1.0勧告であるW3Cの「Extensible Markup Language (XML) 1.0 (Third Edition)」(英語)を参照し、その日本語訳として、日本工業規格 JIS X 4159:2002(Second Edition相当。リンク先は該当規格の原案ですが、最終版とほぼ同等の内容です)と追補1として出版予定の原稿(Third Edition対応)を参照しています。本文中のピンクの地の部分は、XML 1.0勧告の原文を示しています。


条件付きセクションの概要

 さて、「3.4 Conditional Sections(3.4 条件付きセクション)」を読んでいこう。これは、仕様書を読んだだけでは何に使うのかピンとこない典型的な機能の例といえる。実際にどう使うかは、最後に掲載されている例で示されているのだが、それが何を意図したものであるかの説明はない。かなり想像力を働かせないと、予備知識なしでこの例から意図を読み取ることは難しい。それだけでなく、読み取った意図が本当に正しい意図であるかどうか、確実ではない。

条件付きセクションの意図

 話の順番を少し入れ替えるが、先に、条件付きセクションが意図するものを説明しておこう。

 プログラミングやHTML文書の作成などで、一時的にある範囲の機能の有効/無効を切り替えたい場合がある。以下に簡単な一例を示す。HTML文書を扱っている場合にしばしば経験することだが、一時的に入力欄の一部をなかったことにして動作させたい場合がある。以下のようなinput要素が並んだHTML文書があるとしよう。

        <INPUT id="Text1" type="text" name="Text1">
        <INPUT id="Text2" type="text" name="Text2">
        <!-- コメント -->
        <INPUT id="Text3" type="text" name="Text3">

 ここで、Text2というIDを持ったinput要素を一時的にないこととして扱いたい場合は、以下のようにinput要素をコメントの中に入れてしまえばよい。

        <INPUT id="Text1" type="text" name="Text1">
        <!--<INPUT id="Text2" type="text" name="Text2">-->
        <!-- コメント -->
        <INPUT id="Text3" type="text" name="Text3">

 このテクニックをコメントアウトという。

コメントアウトの限界

 コメントアウトは、さまざまなジャンルでよく使われるテクニックであり、もちろん、XMLのDTDの内部でも使用できる。一時的にDTDの一部の機能を有効にしたり、無効化する切り替えに使える。しかし、コメントアウトは万能ではない。コメントアウトで対処できない例をHTML文書を例に見てみよう。もし、上記の例でText2というIDを持ったinput要素だけでなく、Text3というIDを持ったinput要素も同時にコメントアウトする必要が発生したとしよう。以下のような記述を試みたとする。

        <INPUT id="Text1" type="text" name="Text1">
        <!--<INPUT id="Text2" type="text" name="Text2">
        <!-- コメント -->
        <INPUT id="Text3" type="text" name="Text3">-->

 これはうまく機能しない。Text3というIDを持ったinput要素は依然として有効のままであるだけでなく、その後に余計な「-->」という文字列まで表示されてしまう。そのような結果になる理由は、コメントはネスト(入れ子に)できないという単純な制約による。つまり、<!-- コメント -->という行の最後の-->がコメントの終わりを示すため、コメントはここで終わってしまうのである。その結果、Text3というIDを持ったinput要素はコメントが終わった後に記述されたものと見なされ、当然、その後の「-->」という文字列も通常の文書の一部と見なされる。

 このような問題が発生するため、コメントアウトというテクニックは万能とはいえない。通常のHTML文書なら、コメントを入れることは多くないので何とかなるかもしれない。しかし、DTDでは話が変わる。多くのDTDは、さまざまなコメントが書き込まれている。

 例えば、XHTML 1.1のDTDから、特にコメントが頻出する個所を引用してみよう。

<!ENTITY iexcl  "&#161;"> <!-- inverted exclamation mark, U+00A1 ISOnum -->
<!ENTITY cent   "&#162;"> <!-- cent sign, U+00A2 ISOnum -->
<!ENTITY pound  "&#163;"> <!-- pound sign, U+00A3 ISOnum -->
<!ENTITY curren "&#164;"> <!-- currency sign, U+00A4 ISOnum -->
<!ENTITY yen    "&#165;"> <!-- yen sign = yuan sign, U+00A5 ISOnum -->

 このような宣言を数行まとめてコメントアウトしようとするだけで、かなり困った事態になる。

 毎行コメントが入るのは、最も極端な部分としても、数行ごとにコメントが入るのは珍しくもない。そのようなDTDの20〜30行ぐらいを一時的に無効にしようと思うと、1つのコメントアウトで対処することはほぼ不可能といえる。もし、対処しようとすると、複数の範囲に分けて、個別にコメントアウトする必要がある。

 このような問題は、Cなどのプログラム言語にも存在する。例えば、Cのコメントは「/*」より始まり「*/」で終わる。そのため、コメント内に「*/」を含められず、コメントを含む範囲をコメントアウトできない。

条件付きコンパイルのメリット

 このような問題に対処するために、Cには条件付きコンパイルという機能を使用できる。これは、ある範囲の行の有効/無効を指定する機能で、よく使われる定番機能といえる。類似の機能は、C++やC#にもある(Javaにはない)。条件付きコンパイルは、ある範囲の行の有効/無効を指定するもので、コメントとは異なるため、コメントが含まれていても有効に機能する。

 コメントアウトには、もう1つの問題がある。それは、安全にスイッチをオン/オフするように、有効/無効を切り替えられないことである。コメントアウトは、ソースを書き換えてDTDの一部をコメント化することによって無効化し、コメントの構文を取り除くことで有効化するやり方であるため、無効化した後に有効化すると、無効化したときにどの範囲を無効化したのかの情報が残らない。そのため、再度無効化しようとした場合、確実に同じ範囲をコメントアウトするには、細心の注意を要する。

 この問題は、条件付きコンパイルでは解決されている。条件付きコンパイルでは、あらかじめ範囲を指定しておき、スイッチを切り替えるようにオン/オフを入れ替えられる。範囲の指定とスイッチの指定は独立しており、スイッチの切り替えで範囲指定が変更される気遣いはない。

 この条件付きコンパイルに近い性格を持つ機能が、ここで規定されている条件付きセクションである。条件付きセクションはDTD内の指定範囲を有効化したり、無効化する機能を持つ。そして、パラメタ実体を併用することにより、範囲指定とは独立した形で、有効/無効を切り替えるスイッチを用意することができる。ここで注意すべきことは、パラメタ実体を併用することによりという部分である。条件付きセクションだけでは実現されない機能であるため、条件付きセクションの規定の中では明示的に使い方が説明されていない。その部分は、随時解説を補足しながら読んでいこう。

条件付きセクションの定義

 それでは勧告の本文を読み始めよう。

[Definition: Conditional sections are portions of the document type declaration external subset or of external parameter entities which are included in, or excluded from, the logical structure of the DTD based on the keyword which governs them.]

[定義:条件付きセクションとは、文書型宣言の外部サブセットの一部または外部パラメタ実体の一部であって、制御キーワードの指定によって、DTDの論理構造に含まれるかまたは除かれるかが変わる部分とする。]


 JIS X 4159では明確に読み取れないが、Conditional sections(条件付きセクション)という用語の定義となる文章である。

 ここに記述された情報は、主に2つに分けられる。前半は、条件付きセクションを記述できる場所である。1つは、文書型宣言の外部サブセットの一部。もう1つは外部パラメタ実体の一部である。文書型宣言の外部サブセットとは、マーク付け宣言を含んだ特別な種類の外部実体である。一般的にXML文書の外部に用意されるDTDがこれに当たる。外部パラメタ実体とは、パラメタ実体参照で参照される外部実体である。これらに条件付きセクションを記述できるということは、裏を返せば、内部サブセットには記述できないということを意味する。

 後半は、条件付きセクションの機能性についての規定である。まず「制御キーワードの指定によって」という部分に注目しよう。これは、うっかりすると見落としがちだが、重要なポイントである。この後で「DTDの論理構造に含まれるかまたは除かれるか」と書かれた選択のスイッチとして、制御キーワードの指定が機能するということである。条件付きセクションは、漫然と読むと、含めるためのINCLUDE構文と、含めないためのIGNORE構文の2つがあるかのように見えるが、この機能を用意した意図としては、決して2つの独立した構文を用意することではなく、制御キーワードによってスイッチ可能な事実上1種類の構文を用意することだったといえる。

 最後に「DTDの論理構造に」という部分にも注意を払っておこう。まず、この部分から、条件付きセクションはDTDで使われるものだということが分かる。DTD以外では使用できない。例えば、XML文書内の通常のテキストを含めるか含めないかを指定するためには使えない。そして「論理構造」という言葉は、文字列に対して作用するのではない、という意図が表現されている。例えば、XMLのパラメタ実体は文字列に対して作用するものであるため、さまざまな宣言の一部だけをパラメタ実体で表記可能であった。また、Cの条件付きコンパイルの機能は、ソースコードの文字列の有効/無効を指定するものであって、ソースコードの論理的な機能の単位とは関係なく指定できた。しかし、条件付きセクションはこれらとは異なる。

条件付きセクションのEBNF定義

 次は、条件付きセクションのEBNFによる定義である。

Conditional Section
[61]    conditionalSect    ::=    includeSect | ignoreSect
[62]    includeSect    ::=    '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>' [VC: Proper Conditional Section/PE Nesting]
[63]    ignoreSect    ::=    '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>' [VC: Proper Conditional Section/PE Nesting]
[64]    ignoreSectContents    ::=    Ignore ('<![' ignoreSectContents ']]>' Ignore)*
[65]    Ignore    ::=    Char* - (Char* ('<![' | ']]>') Char*)

 まず、生成規則[61] conditionalSectは、条件付きセクションそのものについての定義である。内容は単純で、生成規則[62] includeSect生成規則[63] ignoreSectのどちらか1つになる。この2つは、この後すぐに登場するので説明は横に置いて、生成規則[61] conditionalSectがどこから参照されているか見てみよう。調べてみると、以下の生成規則[31] extSubsetDeclから参照されていることが分かる。

[31] extSubsetDecl ::= ( markupdecl | conditionalSect | DeclSep)*

 生成規則[31] extSubsetDeclは、外部サブセットの本体の定義である。マーク付け宣言(markupdecl)、条件付きセクション(conditionalSect)、パラメタ実体参照または空白(DeclSep)のいずれかを0回以上繰り返すという定義である。ここから、外部サブセットの中に条件付きセクションを記述できるという意図を読み取れる。

 次は、生成規則[62] includeSectである。これは、'<!['で始まり、省略可能な空白があり、'INCLUDE'という文字列があり、省略可能な空白があり、'['があり、生成規則extSubsetDeclがあり、']]>'という文字列を記述して終わることを示している。生成規則extSubsetDeclは上述の[31] extSubsetDeclそのものである。つまり、extSubsetDeclの中に、またextSubsetDeclが許されるというネスト(入れ子)の構造があり得る。この生成規則は、以下のような文字列を有効とする(……の部分は生成規則[31] extSubsetDeclを満たす文字列が入るものとする)。

<![INCLUDE[……]]>

 ネスト(入れ子)を許可していることから、以下のような文字列でも有効である。

<![INCLUDE[<![INCLUDE[<![INCLUDE[……]]>]]>]]>

 このことは、コメントと条件付きセクションの性質の違いを表す重要なポイントといえる。コメントはネスト(入れ子に)できないため、コメントアウトというテクニックでコメントを含む領域を対象とすることはできなかった。条件付きセクションは、コメントではないので、コメントを含む領域を対象としても問題にならないことはすでに説明した。しかし、条件付きセクションは、それだけではなく、条件付きセクションを含んだ領域を条件付きセクションの対象とできる

 例えば、名簿を記述するDTDがあったとき、その中で人名のミドルネームを記述する要素を使うか使わないかを条件付きセクションで指定できるようになっていたとする。そこで、さらに条件付きセクションを含む人名の定義そのものを、さらに条件付きセクションで有効/無効を指定するように書き加えることができ、それは機能するということである。自分自身のネスト(入れ子)が可能であるという点で、コメントと条件付きセクションは性質が異なる。

 さて、これがどんな機能を指定するものであるかの説明は、後で出てくる。ここでは、それを知りたい欲求をグッと我慢して、EBNFを読み進もう。

 次は、[63] ignoreSectである。これは、キーワードが'INCLUDE'ではなく'IGNORE'であること。参照される生成規則がextSubsetDeclではなくignoreSectContents*であることを除けば同じ内容となっている。ここで、ignoreSectContents*と最後に*が付いて、0回以上繰り返し可能であることを確認しよう。ignoreSectContentsは、次の生成規則である。

 さて、次の生成規則[64] ignoreSectContentsであるが、これはこれまでとはやや趣が異なる。まず、生成規則[65] Ignoreがあり、次に0回以上繰り返される範囲が指定されている。その範囲の内側は、文字列'<!['があり、生成規則[64] ignoreSectContentsがあり、文字列']]>'があり、生成規則[65] Ignoreで終わる。生成規則[64] ignoreSectContentsとはこの生成規則自身のことである。つまりネスト(入れ子)が実現されている。では、生成規則[65] Ignoreとは何かというと、次の生成規則がそれに当たる。

 次の生成規則[65] Ignoreは、また少々ややこしい形をしている。生成規則[2] Charの0回以上の繰り返しだが、後半に書かれたものが除外される。除外されるのは、生成規則[2] Charの0回以上の繰り返し、文字列'<!['または']]>'、生成規則[2] Charの0回以上の繰り返し、という文字列である。EBNFで書くとややこしいが、要するに文字列'<!['または']]>'を含まない文字列という意図を表現している。

 では、生成規則[64] ignoreSectContentsと生成規則[65] Ignoreを合わせると、どんな意図を表現しているのだろうか。この2つに共通することは、文字列'<!['と']]>'が特別扱いされ、そのほかの文字は特別扱いされていないことである。生成規則[65] Ignoreにこれらは含まれていないので、生成規則[64] ignoreSectContentsに適合する文字列に含まれる文字列'<!['と']]>'は、すべて生成規則[64] ignoreSectContentsに直接書かれた文字列'<!['と']]>'に対応することになる。それが何を意味するかといえば、文字列'<!['があれば、その後に、必ず対応する文字列']]>'がある、という絶対的な対応関係を意味する。ネスト(入れ子)になることはできるが、'<!['と']]>'の数は必ず同数になる

 この生成規則によって、ネスト(入れ子)になった条件付きセクションを正しく扱うことが可能となる。つまり、コメントは、文字列'-->'に出合うとそこでコメントの終わりと認識するのに対して、条件付きセクションは文字列']]>'に出合ったからといって、そこで条件付きセクションの終わりと見なすとは限らないということである。もし、文字列'<!['に10回出合っていれば、文字列']]>'にも10回出合わなければ、条件付きセクションは終わらないのである。

条件付きセクションのEBNF定義(妥当性制約)

 次は、これらのEBNFに付く妥当性制約についての規定が続く。

Validity constraint: Proper Conditional Section/PE Nesting

If any of the "<![", "[", or "]]>" of a conditional section is contained in the replacement text for a parameter-entity reference, all of them MUST be contained in the same replacement text.

妥当性制約:条件付きセクション/パラメタ実体が厳密に入れ子をなすこと

条件付きセクションの"<![", "["または"]]>"のいずれかがパラメタ実体参照の置換テキストに含まれるなら、すべてが同一のパラメタ実体の置換テキストに含まれなければならない。

 これは、「妥当性制約: Proper Conditional Section/PE Nesting(条件付きセクション/パラメタ実体が厳密に入れ子をなすこと)」である。MUSTが使われているとおり、絶対的な制約である。

 ここで気になるのは、EBNFでは文字列"<!["と"]]>"だけが特別扱いされていたのに対して、ここではそれに加えて"["も含まれていることである。この"["は、<![INCLUDE[……]]>と書いたときの、"!"と"INCLUDE"の間の"["である。この"["も含め、"<!["と"]]>"は同一のパラメタ実体の置換テキストに含まれていなければならない。

 そう考えると分かりにくいが、(不正確ではあるが)裏から考えると分かりやすいかもしれない。つまり、<![……[……]]>という条件付きセクションの構文の中で、……の部分だけがパラメタ実体参照として記述できる、と考えるわけである。前の……は'INCLUDE'または'IGNORE'に相当する部分であり、条件付きセクションの種類を選択するものである。そして、後の……は条件によって有効/無効を切り替える対象となるものである。つまり、前はスイッチ、後はスイッチによって切り替えられるものである。この2つを同じパラメタ実体参照によって表記することは、あまり意味がないことだろう。

条件付きセクションの解説文

 次は、EBNFの解説的な文が続く。

Like the internal and external DTD subsets, a conditional section may contain one or more complete declarations, comments, processing instructions, or nested conditional sections, intermingled with white space.

条件付きセクションは、DTDの内部サブセットおよび外部サブセットと同様に、完全な宣言、コメント、処理命令または入れ子になった条件付きセクションを、いくつか含んでよい。これらの間に、空白が現れてもよい。

 これはすでに述べたことの繰り返しとなる。ただ「DTDの内部サブセットおよび外部サブセットと同様に」という部分が新しいニュアンスを示している。条件付きセクションの内部は、DTDの内部サブセットや外部サブセットと同様に記述できるものである。そう書くとありがたみが分かりにくいが、これも裏から読むとよいだろう。つまり、同様であるため、通常のDTDの一部を、条件付きセクションの内側に入れることができる、ということである。

 次は、文字列'INCLUDE'と'IGNORE'についての説明である。

If the keyword of the conditional section is INCLUDE, then the contents of the conditional section MUST be considered part of the DTD. If the keyword of the conditional section is IGNORE, then the contents of the conditional section MUST be considered as not logically part of the DTD. If a conditional section with a keyword of INCLUDE occurs within a larger conditional section with a keyword of IGNORE, both the outer and the inner conditional sections MUST be ignored. The contents of an ignored conditional section MUST be parsed by ignoring all characters after the "[" following the keyword, except conditional section starts "<![" and ends "]]>", until the matching conditional section end is found. Parameter entity references MUST NOT be recognized in this process.

条件付きセクションのキーワードがINCLUDEならば、条件付きセクションの内容はDTDの一部と見なさなければならない。条件付きセクションのキーワードがIGNOREならば、条件付きセクションの内容は論理的にはDTDの一部と見なしてはならない。キーワードをINCLUDEとする条件付きセクションが、キーワードをIGNOREとするより大きな条件付きセクションに含まれるならば、外側および内側の条件付きセクションの両方とも無視しなければならない。無視される条件付きセクションの内容を解析するとき、キーワードに続く"["の後のすべての文字は、条件付きセクションを開始する"<!["と終了する"]]>"を除き、この条件付きセクションの終了が見つかるまで無視する。この処理において、パラメタ実体参照は認識してはならない。

 少し長いが、順番に見ていこう。最初の文はMUSTであり、必須の要求である。「一部と見なす」ということは、有効/無効を切り替える機能のうち、「有効」という役目を担当することを意味している。

 次もMUSTである。見なしてはならないということは、「無効」という役目を担当することを意味している。

 次もMUSTである。これは以下のような条件付きセクションがあった場合の話である。

<![IGNORE[……<![INCLUDE[……]]>……]]>

 この場合、外側の条件付きセクションが無効を、内側の条件付きセクションが有効を指定している。しかし、この場合、外側の条件付きセクションで無効とされた場合は、内側の条件付きセクションが有効と主張してもそれも含めて無効とされるのである。このことは、EBNFの定義を思い返せば必然であることが分かるだろう。IGNOREの条件付きセクションの内部の生成規則は、文字列"<!["と"]]>"だけを特別扱いし、ほかの文字はすべて一律に扱うようになっている。つまり、IGNOREの条件付きセクションの内部に条件付きセクションがあったとしても、それは構文上条件付きセクションとして認識されることはなく、たとえINCLUDEと書かれていても、それは何の意味も発揮し得ない。

 次はEBNFの定義の言い直しのようにも見えるが、1つだけ重要な追加情報がある。それは「特別扱いする2つの文字列以外はすべて無視する」という部分である。これらの文字は一切意味を持たず、XMLプロセサから認識もされないことになる。

 最後もMUSTである。この処理とは無視する処理のことだが、無視する対象の文字列にパラメタ実体参照が含まれることは、十分にあり得る事態である。これを展開してから無視するか、それともパラメタ実体参照そのものを無視するかは、どちらでも同じ結果であるように思えるかもしれない。しかし、パラメタ実体参照に何らかの誤りが含まれた場合、エラーメッセージを見るか否かという相違が発生し、両者の結果は同じにならない。ここでは、パラメタ実体参照を必ず認識しない、と規定することによって、結果の違いが出ないようにしている。この規定によって、エラーになるはずのパラメタ実体参照を、一時的に条件付きセクションに入れることで、エラーを起こさせずに使うことが可能となる。プログラム言語でも、現在は存在しない機能へアクセスするコードを条件付きコンパイルの機能によって無効化し、エラーにならないようにすることと同様の使い方ができる。

 次は、キーワードとなる文字列'INCLUDE'と'IGNORE'についての規定である。

If the keyword of the conditional section is a parameter-entity reference, the parameter entity MUST be replaced by its content before the processor decides whether to include or ignore the conditional section.

条件付きセクションのキーワードがパラメタ実体参照ならば、XMLプロセサは条件付きセクションを取り込むか無視するかを判断する前に、このパラメタ実体を展開しなければならない。

 これもMUSTである。これこそが、非常に回りくどい形で、条件付きセクションの最も重要な使い方を示している。つまり、条件付きセクションのキーワードは通常パラメタ実体として記述しておき、パラメタ実体の置換テキストの文字列を'INCLUDE'と'IGNORE'を切り替えることで、条件付きセクションの有効/無効を切り替えるスイッチとして使うのである。そして、これがパラメタ実体を併用することにより条件付きセクションが有効に活用可能となるという理由である(ここでパラメタ実体の宣言は上書きできることを思い出してほしい。つまり、DTDに書かれた置換テキストを上書きして、機能を切り替えることも可能なのである)。

 このような条件付きセクションの活用事例は、あちこちで見られる。例えばXHTML 1.1のDTDには以下のような記述が見られる。

<![%XHTML.prefixed;[
<!ENTITY % XHTML.pfx "%XHTML.prefix;:" >
]]>

 これは、条件付きセクションにより、内部の宣言の有効/無効を切り替え可能とした例である。ここには、INCLUDEともIGNOREとも書かれていないため、これが条件付きセクションの利用例であることはパッと見ても分かりにくい。しかし、これこそが、典型的な条件付きセクションの使い方である。このXHTML.prefixedというパラメタ実体は以下のように宣言されている。

<!ENTITY % NS.prefixed "IGNORE" >
<!ENTITY % XHTML.prefixed "%NS.prefixed;" >

 つまり、これはIGNOREという置換テキストを持っていて、このDTDをそのまま使うと、条件付きセクション内の実体宣言は無視される。しかし、パラメタ実体を変更することによって有効化することもできる。

条件付きセクションの使用例

 最後に条件付きセクションの使用例が記述されている。

An example:

<!ENTITY % draft 'INCLUDE' >
<!ENTITY % final 'IGNORE' >

<![%draft;[
<!ELEMENT book (comments*, title, body, supplements?)>
]]>
<![%final;[
<!ELEMENT book (title, body, supplements?)>
]]

 ここまでの説明を読んでいれば、この例が何を意味しているか分かるだろう。ここでは、パラメタ実体のdraftとfinalが、条件付きセクションの有効/無効を切り替えるスイッチとして機能している。

 これは文書のドラフト版のときと、ファイナル版のときでは、文書の内容を変えたい、という意図を持ったDTDのように思える。ドラフト版が有効の場合は、commmentsという要素をbook要素の子要素として記述できる。これは編集段階のコメントを文書に書き込めるようにするためだろう。しかし、ファイナル版では編集用のコメントを残すことは間違いとなるので、comments要素は許されていない。この例では、パラメタ実体draftの置換テキストが'INCLUDE'で、パラメタ実体finalの置換テキストが'IGNORE'であるため、DTDはドラフト版として機能する。しかし、パラメタ実体draftの置換テキストが'IGNORE'で、パラメタ実体finalの置換テキストが'INCLUDE'と変更すれば、ファイナル版のDTDとして機能する。

 さて、以上で「3.4 Conditional Sections(3.4 条件付きセクション)」の説明は終わりである。また、「3 Logical Structures(3 論理構造)」も読み終わった。次回からは、新しい世界「4 Physical Structures(4 物理構造)」に足を踏み入れる。XML勧告は6章まであるが、6章は先に読んでいるので、(附属書を別にすれば)残りは4章と5章だけということになる。あと一息で終わりそうだが、なかなかに4章は難物である。これを乗り越えて、ぜひともXML勧告を読み切ろう。

連載 やさしく読む「XML 1.0勧告」


XML & SOA フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日月間