第7回 XMLで使ってもいい文字データとコメント

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

川俣 晶
株式会社ピーデー
2003/3/6



なぜエラーになるか分かる
今回の主な内容
なぜエラーになるか分かる
文字データとマーク付け(前回の続き)
“&”と“<”の使い方
SGMLとの互換性に関する“>”
要素とCDATA内の文字データ
引用符の使い方
コメントの書き方
コメントのBNF表記

 今回は、W3CによるXML 1.0勧告の中で、「2 Documents(文書)」の中の「2.4 Character Data and Markup(文字データ及びマーク付け)」の途中から、「2.5 Comments(コメント)」までを解説する。

 「2 Documents」は、XML文書の基本的な構造について述べている部分である。その中で、「2.4 Character Data and Markup」の方は、文字データとマーク付けの基本的な説明が行われている。マーク付けに使用される特別な役割を持つ文字と文字データの関係などが説明されている。

 「2.5 Comments(コメント)」では、データ本体ではなく補足的な説明をXML文書に書き込むためのコメントについて記述されている。コメントは、一見簡単そうではあるが、コメント中に書き込むことができない特別な文字列“--”の扱いについて慎重に見ておく必要がある。

 このあたりの説明は、ある意味でささいな重箱の隅のような話ばかりともいえる。しかし、まったく知らなくてよいというものではない。XML文書の本文中に“]]>”という文字列をたまたま書く場合や、コメントの最後の文字がたまたま“-”記号になった場合など、意図しないエラーに遭遇する可能性はあり得る。その場合には、今回書いたような内容が、なぜエラーになるのかを知るための手掛かりとなるだろう。併せて、対策方法も分かるはずだ。

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

文字データとマーク付け(前回の続き)

 さて、前回の続きとして、XML 1.0勧告の「2.4 Character Data and Markup」を読むことを再開しよう。ここでは、文字データとマーク付けに関する説明が記述されている。

 以下は、XML 1.0勧告のcharacter data(文字データ)の定義についてである。

[Definition: All text that is not markup constitutes the character data of the document.]

 マーク付けではないすべてのテキストは、character data(文字データ)を構成する、とある。ここで重要なことは、「マーク付け」と「テキスト」と「文字データ」の相違をしっかり把握することである。テキストはマーク付けであったり、文字データであったりする。例えば、

  <element>characters</element>

というのは一種の「テキスト」である。この中で、開始タグや終了タグが「マーク付け」の部分に当たるのは、すぐに分かるだろう。そして、マーク付けではない部分、つまり上の例でcharactersと記述された部分が「文字データ」であるということである。しかし、文字データとして扱われるべきものがすべて文字データであると考えるのは早計である。というのは、例えば“&lt;”と実体参照を書いたときに、意図したのは“<”という1文字を書き込むことであるが、この実体参照はマーク付けであって文字データではない。

“&”と“<”の使い方

 次は、特別な記号であるアンパサンド(&)と不等号(<)が、そのままの形で出現してよい条件に関する説明だ。

The ampersand character (&) and the left angle bracket (<) may appear in their literal form only when used as markup delimiters, or within a comment, a processing instruction, or a CDATA section. If they are needed elsewhere, they must be escaped using either numeric character references or the strings "&amp;" and "&lt;" respectively. The right angle bracket (>) may be represented using the string "&gt;", and must, for compatibility, be escaped using "&gt;" or a character reference when it appears in the string "]]>" in content, when that string is not marking the end of a CDATA section.

 最初に、“&”と不等号“<”は、次の条件の場合にそのままの形で出現してよいとしている。その条件とは、マーク付けの区切り子として使用する場合、そしてコメント、処理命令CDATAセクション内で使用する場合だけである。逆にいえば、これに該当しない個所では、この2つの記号はそのままの形で出現してはならないということになる。つまり、定義済み実体の参照などの形を取る必要がある。別のいい方をすれば、もしこの2つの記号がそのままの形で出現すると、意図しない文字として認識されたり、構文エラーを発生させることになるわけである。

 次には、そのままの形ではない書き方について説明が行われている。この2つの文字が、上記の個所以外で必要なときには、番号による文字参照か、文字列“&amp;”と文字列“&lt;”を使用してエスケープしなければならないとしている。ここでは文字列“&amp;”というように文字列と表記しているが、もちろんこれは定義済み実体の参照である。

SGMLとの互換性に関する“>”

 次は、もう1つの不等号(>)に関する説明である。ここは、主にSGMLとの互換性を意識しなければ、さほど注意を払う必要はないだろう。まず、“>”は文字列“&gt;”を使用して表現してもよい、としている。「してもよい」ため、必須ではない。実際には“>”を“&gt;”と書かなければ正しく処理されない、という状況に出合うことはほとんどないだろう。しかし、SGMLとの互換性の問題を解決する場合には“&gt;”と書く必要が生じる。その問題の具体的な内容は次のように書かれている。文字列“]]>”を使用するとき、それがCDATAセクションの終了のマーク付けではない場合には、“>”を“&gt;”または文字参照を使用してエスケープしなければならない。

 これはSGMLとの互換性のための規定であるため、XMLパーサを通すときには守らなくても通るような気もするが、実際に以下のXML文書をInternet Explorer 6.0に読み込ませてみるとエラーになった。

  <a>]]></a>

 これを実体参照に置き換えて以下のように書き直すと正常に通った。

  <a>]]&gt;</a>

 このことから考えると、SGMLとの互換のための規定であっても、それを守ってXML文書を作成しておく方が安全といえるだろう。

