ボキャブラリを拡大する「名前空間」XMLを学ぼう(7)

XMLの特徴の1つは、自由にタグを定義できる点にある。しかし、自由にタグが定義できてしまうということは、全く同じ名称のタグに、定義した人それぞれが異なる意味を与える可能性がある、ということだ。こうした名前の衝突を解決するのが「名前空間」だ。

» 2000年11月29日 00時00分 公開
[川俣晶株式会社ピーデー]

あのタグさえ使えれば

 例えば、商品情報を記述したHTMLファイルがたくさんあったとしよう。1つのHTMLファイルに1つの商品の名称や価格、スペックなどが詳細に書き込まれている。以下のように、そんなファイルがいくつもあったとする。

<h1>極楽トンボ1号</h1>
<p>微笑みの光をあなたに</p> 
<p>中央処理ユニット: Z-280</p> 
<p>定価: \190,000-</p>
<h1>轟く雷鳴!極楽トンボ2号</h1>
<p>CPU: Z-800</p> 
<p>定価: \299,000-</p>
<h1>極楽トンボ3号</h1> 
<p>MPU: Z-8000</p> 
<p>税別価格: \148,000-</p> 
<p>鋼の英知!ここに参上</p>

 さて、せっかく商品名や価格やスペックが書き込まれたファイルがあるのだから、これを集計して、商品一覧を作れるのではないか、と考えることができる。

■HTMLの中から情報を抜き出す

 これらのHTMLファイルの中には、確かに「商品名」「CPUの種類」「価格」の3つの情報が含まれている。もし、商品種類が3個程度なら手動でカット&ペーストして一覧表を作ってもよいのだが、数が膨大になると手作業ではやっていられない。自動的にHTMLファイルから意味ある情報を拾いあげて、自動的に一覧表を作成するソフトウェアが作れないものだろうか?

 実際に上記のHTML文書の例を見て、簡単なルールで意味ある情報を抜き出すことができるか、考えてみよう。

 まず商品名だが、見出しとなるh1要素に必ず商品名が書き込まれているという共通ルールが見てとれる。ところが、「極楽トンボ2号」の前に付いている「轟く雷鳴!」という文字列は商品名の一部ではない。では、商品名とそれ以外を区別する何か明確なルールがあるかというと、そんなものはなく、HTMLを書くデザイナーが自由に判断しているという。

 CPUの種類を知るのも難しい。何番目の段落にCPUの名前が書かれているかも決まっていないし、そもそもCPUだったり、MPUだったり、中央処理ユニットだったり、表記も一定していない。同様に価格も、定価であったり税別価格であったり、表記が一定していない。

■情報抜き出し用のタグを埋め込めば問題は解決する

 では、どうすれば、このHTML文書から確実に有益な情報を抜き出せるのだろうか。1つの方法は、情報抜き出し用のタグを埋め込むことである。例えば、商品名を確実に抜き出したいと思うなら、<商品名>というタグを創作して、これを埋め込んでしまうのである。例えば、以下のように記述する。

<h1>轟く雷鳴!<商品名>極楽トンボ2号</商品名></h1>

 こうやって商品名や価格の範囲を、それと分かるように専用のタグで囲っておけば、どんなにレイアウトを変えた商品情報を記述しても、そこから欲しい情報を確実に抜き出すことができる。

 だが、このアイデアを実行するにあたって、従来は1つの障害があった。それは、HTMLがユーザー独自のタグを創作して拡張することを許していない、ということだったのである。そして、この制約を、XMLは解き放ってくれる。

 しかし、XMLがHTMLに独自のタグを追加する手段ではないことは、いうまでもない。HTMLの後継言語がXMLというわけでもない。HTMLの後継言語はXHTMLであって、XMLではない。XMLは、別個に作られた言語のタグを、1つのXML文書に混在させることを許す。XHTMLのタグと、自作タグを1つのXML文書に共存させることができるのである。つまり、XMLは大きな鍋であり、その中にさまざまな具を入れることが許されている、ということだ。その具の1つがXHTMLというだけで、XHTML以外の別の言語を具として入れても構わないのである。

