XML でデータを処理する

CDATA セクションを有効利用する

通常、XML ファイルの中にデータを含めるときには、安全で XML パーサーを混乱させないような方法でデータをエンコードするよう注意しなければなりません。特殊な XML マークアップ文字は実体に変換しなければなりませんが、テキスト・エディターを使って手作業で XML を作成しているとしたら、かなり厄介なことになります。そこで、この面倒を避ける手段となるのが CDATA セクションです。CDATA セクションには、エンコードについて心配することなく直接データを保存することができます。この記事では、XML の CDATA セクションについて説明し、XML ファイルと併せてマークアップ付きデータを配布しなければならない場合に、CDATA セクションをどのように利用すればよいかを紹介します。

Chris Herborth, Technical writer and software developer, Freelance

Photo of Chris HerborthChris Herborth は、受賞の栄誉に輝くシニア・テクニカル・ライター兼ソフトウェア開発者で、これまで 15 年以上、オペレーティング・システムおよびプログラミングについての著作活動を続けています。余暇は、息子の Alex や妻の Lynette と一緒でないときには、ビデオ・ゲームの設計、作成、調査 (つまりゲームで遊んでいるということです) で過ごしています。ただし、「World of Warcraft」には手をつけていません。



2010年 1月 12日

はじめに

よく使われる頭字語

  • Ajax: Asynchronous JavaScript + XML
  • API: Application Programming Interface
  • CSS: Cascading Stylesheets
  • DOM: Document Object Model
  • DTD: Document Type Definition
  • HTML: HyperText Markup Language
  • HTTP: HyperText Transfer Protocol
  • IIS: Internet Information Services
  • LAN: Local Area Network
  • MIME: Multipurpose Internet Mail Extension
  • UTF: Unicode Transformation Format
  • VPN: Virtual Private Network
  • XHTML: Extensible Hypertext Markup Language
  • XML: Extensible Markup Language
  • XSD: XML Schema Definition

XML は、構造化データのエンコードについて確固たる支持を得ているインターネット標準です。XML では、実質的にあらゆるプログラミング言語で簡単にデコードできるような形式に構造化データをエンコードできるだけでなく、エンコードされた構造化データは、通常のテキスト・エディターを使って人間が読んだり、書いたりすることもできます。標準に準拠した最近の Web ブラウザーをはじめ、多くのアプリケーションが XML データを直接処理することができます。

XML はテキストをベースとした標準であることから、クライアント・システムとサーバー・システムとの間でデータを交換するには最適です。ほとんどのデータはすでにテキストをベースにしていること (ファイル・パス、説明、アドレス、名前など)、そして整数、浮動小数点数、日付などは簡単にストリング表記に変換したり、ストリング表記から変換したりできることが、XML が最適とされる理由です。

しかし残念ながら、データのなかには XHTML または XML マークアップなどのように、XML 文書に組み込むのが困難なものや、非常に手間がかかるものがあります。マークアップを XML 要素に含める 1 つの方法は、マークアップ文字 (より少ない (>)、より大きい (<)、アンパサンド (&)) をそれぞれに対応する実体 (&lt;、&gt;、&amp;) に置き換えることです。しかしそうなるとデータは大きくなり、人間にとってかなり読みにくいものになります。さらにテキスト・エディターを使って手作業で XML を作成しているとしたら、マークアップを変換するのがどんなに厄介な作業になるかは言うまでもありません。

実体に置き換えるよりも賢いソリューションとしては、マークアップを XML 文書に直接組み込む方法が考えられます。そこで活躍するのが、XML の CDATA セクションです。


CDATA とは何か?

XML 文書内のテキストは通常、構文解析された文字データです。この文字データは、Document Type Definition の用語では PCDATA と呼ばれます。XML の特殊文字 (&、<、>) は PCDATA で認識され、要素名および実体の構文解析に使用されます。パーサーは CDATA (文字データ) セクションをデータのブロックとして扱うため、データ・ストリームには任意の文字を含めることができます。