要素とCDATA内の文字データ

 次は、要素と、CDATAセクション内の文字データの条件である。

In the content of elements, character data is any string of characters which does not contain the start-delimiter of any markup. In a CDATA section, character data is any string of characters not including the CDATA-section-close delimiter, "]]>".

 ここではまず、要素についての話が書かれている。要素の内容では、マーク付けの開始区切り(delimiter)を含まないどんな文字列も、文字データであるとしている。ちょっと分かりにくいかもしれない。例えば、

  <a>A<b>B</b>C</a>

というXML文書があったとき、要素aの内容は

  A<b>B</b>C

となる。この内容を見るとマーク付けの開始区切りである“<”を含むので、A、B、Cといった文字も文字データと見なされないように思えるかもしれない。しかしこの場合は(開始区切りを含む)マーク付けの部分は除いて、A、B、Cといった文字は文字データである。つまり上記の説明は、要素の内容の文字データにはマーク付けの開始区切りが含まれてはならないことを記述しているのであって、それ以外の意図を記述しているわけではないのである。

 続いてCDATAセクションについての話が書かれている。CDATAセクションでは、CDATAセクションの終了区切り“]]>”を含まない任意の文字列が、文字データを構成するとしている。話は、要素の場合と似ているが、CDATAセクションの中にはマーク付けを記述できないので、条件が異なっている。CDATAセクションで特別な意味を持つのは終了を意味する“]]>”だけである。この話題は、この後のCDATAセクションについての説明で再度出てくる。

引用符の使い方

 次は、引用符の使い方について記述している。

To allow attribute values to contain both single and double quotes, the apostrophe or single-quote character (') may be represented as "&apos;", and the double-quote character (") as "&quot;".

 ここでは、属性の値に、引用符を含める方法について説明している。XMLの属性の値は常に引用符でくくる必要があるので、引用符でくくった値の中に同じ引用符を書くと混乱することになる。この問題は重要である。ここでは、属性値が一重引用符(')および二重引用符(")を含むためには、一重引用符とアポストロフィ(')は“&apos;”として表現し、二重引用符(")は“&quot;”として表現する、としている。ここで注意することは、この文章は属性の値を書く場合の話をしているだけで、“&apos;”や“&quot;”は属性の値でのみ使われる実体参照ではない、ということである。これらは要素内容のテキストで使用しても問題ないものである。しかし、これらの実体参照を使う意義があるのは、属性の値を記述する場合である。その場合でも、属性の値を区切る引用符と異なる引用符を書き込む場合には、実体参照は必要ない。

 次は文字データのEBNF表記である。

Character Data
[14]    CharData    ::=    [^<&]* - ([^<&]* ']]>' [^<&]*)

 ただの文字のデータを表記するにしては複雑に見えるかもしれない。しかし、例外事項を織り込んで記述すると、こういう表記になってしまうわけである。右辺の最初の、

  [^<&]*

という部分は、“<”記号と“&”記号を除くほかのすべての文字の0回以上の繰り返しを意味する。そして、それ以降の部分が除外されるべきケースを記述している(“-”以降)。除外されるべきケースとは、

  • “<”記号と“&”記号を除く、ほかのすべての文字の0回以上の繰り返し
  • “]]>”という文字列
  • “ <”記号と“&”記号を除く、ほかのすべての文字の0回以上の繰り返し

に該当する文字列である。これはもっとシンプルにいえば、“]]>”が含まれる場合は文字データではない、ということである。

コメントの書き方

 さて、次は「2.5 Comments(コメント)」に入る。いうまでもなくコメントは、説明を書き込むための機能である。プログラムでXML文書を生成する場合は、ありがたみが分からないかもしれないが、手動でXML文書をマーク付けしていると、しばしば欲しくなる機能といえる。しかし、XML 1.0勧告には、そのようなコメントの効能や価値などは書かれていない。XML 1.0勧告は入門書や解説書ではないためだ。

 それはさておき、勧告の内容を読んでみよう。まず、Comments(コメント)という用語の定義から入る。