タグ名の衝突

 XMLという鍋にさまざまな言語に属する具を入れていると、しばしば問題が起きる。基本的に、具はタグ名という名前によって種類を区別するのだが、別の言語に同じタグ名が規定されていたりする。よくある英単語などは、このような衝突を起こすことも多い。そのとき、意味が同じで区別の必要がなければよいのだが、現実には名前は同じなのに意味はまったく異なるというケースが発生する。

 よく引き合いに出される事例は、「title」というタグ名が引き起こす衝突である。ご存じの通り、titleというタグ名は、HTMLではページのタイトルを示すために使用される。ところが、住所録などでは、titleは「肩書き」という意味を持つことが多く、住所録などを素直にXMLで表現するとtitleタグが肩書きを示す、というようなことが、しばしば起きる。HTMLとこの住所録言語を1つの鍋に入れて利用したいと思った場合、鍋から取り出したtitle要素がページのタイトルなのか、肩書きなのか、タグ名だけを見ても識別はできないのである。

 これを解決できなければ、せっかくのXMLの鍋としての機能も、実用性が半減である。

XMLの仕様を差し替えた名前空間

 タグ名を従来通りのタグ名として使うかぎり、「たまたま同じタグ名があった」ときに、それをうまく区別することはできない。属性名などにも同じ問題が生じる。これを解決するためには、タグ名だけでタグを区別しないという方法が必要になる。先に結論をいってしまうと、「名前空間(namespace)」(http://www.w3.org/TR/REC-xml-names/)と呼ばれるものを導入することで、これを解決する。要素名や属性名に名前空間の情報を付け加えて、同じタグ名であっても名前空間が違えば、違うものだと識別できるようにするのである。

 ところが、ここで問題が1つある。XMLの仕様書では、タグ名が同じなら同じものと見なすことが明確にルール化されている。名前空間の情報も一致しないと同じタグ名と見なさない、というルールを導入すると、XML本体の仕様書と矛盾をきたしてしまう。

 そこでXMLの名前空間の仕様書は、大胆不敵にも、XML本体の仕様書の一部を差し替えるという構成をとっているのである。そのため、XML本体だけで使用する場合と、名前空間仕様によって一部が差し替えられたXML仕様を使用する場合では、微妙に構文が異なることになる。ただ、要素名や属性名に、コロン記号(:)を使っていなければ、あまり気にする必要もない。普通、要素名や属性名に使う記号ではないので、気にする必要はないだろう。

名前空間URI

 XMLによって作り出される言語には、名前空間を使用するものと、使用しないものがある。基本的には、鍋の具として利用されるという自覚のある言語は、名前空間を使用することを前提に作り出されることになる。しかし、鍋の具として使われる予定がない言語であっても、名前空間を意識することが望ましい。なぜなら、一度作り出された言語は、多くの利用者からさまざまな使い方をされる可能性があるからだ。どんな言語でも、「これは鍋の具にしてもおいしいのではないだろうか」とだれかが考える可能性がある。つまり、よほど狭い範囲内だけで使われる言語や、便宜的に利用する使い捨て言語でもなければ、名前空間を意識しておく価値がある。

■どうやって名前空間を区別するか

 さて、一部の例外を除き、すべての言語が名前空間を意識するということになると、次に大きな問題が出てくる。全世界で生み出される膨大な言語を区別するには、どうしたらよいか、という問題だ。いちいち名前を付けていたのでは、今度は名前空間名の衝突という問題が起きかねない。それを回避するために、名前空間の名前空間を考えるのは無駄な話である。

 そこで、名前空間を区別する名前としては、URIを使うという方法がとられている。URIというのは、皆さんご存じの通り、「http://www.atmarkit.co.jp/」のような文字列だ。URIを識別名として使うというアイデアが秀逸なのは、インターネットの利用者であれば、だれでも、自分だけしか割り当てることができないURIを持っていることだ。例えば、abcというインターネットサービスプロバイダと契約して、http://www.abc.ne.jp/~autumn/というURIのディスクスペースの使用権を手に入れているなら、少なくとも契約を解消するまでは、このURIを他人が利用することは絶対にありえない。全世界のだれがこのURIにアクセスしても、必ずこのURIの利用者の用意した情報にアクセスすることになる。ということは、このURIを、名前空間の識別名として使えば、全世界の人間がだれでも自分だけの名前空間名を持つことができ、しかも、http://www.abc.ne.jp/~autumn/language1、http://www.abc.ne.jp/~autumn/language2と、ディレクトリを深く持てば、事実上無限に等しい数の名前空間名を作り出すことが可能になるのだ。

■登録などの管理業務は必要ない

 このような方法の別のメリットは、名前空間の登録などの管理業務が発生しないことである。膨大な言語が生み出され、それらが鍋の具であることを意識しているとすると、それを登録管理するのに必要なコストと手間は膨大なものになる。この動きの早いインターネットで、登録申請してから許可が下りるまで待たされるようではやっていられない。その点、URIを使う方式なら、ドメイン名に関しては公式な登録手続きはあるが、取得済みのドメイン名の下に新しい名前を付け加えることなら、何の手続きもなく簡単に実行できる。

 さて、この名前空間URIは、名前空間を識別するためだけに使用される。そのため、名前空間URIが指定する先に、何かの意味のある情報が置かれているわけではない。もちろん、説明文などを置いてもよいし、それを勧める人もいるが、それは必須の要求ではない。

 ちなみに、XHTMLの名前空間URIは、「http://www.w3.org/1999/xhtml」。XSLTの名前空間URIは、「http://www.w3.org/1999/XSL/Transform」、となっている。名前空間URIは言語がバージョンアップしても変更しないのが一般的である。

名前空間接頭辞

 名前空間URIは事実上無限に新しい名前を作り出すことができ、しかも簡単かつ確実である。しかし、タグを1個書き込むごとに、名前空間URIを書くというのは面倒でたまらない。例えば以下のようなXML文書を延々と書き続けることに耐えられるだろうか?

<http://www.w3.org/1999/xhtml:p>今日は
  <http://www.w3.org/1999/xhtml:strong>素敵
  </http://www.w3.org/1999/xhtml:strong>な1日です。
</http://www.w3.org/1999/xhtml:p>

■名前空間URIの代わりに使うもの

 そこでXMLの名前空間では、名前空間URIを直接書き込むような方法をとっていない。その代わり、名前空間接頭辞(namespace prefix)というものを使う。名前空間接頭辞というのは、名前空間URIの一種の短縮名である。つまり、<http://www.w3.org/1999/xhtml:p>と書く代わりに、<xhtml:p>と書こう、ということである。

 ただ、この短縮名称が登録制になったりすると、せっかく名前空間URIという工夫をしたことが無駄になってしまう。さらに、早い者勝ちでよい名前を独占したりすることを許すとXMLの発展を阻害しかねない。そこで、名前空間接頭辞はXML文書の中で定義する方法が採用されている。

 例えば、xhtmlという名前空間接頭辞をhttp://www.w3.org/1999/xhtmlという名前空間URIに割り当てるには、以下のような属性を記述する。

xmlns:xhtml="http://www.w3.org/1999/xhtml"

 このような属性を記述した要素とその子ノードでは、xhtmlという名前空間接頭辞がhttp://www.w3.org/1999/xhtmlという名前空間URIを指し示すようになる。以下がその一例である。

 <xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml">
   <xhtml:body>
     <xhtml:p>Hello, Namespaces!</xhtml:p>
   </xhtml:body>
 </xhtml:html>

 ここで注意すべきことは、名前空間接頭辞の宣言は、その宣言が記述された要素の子ノードだけでなく、その要素自身にも及ぶということである。だから、xmlns:xhtml属性が記述された要素自身の名前がxhtml:htmlと記述され、xhtmlという名前空間接頭辞を使っているのは、正しい使い方なのである。

■XHTMLとほかの言語を共存させてみる

 さて、1個の名前空間しか使わないのでは、そのありがたみが実感できないと思う。次に、2個の名前空間が共存している例を示そう。ここでは、http://www.autumn.org/example/titleという名前空間URIに、titleという名前の要素で肩書きを示す言語があるとしよう。これを、XHTMLと併用してみるとする。当然、XHTMLにはもともとtitleという名前の要素があるので、名前空間を使わなければ名前が衝突してしまうケースである。

 <xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml">
 <xhtml:head>
   <xhtml:title>本の紹介</xhtml:title>
 </xhtml:head>
 <xhtml:body xmlns:example="http://www.autumn.org/example/title">
   <xhtml:p>著者は<example:title>日本XMLほら吹き協会会長</example:title>オータム川俣です。</xhtml:p>
   </xhtml:body>
 </xhtml:html>

 これを見ると、XHTMLのtitle要素と、肩書きを示すtitle要素が、あいまいさを許さずに使い分けられていることが分かるだろう。このサンプルで注目すべき点は、xmlns:example属性を記述している位置である。見て分かる通り、ルート要素ではなく、かなり内側に入り込んだ位置にある。このように、名前空間接頭辞の宣言は、実際に使用する場所を範囲に含んでいる場所ならどこでもよく、ルート要素で宣言する必要はない。もちろん、ルート要素で宣言してもよい。

名前空間接頭辞の省略

 上記のサンプルを見ると、exampleという名前空間接頭辞はほとんど出番がなく、大半は名前空間接頭辞xhtmlが使われていることが分かる。この何度も繰り返し書かれる名前空間接頭辞を書かずに済ませる方法はないだろうか。

■デフォルトの状態を定義する

 名前空間接頭辞を付けなかった場合に、どの名前空間URIに属するかを指定する構文が用意されている。以下のような書式の属性を記述する。

xmlns="http://www.w3.org/1999/xhtml"

 この属性を記述した要素とその子ノードで、名前空間接頭辞を省略した要素名、属性名は、この名前空間URIに属するものと見なされる。では、この構文を使ってXHTMLの名前空間を指定するサンプルを以下に示そう。

 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
   <title>本の紹介</title>
 </head>
 <body xmlns:example="http://www.autumn.org/example/title">
   <p>著者は<example:title>日本XMLほら吹き協会会長</example:title>オータム川俣です。</p>
 </body>
 </html>

 この通り、同じ名前空間接頭辞の繰り返しが消えて、かなりすっきりと姿が変わった。しかし、名前空間URIの指定がちゃんとされていることに変わりはない。例えば、html要素は、間違いなくhttp://www.w3.org/1999/xhtmlという名前空間URIに属していることが指定されている。

■途中で名前空間を切り替えることも

 さて、名前空間接頭辞省略時の指定は複数の指定を行うことができる。その場合は、その要素や属性に対して有効な指定の中で、階層が親方向に最も近いものが使われる。例えば、上記の例はさらに以下のように書き換えることができる。

 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
 <title>本の紹介</title>
 </head>
 <body>
   <p>著者は<title xmlns="http://www.autumn.org/example/title">日本XMLほら吹き協会会長</title>オータム川俣です。</p>
 </body>
 </html>

 6行目の名前空間URIの指定によって、6行目のtitleタグは、XHTMLではなく、この名前空間URIに属することになる。だが、この要素の子孫ではない3行目のtitle要素には効力が及ばないので、こちらは、XHTMLの名前空間URIに属することになる。このように局所的に名前空間接頭辞省略時の指定を変更できるので、ある要素を明確な境界線にして、使用する名前空間URIが変わるときには、いちいち名前空間接頭辞を付けないという方法も選択できる。

■すべてが切り替わることに注意

 さて、以下は間違った指定方法を行った例である。

 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
 <title>本の紹介</title>
 </head>
 <body xmlns="http://www.autumn.org/example/title">
   <p>著者は<title>日本XMLほら吹き協会会長</title>オータム川俣です。</p>
 </body>
 </html>

 この例では、5行目に、名前空間の指定があり、5〜7行目に存在するすべての要素と属性が、http://www.autumn.org/example/titleに属すると指定されており、bodyやp要素はXHTMLのものとは見なされない。たとえ、名前空間URI http://www.autumn.org/example/titleにbodyやpが規定されていなくても、これらがXHTMLのものと見なされることはない。つまり、省略時の名前空間が切り替わるときには、すべてが一気に切り替わるということで、使用上注意すべき点である。

XSLTにおける名前空間の利用例

 実際に名前空間が有益に役立っている例として、XSLTを紹介しよう。名前空間が具体的にどう役立つのかピンとこない人は、これを見ていただきたい。ただし、この記事はXSLTの入門を意図したものではない。XSLTをまったく知らない人は、@ITのXSLT入門の記事(「サンプルで覚えるXSLTプログラミング」)などを参照していただきたい。

 XSLTの機能を非常に単純化して一言で要約すると、XML文書と、XMLで記述された変換スクリプトを読み込んで、変換を行った上で出力することである。このとき、注目すべきことは、以下の点である。

  • XSLTのスクリプトはXMLで記述されている
  • XSLTのスクリプトには出力するXML文書の断片が書き込まれている

 つまり、XSLTスクリプトは1個のXML文書でありながら、このXML文書の上には、XSLTで規定された要素や属性と、出力に使用する要素や属性の両方が書き込まれているということである。

 普通にやれば、1つのXML文書に、異なる言語の要素や属性を混在させるのは、トラブルのもとである。しかし、XSLTでは、XSLTの要素や属性に、http://www.w3.org/1999/XSL/Transformという名前空間URIを与えることで、XSLT自身が利用する要素・属性と、それ以外のものを、明瞭に区別することに成功している。

■名前空間URIの持つ意味の重大さ

 逆に、この特徴が、興味深いトラブルの原因となったことも見逃せない。XSLTの仕様が決まる前、まだワーキングドラフトと呼ばれていたころに、マイクロソフトはXSLTプロセッサを開発して、Internet Explorerに組み込んだ。このとき、XSLTの名前空間URIはまだ正式に決まっておらず、http://www.w3.org/TR/WD-xslという仮の名前空間URIを使用していた。しかし、正式にXSLTが勧告として決まった今、XSLTにはhttp://www.w3.org/1999/XSL/Transformという正式の名前空間URIが与えられている。この違いのため、たとえスクリプトの内容に一切変更の必要がない場合であっても、XSLTスクリプトに書き込まれた名前空間URIの変更が要求されることになるのである。

 これは、名前空間URIというものが持つ意味の重大さを示した事件といえるだろう。つまり、名前空間URIが変わるというのは、それを利用しているすべてのデータの訂正も要求する大事件に発展してしまうのである。だから、名前空間URIは慎重に決定し、一度決めたらみだりに変えないことが重要である。

鍋にダシは不可欠だ

 XMLを、ただ単にその場その場でデータの記述を楽に行う手段と考えている間は、名前空間のありがたさは分からないかもしれない。だが、いちいち必要が生じるごとに言語を作るような使い方は無駄が多い。再利用可能な言語の部品を、名前空間というダシを入れたXMLという鍋に入れて、グツグツ煮込んで、必要な言語を手に入れる方が、ずっと合理的で楽ができる。それを実現するためには、常日ごろから、再利用されることを意識しながら言語を作ることが重要である。

 これは、ある意味で、オブジェクト指向プログラミングの世界の中で、常日ごろ再利用されることを意識しながらクラスを設計することと、同じような意味を持つことだといえる。

 次回は再利用できる言語とは何かを、より深く考えてみよう。

 それでは次回、また会おう。


Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。