XML 文書に、例えば資料として HTML や XML を組み込もうとしたことがあれば、それらのサンプルを含めようとした途端、以下で取り上げる問題に突き当たった経験があるはずです。リスト 1 に、一部のテキストを強調表示した単純なパラグラフのサンプルを記載します。

リスト 1. sample 要素に含まれたサンプル XHTML
<?xml version="1.0" encoding="UTF-8"?>
<sample>
    <description>
    Paragraphs can include emphasized text.
    </description>

    <example>
    <p>The pug snoring on the couch next to me is 
    <em>extremely</em> cute.</p>
    </example>
</sample>

このパラグラフのマークアップを実体で表すとなると、ちょっとした悪夢です (リスト 2 を参照)。

リスト 2. マークアップを実体で表したサンプル XHTML
<?xml version="1.0" encoding="UTF-8"?>
<sample>
    <description>
    Paragraphs can include emphasized text.
    </description>

    <example>
    &lt;p&gt;The pug snoring on the couch next to me is 
    &lt;em&gt;extremely&lt;em&gt; cute.&lt;/p&gt;
    </example>
</sample>

CDATA セクションのなかにサンプルのマークアップをラップすれば、マークアップをそのまま記述しても XML パーサーはそのサンプルを <em> 要素が含まれる <p> 要素として解釈することはありません。DTD または XML Schema に対して XML の妥当性検証を行う場合には、このように CDATA セクションでラップする必要があります (要素が実際に DTD または XSD のなかに存在し、文書のその箇所に組み込むことが可能である場合は、その限りではありません)。リスト 3 を見てください。

リスト 3. CDATA を使用したサンプルの保護
<?xml version="1.0" encoding="UTF-8"?>
<sample>
    <description>
    Paragraphs can include emphasized text.
    </description>

    <example>
    <![CDATA[<p>The pug snoring on the couch next to me is 
    <em>extremely</em> cute</p>]]>
    </example>
</sample>

CDATA の使用方法

リスト 3 の簡単な例からわかるように、CDATA セクションは <![CDATA[ という特殊なシーケンスで始まり、]]> のシーケンスで終わります。この 2 つのマークアップの間にあるコンテンツはすべて構文解析されずにそのまま、XML パーサーを通過します。一部の開発プラットフォームには、CDATA セクションのコンテンツを表す特殊な CDATA オブジェクト (XML DOM の CDATASection など) がありますが、それ以外のプラットフォームではそれよりも汎用的なオブジェクト (通常は XML テキスト・ノード) としてコンテンツを提供します。いずれの場合にしても、CDATA セクションのコンテンツは変更することなく使用することができます。

通常、XML はホワイト・スペースに関してはかなり寛容ですが、セクション終了シーケンスの ]]> にスペースや改行を含めることはできません。

XHTML での CDATA

これまで JavaScript スクリプトが埋め込まれた Web ページを数多く見てきていれば、CDATA が実際に使用されているのを目にしたことがあるはずです。例えば、リスト 4 のようなコードをよく見かけると思います。

リスト 4. XHTML の <script>要素に含まれる CDATA
<?xml version="1.0" encoding="UTF-8"?>
<!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">
<head>
<meta http-equiv="Content-Type" 
content="application/xhtml+xml;charset=utf-8"/>
<title>CDATA Section in Action</title>
<script type="text/javascript">
// <![CDATA[
function nowWeAreSafe( x, y, z ) {
    // Without the CDATA section, these would cause 
    // parsing errors:
    if( x < y && y > z ) {
        return y--;
    }
    return 0;
}
// ]]>
</script>
</head>
<body>
...
</body>
</html>

<script> 要素内の JavaScript は、CDATA セクションの始まりが含まれるコメントで始まり、CDATA セクションを終了するコメントで終わっています。これは一見、XHTML と JavaScript を無意味に煩雑にしているように思えますが、この CDATA セクションがなければ、スクリプトは Web ブラウザーの XHTML パーサーに処理されることになってしまいます。