[Definition: Comments may appear anywhere in a document outside other markup; in addition, they may appear within the document type declaration at places allowed by the grammar. They are not part of the document's character data; an XML processor may, but need not, make it possible for an application to retrieve the text of comments. For compatibility, the string "--" (double-hyphen) must not occur within comments.] Parameter entity references are not recognized within comments.

 コメントは、ほかのマーク付けの外ならば文書のどこに現れてもよい、としている。「ほかのマーク付け」、と、ほか(other)という言葉が付いているのは、コメントもマーク付けの一種だからである。マーク付けの外ならどこに現れてもよい、ということは、裏を返せばマーク付けの中に現れることはできないということだ。例えば以下のXML文書のコメントはOKである。要素の内容だがマーク付けの外だからだ。

  <?xml version="1.0" ?>
<a><!-- コメント --></a>

 しかし、以下のように記述するとNGである。コメントが開始タグの内部に記述されているが、開始タグはマーク付けであるから、ここにコメントは記述できない。

  <?xml version="1.0" ?>
<a <!-- コメント --> ></a>

 それに続いて、文書型宣言の中で、文法が許す場所に現れてもよい、と書かれている。文書型宣言を書くときにコメントはつきものであるから、当然のことと言える。ここで、文法が許す場所(allowed by the grammar)とは、XML 1.0勧告でEBNFによって記述されている構文の中に、はっきりと「ここにコメントを書いていいよ」という箇所が明示されているということである。これは、おいおい説明が進めば登場することになるだろう。ここでは、この件は横に置いて先に進もう。

 次に、コメントは文書の文字データの一部ではない、としている。コメントがマーク付けなら文字データではないのは当然のことである。この説明はそれを述べたいわけではなく、その続きのためにある。その続きとは、XMLプロセサは、アプリケーションプログラムがコメントのテキストを取り出すことを可能としてもよいが、そうしなくともよい、と記されている部分だ。つまり、XML 1.0勧告としては、コメントを処理可能にするべきとはいっておらず、XML文書を解析中にコメントを捨ててしまっても間違いとはしていないのである。

 とはいえ、XML文書を読み込んで変更して書き戻すような応用プログラムを想定すると、コメントを扱えないXMLプロセッサは便利ではない。せっかくXML文書にコメントを書き込んでも、XMLプロセッサで読み込んだ時点ですべて消えてしまうのでは使いにくい。もし、アプリケーションプログラムがXML文書を読み込む動作しかせず、書き込み処理がなければ、コメントを捨てても構わないのだろうが。とはいえ、この規定は、実際にXMLプロセッサを開発する際に開発者に選択の自由を与えるわけではないだろう。というのは、コメントをアプリケーションプログラムに渡せるかどうかは、採用するXMLプロセッサのAPIで決まってしまうものだからだ。

 さて、その次を読もう。互換性のために、文字列“--”(二連ハイフン)はコメント内に現れてはならない、としている。SGMLとの互換性のためではあるが、これも守った方がよいだろう。“--”を含むコメントをXMLプロセッサが受け付けるとは期待しない方がよい。

 次は最後の1文である。この1文だけはコメントの定義の外側にある。この文は、パラメタ実体参照はコメントの内部では認識されない、と説明している。パラメタ実体参照と書いてある以上、文書型宣言の内部の話ということになる。文書型宣言の内部に記述されたコメントの中にパラメタ実体の参照を書いても、展開されるわけではない、という意味である。例えば、

  <!-- 著者: %author; -->

というようなパラメタ実体参照を含むコメントは書けないわけである。もっとも、直接ファイルをテキストとして開いてみたときに意味があるコメントに、実体参照を使ったところで読みやすくなるわけでもない。これはこのままで何ら問題ないだろう。

コメントのEBNF表記

 さて、次はコメントのEBNF表記である。

Comments
[15]    Comment    ::=    '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'

 ちょっとトリックのような書き方だが、要するに<!--で始まり、-->で終わり、中間に“--”が含まれない、ということを表現している。

  Char - '-'

はハイフンを含まない任意の文字。

  '-' (Char - '-')

はハイフンとそれに続いてハイフン以外の任意の文字という意味を表現している。このどちらかが0回以上繰り返されるわけである。その結果、どんな文字の並びも許されるが、“-”記号が2回繰り返されることだけはあり得ない。パズルが好きな人は、よく考えてみると面白いだろう。

 下記は、コメントの例である。

An example of a comment:

<!-- declarations for <head> & <body> -->

Note that the grammar does not allow a comment ending in --->. The following example is not well-formed.

<!-- B+, B, or B--->

 上の例は、“<”記号や“&”記号をそのまま記述して使っている。しかし、コメント内でマーク付けが認識されることはないので、これが何かの問題を起こすことはない。下の例は、正しくない例である。文法では“--->”で終わるコメントは許されておらず、整形式ではない、と述べられている。単純にコメント内に2つのハイフン“--”が出現してはならない、とだけ理解していると、“--->”は、1つのハイフン“-”とコメントの終わりの“-->”の組み合わせだから大丈夫と思えるかもしれない。しかし、このEBNFの定義を解釈すると、それが許されない組み合わせであることが分かるだろう。つまり、コメント内には“-”の次には“-”ではない文字が必ず必要とされるため、コメント内容の最後の1文字を“-”にすることはできないのである。ちょっとした細かいことだが、こういうささいな点に気付いて読み取ることが、規格書を読む面白さの1つともいえるだろう。

 さて、今回はここまでである。次回は、「2.6 Processing Instructions(処理命令)」の説明に進む予定である。

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


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

注目のテーマ

HTML5+UX 記事ランキング

本日月間