とことん運に見放されない限り、これが原因で問題が生じることはありませんが、複雑でデバッグしにくいレンダリング・エラーにつながるパーサー・エラーが発生する可能性は確かにあります。なぜ、そのような結果になるのでしょう?

お察しのとおり、その理由は、<、>、& の文字には要素または実体のフラグが立てられることになるからです (あるいは、解釈されないマークアップ文字となります)。さらに、2 つのダッシュ ( -- ) のシーケンスが XHTML コメント・ブロックの開始 (終了) として想定外の解釈をされる可能性もあります。実際こうした理由から、埋め込まれたスクリプトは XML のコメントにするのではなく、CDATA セクションでラップしなければならないのです。XML のコメントにしても、頼りにはなりません。

めったにないことですが、CDATA はインライン <style> 要素のなかに現れることもあります (リスト 5 を参照)。

リスト 5. CDATA による <style> 要素での構文解析エラーの回避
<style type="text/css">
/* <![CDATA[ */
body {
    background-image: 
        url("marble.png?width=300&height=300")
    }
/* ]]> */
</style>

ここでもやはり、CDATA マーカーが言語固有のコメントのなかに隠されていて、クライアント Web ブラウザーの CSS パーサーを混乱させないようにしている点に注目してください。


CDATA の制約事項

CDATA セクションが有用であることは確かですが、すべての長所と同様に、念頭に置いておかなければならない制約事項がいくつかあります。

ブラウザーは通常、XML パーサーでありません

ブラウザーが仮に HTML または XHTML の CDATA を処理するとしても、その処理は確かなものではありません。CDATA セクションは (すべての XML アプリケーションでの場合と同じく) XHTML のあらゆる場所で使用できますが、実際には完全に無視されます。そのため、コンテンツを失うか (つまり CDATA セクションが通常の DOM から消えてなくなるか)、解釈されないマークアップ文字を持つキストとしてレンダリングされる結果となります。

この結果を確認するには、サンプル・パラグラフ、(実体を使用して) マークアップを可視にしたサンプル・パラグラフ、そしてCDATA を使用してマークアップを可視にしようとしたサンプル・パラグラフを表示するページを見てください。この XHTML ページのソースはリスト 6 のとおりです。

リスト 6. XHTML で CDATA を使おうとした場合
<?xml version="1.0" encoding="UTF-8"?>
<!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">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml;charset=utf-8"/>
<title>CDATA Section in Action</title>
</head>
<body>
<h1>CDATA Section in Action</h1>

<p>
A sample paragraph:
</p>

<p>The pug snoring on the couch next to me is <em>extremely</em> 
cute.</p>

<p>
Markup version:
</p>

<p id="no1">
<p>The pug snoring on the couch next to me is <em>extremely</em> cute.</p>
</p>

<p>
CDATA version:
</p>

<p id="no2">
Uh,
<![CDATA[<p>The pug snoring on the couch next to me is <em>extremely</em> cute.</p>]]>
where?
</p>

<p>
Wait, what?
</p>

</body>
</html>

Firefox 3 は図 1 に示すように、CDATA セクションのコンテンツを表示しません。(図 1 のテキストのみのバージョンを見る)。

図 1. CDATA セクションを無視する Firefox
Firefox は CDATA セクションを無視し、CDATA のコンテンツをまったく表示しません。
CDATA セクションが表示されない Firefox 3 の画面 (図 1) のテキスト・バージョン
CDATA Section in Action

A sample paragraph:

The pug snoring on the couch next to me is extremely cute.

Markup version:

<p>The pug snoring on the couch next to me is <em<extremely</em> cute.</p>

CDATA version:

Uh, where?

Wait, what?

Safari や Chrome などの WebKit ベースのブラウザーが CDATA セクションをレンダリングすると、余分なマークアップ文字が表示されます (図 2 を参照)。(図 2 のテキストのみのバージョンを見る)

図 2. CDATA セクションをレンダリングする Safari および Chrome
Safari と Chrome は CDATA セクションをレンダリングしますが、不適切な文字を表示します。
CDATA セクションに加えて不適切な文字が表示される Safari および Chrome の画面 (図 2) のテキスト・バージョン
CDATA Section in Action

A sample paragraph:

The pug snoring on the couch next to me is extremely cute.

Markup version:

<p>The pug snoring on the couch next to me is <em<extremely</em> cute.</p>

CDATA version:

Uh,

The pug snoring on the couch next to me is extremely cute.

]]> where?

Wait, what?

Internet Explorer® でも同じように、余分なマークアップ文字が表示されます (図 3 を参照)。(図 3 のテキストのみのバージョンを見る)

図 3. 同じく CDATA セクションをレンダリングする Internet Explorer 8
Internet Explorer 8 も CDATA セクションをレンダリングしますが、不適切な文字を表示します。
CDATA セクションに加えて不適切な文字が表示される Internet Explorer 8 の画面 (図 3) のテキスト・バージョン
CDATA Section in Action

A sample paragraph:

The pug snoring on the couch next to me is extremely cute.

Markup version:

<p>The pug snoring on the couch next to me is <em<extremely</em> cute.</p>

CDATA version:

Uh, The pug snoring on the couch next to me is extremely cute.

]]> where?

Wait, what?

ブラウザーは XHTML 文書に CDATA セクションが含まれていると正しく動作しませんが、Ajax によってロードされた XML 文書に含まれる CDATA セクションであれば、正しく処理します。正しく処理できなかったとしたら、そのブラウザーの XML パーサーは「XML の仕様に準拠していない」と見なされ、ユーザーからは冷たく嘲笑され、Ajax にまったく対応していないというレッテルを貼られることになるでしょう。

セクション終了マーカーはやはり特別です

CDATA セクションにはどんなコンテンツでも入れられるとは言え、セクション終了マーカーのシーケンス (]]>) についてはその限りではありません。CDATA セクションをネストすることは絶対に不可能です。XML パーサーがこのシーケンスを読み取ると、それで CDATA セクションは終わったことになります。そのため、実際の CDATA セクションの終わりに達したときに、パーサー・エラーを受け取る結果となります。

別の言い方をすれば、CDATA セクションのなかで <![CDATA[ を使用しても、XML (または XHTML) パーサーは、セクション終了マーカーである ]]> 以外のマークアップ文字はすべて無視するため、これを認識しないということです (リスト 7 を参照)。

リスト 7. 妥当でない XML (CDATA セクションはネストできません)
<?xml version="1.0" encoding="UTF-8"?>
<sample>
    <description>
    You can't nest CDATA sections.
    </description>

    <example>
    <![CDATA[You want a <![CDATA[ ]]> inside your
    example? No, this is wrong.]]>
    </example>
</sample>

セクション終了マーカーを CDATA セクションのなかに入れなければならないとしたら、どうすればよいのでしょうか?その場合には、CDATA セクションを 2 つに分割する必要があります (リスト 8 を参照)。

リスト 8. CDATA セクション内にセクション終了シーケンスを入れる正しい方法
<?xml version="1.0" encoding="UTF-8"?>
<sample>
    <description>
    Split up the section end.
    </description>

    <example>
    <![CDATA[You want a ]]]]><![CDATA[>
    inside your example? Do it this way.]]>
    </example>
</sample>

つまり、データに含まれる ]]>]]]]><![CDATA[> に置き換えることで、シーケンスの最後の > を前の 2 つの ] と離すようにします。パーサーは具体的に ]]> を 3 つの文字のシーケンスとして探すので、これを分割することによってシーケンスを破断するのです。

もちろん ]]]]><![CDATA[> は恐ろしく大きなマークアップの塊ですが、幸い、このような状況に出くわすことはめったにありません。

テキストであることには変わりありません

CDATA セクションのコンテンツは処理されずにそのままパーサーを通過しますが、文書の文字エンコーディング方式で指定された妥当な XML データ文字でなければならないことに変わりはありません。UTF-8 のようなエンコード方式を使用すると、非常にさまざまな文字をデータに使用することができますが、1 文字が 8 ビットぴったりに収まっているというわけではありません。

いわゆる制御文字 (スペース文字である 0x20 より小さい 16 進値を持つ文字) が含まれていると、妥当でないトークンによるエラーでパーサーが停止する可能性があります。妥当な文書とする上では、あらゆるデータを CDATA セクションに入れられるわけではありません。

サイズは重要です

CDATA セクションを使ってデータの塊を XML に追加する際に気を付けなければならない最後の注意点は、サイズです。Web サービスを介して XML ファイルを提供する場合、かなりサイズの大きなデータが転送されることになったとしても、データが 3G 接続で転送される間、必ずクライアント・アプリケーションがタイムアウトになったり、ユーザー・インターフェースをブロックしたりすることがないようにしてください。

逆のことも言えます。XML データを送信するクライアントからの大量のアップストリーム転送を、サーバーが必ず受け付けられるようにする必要があります。DoS (サービス拒否) 攻撃を防ぐために、Web サーバー (特に Windows® プラットフォームでの IIS) のアップロード制限がかなり小さく設定されていることはよくあります。このような大きなサイズのデータ・ブロックをブラウザーから送信すると、エラーの原因となりやすく (ユーザーが例えば、送信に失敗したと思って送信をキャンセルしたとしたらどうなるでしょうか?)、サーバーおよびクライアント上の貴重なリソースがロックされてしまう結果となりがちです。

さらにアプリケーションの内容によっては、多くのユーザーがモバイル・プラットフォームを使用していること、そして未だにダイアルアップ接続に頼っているユーザーもいることを念頭に置き、アプリケーションが LAN の外部で利用されることを想定する必要があります。

ダイアルアップ用に設計されていないアプリケーションだとしても、iPhone のダイアルアップ VPN 接続でそのアプリケーションを利用しようとするユーザーがいれば、そのユーザーは本人のまずい選択は棚に上げて、アプリケーションの速度に不平不満を言うはずです。


バイナリー・データを XML に保存する

バイナリー・データを XML 文書に含めなければならない場合には、バイナリー・データが XML パーサーの足をすくわないようにしてください。データがテキストだとすれば、CDATA セクションにそのデータを放り込むだけで済みますが、真のバイナリー・データは安全かつリカバリー可能な方法でエンコードしておく必要があります。

幸い、MIME 標準では幅広くサポートされている安全なエンコード方式 base64 を定義しています。base64 エンコード方式はバイナリー・データを元のサイズの約 137% にするため、バイナリー・データを XML 文書に組み込める代わりに、追加のストレージ・スペース (そして少々の処理能力) が必要になります

通常は、XML にエンコード方式と元のファイル名を示すことになります (リスト 9 を参照)。

リスト 9. XML 文書内で base64 にエンコードされたファイルの一例
<?xml version="1.0" encoding="UTF-8"?>
<sample>
    <description>
    An embedded image file.
    </description>
    
    <image name="stop.png" encoding="base64"
        source="FamFamFam"
        href="http://www.famfamfam.com/lab/icons/silk/">
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQ
CAYAAAAf8/9hAAAABGdBTUEAAK/INwWK
6QAAABl0RVh0U29mdHdhcmUAQWRvYmUg
SW1hZ2VSZWFkeXHJZTwAAAJOSURBVDjL
pZI9T1RBFIaf3buAoBgJ8rl6QVBJVNDC
ShMLOhBj6T+wNUaDjY0WmpBIgYpAjL/A
ShJ+gVYYYRPIony5IETkQxZ2770zc2fG
YpflQy2MJzk5J5M5z/vO5ESstfxPxA4e
rL4Zuh4pLnoaiUZdq7XAGKzRJVbIBZ3J
PLJaD9c/eCj/CFgZfNl5qK5q8EhTXdxx
LKgQjAFr0NK0ppOpt9n51D2gd2cmsvOE
lVcvOoprKvuPtriNzsY8rH+H0ECoQEg4
WklY1czP8akZby51p6G3b6QAWBl43llS
VTlUfuZE3NmYh9Vl0HkHSuVq4ENFNWFd
C+uJ5JI/9/V2Y//rkShA1HF6yk/VxJ0f
07CcgkCB7+fSC8Dzcy7mp4l9/khlUzwe
caI9hT+wRrsOISylcsphCFLl1RXIvBMp
YDZJrKYRjHELACNEgC/KCQQofWBQ5nuV
64UAP8AEfrDrQEiLlJD18+p7BguwfAoB
UmKEsLsAGZSiFWxtgWWP4gGAkuB5YDRW
ylKAKIDJZBa1H8Kx47C1Cdls7qLnQTZf
fQ+20lB7EiU1ent7sQBQ6+vdq2PJ5dC9
ABW1sJnOQbL5Qc/HpNOYehf/4lW+jY4v
h2tr3fsWafrWzRtlDW5f9aVzjUVj72Fm
CqzBypBQCKzbjLp8jZUPo7OZyYm7bYkv
w/sAAFMd7V3lp5sGqs+fjRcZhVYKY0xu
pwysfpogk0jcb5ucffbbKu9Esv1Kl1N2
+Ekk5rg2DIXRmog1Jdr3F/Tm5mO0edc6
MSP/CvjX+AV0DoH1Z+D54gAAAABJRU5E
rkJggg==
    </image>
</sample>

マシンで生成された XML 文書では、ホワイト・スペースを除外することができるため、改行文字を使わずに base64 エンコード・ファイル全体をひとまとめに実行することができます。

問題を回避する方法

XML に含まれるバイナリー・データを処理する最善の方法は、XML にバイナリー・データを含めること自体を避けることです。HTML の場合と同じように、外部ファイルを標準化した方法で参照すると上手くいきます。何らかの方法でクライアント・アプリケーションが外部ファイルを取得できるとしたら、これが最適なオプションです。HTML の場合、ブラウザーは単に別の HTTP リクエストを行って、<img>のような要素を介して組み込まれたデータを取得します。

XML にバイナリー・データを直接組み込まないようにすることで、無駄なテキストのエンコーディングを避けられるとともに、ほとんどのユーザーにとって Web ブラウザーの魅力となっている画像キャッシュといった別の拡張機能を実装することが可能になります。


まとめ

<![CDATA で始まり、]]> で終わる XML の CDATA セクションを使用すれば、文書の一部をパーサーの処理対象から除外することができます。このセクションに含まれるデータは、パーサーに入る前とまったく同じテキストのままパーサーから出てきます。ただし ]]> シーケンスについては、CDATA セクションを一旦終了してから再開することによって保護する必要があります。

XHTML 文書で CDATA セクションを使用できないとしても、XML であれば、ブラウザーやお馴染みのプログラマミング・プラットフォームで十分にサポートされます。CDATA を使用して XML 文書にマークアップされたデータを直接組み込むことで、データをエンコードする必要はなくなります。その一方、(潜在する) 大量のデータ転送によるクライアントおよびサーバー・アプリケーションへの影響については慎重に考慮する必要があります。

バイナリー・データを XML 文書に保存しなければならない場合は、標準の MIME base64 エンコード方式などのテキスト・エンコーディング方式を使用できますが、おそらくは、外部ファイルを参照したほうが得策でしょう。

参考文献

学ぶために

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

議論するために

コメント

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
ArticleID=467972
ArticleTitle=XML でデータを処理する
publish-date=01122010