XML名前空間の簡単な説明

XMLでは自由に独自のマークアップ言語(タグセット)を設計できますが、ウェブ上で情報を共有するときに、同じタグ名が異なる要素タイプを意味して衝突してしまう可能性があります。この問題を解決するためにXML名前空間は、それぞれのタグセットに固有のURIを割り当て、名前をURIで修飾することでお互いを区別します。名前空間は、ウェブ上で「意味」を明確に定義し、相互理解を可能にするために非常に重要な役割を果たします。

名前空間の導入

XMLでは独自のマークアップ言語(語彙)を自由に設計できますが、多くの人が利用する語彙は、標準的な語彙を共有する方が効率が良く、相互運用性も高まります。そこで、ひとつのXML文書を作成するのに、さまざまなマークアップ言語から語彙を拝借し、組み合わせて利用できるような仕組みが必要になります。たとえば論文を公開するのに、全体の構造や本文はXHTMLで記述しつつ、数式部分にはMathMLの語彙を、グラフにはSVGの語彙を利用するという方法です。

このように複数の言語をモジュールとして組み合わせるためには、それぞれの語彙をきちんと区別できなければなりません。しばしば取り上げられる例としては、titleという名前を持つ要素が、ある時は書物の「タイトル」を表したり、別の時は作者の「肩書き」を表したりすることがあり得るからです。

この問題を解決するためには、それぞれの語彙がユニバーサルな名前、つまり世界で一意に定まる名前を持つための方法が必要です。これを実現するのが、1999年にW3Cから勧告されたXML名前空間[XMLNS]です。XML名前空間は、語彙(要素タイプ名、属性名)をURIと組み合わせる(修飾する)ことで、複数の語彙を混在させるメカニズムです。

名前空間は、タグセットを組み合わせて利用できるようにするだけでなく、ウェブ上で共有・交換される情報の意味を正確に示し、コンピュータに理解可能にするためにも非常に重要な役割を果たします。

名前空間URIによる修飾と接頭辞

名前空間では、複数のタグセットを区別するために、語彙をURIで修飾します。ここで、James Clark氏による説明用の表記法[JCLARK]を借用し、修飾部を{URI}と表記してその仕組みを説明してみましょう。たとえば(1)書物の情報を表現するタグセットをhttp://example.com/ns/book/というURIで、(2)作者の情報を表現するタグセットをhttp://example.com/ns/profile/というURIで識別することにすると、書物のタイトル、作者の肩書きを示す要素タイプ名は、それぞれ

[例1]

{http://example.com/ns/book/}title                  (1)
{http://example.com/ns/profile/}title               (2)

という形で表記できます。URIは世界で重複することのない識別子ですから、語彙ごとにURIを割り当てれば、この方法で必ずタグセットを区別できるわけです。

もっとも、全てのタグにURIを記述していては非常に煩雑になりますから、XML名前空間では、これらのURIに別名を割り当て、それを接頭辞として用いるよう定めています。URIと接頭辞はxmlnsという特別な属性を使って結びつけます。

[例2]

<body xmlns:book="http://example.com/ns/book/"
      xmlns:prof="http://example.com/ns/profile/">
  ...
  <book:title>ユニバーサルHTML/XHTML</book:title>   (1)
  ...
  <prof:title>コントラバス奏者</prof:title>                 (2)
   ...

このように接頭辞を加えた名前はQName(qualified name=修飾された名前)と呼ばれます。QNameでは、titleのような各語彙に属する名前の部分はローカル部(local part)あるいはローカル名(local name)と称します。

この例の(1)(2)は、book:prof:という接頭辞がURIにマップされているので、それぞれ{URI}で修飾した[例1]の(1)(2)と同等の識別情報を持ち、同じようにユニバーサルに区別できる名前になっています。

xmlns属性を使って名前空間を宣言すると、その接頭辞とURIのマッピングは、宣言を行った要素およびその子孫要素にわたって有効になります。

デフォルト名前空間

xmlns属性による名前空間宣言で、接頭辞を省略すると、そのURIが宣言のある要素以下でデフォルトとなり、接頭辞なしのタグ名はこのデフォルト名前空間に属することになります。例えば、XHTMLの場合はルート要素のhtmlタグで次のような名前空間の宣言を行います。

[例3] <html xmlns="http://www.w3.org/1999/xhtml">

この宣言を最初に行うことで、html要素内に記述するタグは、接頭辞を持たなくてもXHTMLの名前空間に属することになるのです。

デフォルト名前空間を含め、名前空間の接頭辞は宣言している要素とその子孫で有効ですが、子孫要素で同じ接頭辞(あるいはデフォルト)の名前空間が宣言されると、その内部では新しい宣言によって結びつきが上書きされます。

[例4]

<!-- 最初のデフォルト名前空間はXHTML -->
<html xmlns="http://www.w3.org/1999/xhtml">
...
<body>
...
<!-- ここからデフォルト名前空間はMathML -->
<math xmlns="http://www.w3.org/1998/Math/MathML">
 <mrow>
 ...
</math>
<!-- デフォルト名前空間はXHTMLに戻る -->
...

名前空間URIの意味するところ

名前空間においていまひとつ分かりにくいのが、そのURIにはどんな意味があるのかというところでしょう。

[例5] <html xmlns="http://www.w3.org/1999/xhtml">

などと記述されていると、このURIをたどれば、XHTMLの仕様書かDTDが取り出せると考えたくなるのが人情です。しかし、XML名前空間の仕様書では、

The namespace name, to serve its intended purpose, should have the characteristics of uniqueness and persistence. It is not a goal that it be directly usable for retrieval of a schema (if any exists).

となっていて、このURIは仕様やスキーマを取り出すためのものではなく、ユニークで永続的な識別が目的であるとされています(namespace nameとはURIのこと)。多くの場合、名前空間を示すURIにhttp:スキームが使われているため、何かを取り出せるという印象があるのですが、これは第一義的にはその名のとおり「ID」の役割を果たすものと理解してください(もちろん、そこにスキーマ自身や、スキーマにリンクする文書があっても構わないし、それはある意味で推奨されているのですが)。

名前空間の区画と属性の名前空間

以下の説明は、重要ではありますが、かえって混乱するかもしれないので、名前空間の概要のみを知りたいときは、適当に端折ってください。

XML名前空間で、もうひとつ分かりにくのが「区画(partition)」という概念です。仕様書の付録A.2 XML Namespace Partitionsには次のような3つの区画が説明されています。

1. 要素タイプ全てが属する区画
要素タイプ名は全てこの区画に属します。それぞれの要素タイプは固有のローカル部を持ち、名前空間名+ローカル部の組み合わせが要素タイプを一意に特定します。
2. グローバルな属性の区画
ある名前空間においてグローバル(共有)と定義された属性名が属する区画です。要素タイプに関係なく、名前空間内でユニークであることが求められます。名前空間名+属性名の組み合わせが、属性を一意に特定します。
3. 要素タイプごとの区画
それぞれの要素タイプは、自分自身の名前空間区画を持ち、タグ中の修飾されない属性がこの区画に属します。ここでは、名前空間名+要素タイプのローカル名+属性名の組み合わせが、属性を一意に特定します。

デフォルト名前空間は属性には適用されないので、接頭辞がある属性は2.の区画に、接頭辞なしの属性は3.の区画に属すると単純に考えることができます。

同じ属性名なのか異なる属性なのか

混乱を招きやすいのは、2.と3.の属性の区画がどう違うのかということです。たとえば、“XHTMLの文書の中にbookの語彙を埋め込みつつ、共通のクラスを指定するためにXHTMLのclass属性を使う”というケースを考えてみましょう。

[例6]

<h:html xmlns:h="http://www.w3.org/1999/xhtml"
        xmlns:b="http://example.com/ns/book/">
...
 <h:div class="biblio">
 <b:book>
  ...
  <b:author h:class="person">神崎正英</b:author>
  ...

この例では、最初のh:div要素で登場するclass属性は、要素自身がXHTML空間に属するので属性名のみを記述しています。一方b:author要素では、要素の名前空間がbookに属するため、class属性はそれとは異なるXHTML名前空間に属することを示すh:で修飾しています。

いずれも同じXHTMLのclass属性であることを示しているように思えるのですが、「区画」という定義によると、少々ややこしいことになります。最初にとりあげたJames Clark氏の表記方法を拡張して、名前空間名を{URI}で表記し、属性名は#属性名で加えたかたちで、上記の属性名を展開してみましょう(檜山正幸氏の応用[HIYAMA]による)。

値が"biblio"である最初のclass属性は、3.の区画に従って名前空間名+要素タイプのローカル名+属性名で特定されるので、次のようになります。

[例7] {http://www.w3.org/1999/xhtml}div#class

一方、後者の"person"という値をとるclass属性は、接頭辞h:で示されるようにXHTML名前空間に直接属しており、2.の区画となりますから名前空間名+属性名で表記されます。

[例8] {http://www.w3.org/1999/xhtml}#class

同じXHTMLのclass属性ではあっても、区画の違いで展開した名前(ユニバーサル名)は異なったものとなり、厳密には別の属性ということになるのです(この区画に従って厳密に考えると、通常のXHTMLの属性記述方法では、class属性は要素タイプごとに定義されていて「グローバル」ではないということになります)。

どっちでも大差ない? ひとつのタグセットの語彙だけで書かれた文書(たとえばXHTML1.0)を処理している間は、特に問題は生じないかも知れません。しかし、複数の語彙を混在して記述し、汎用のXMLユーザエージェントで利用するときには、属性名を名前空間で修飾するかどうかは重要になってきます。この点は応用言語の仕様書でも曖昧になっていることが多いのですが、要素タイプを問わずに「グローバル」に使う属性は、原則として名前空間修飾しておく必要があると考えておくべきでしょう。

参照文献

[XMLNS]
Tim Bray, et al., Namespaces in XML, , W3C Recommendation
<http://www.w3.org/TR/REC-xml-names>
[JCLARK]
James Clark, XML Namespaces,
<http://www.jclark.com/xml/xmlns.htm>
(ここで借用した{URI}による修飾は、説明用の便宜的なもので、文法的に正確な表記ではありません)
[HIYAMA]
檜山正幸, XML名前空間の落とし穴, , XML eXpert eXchange
<http://www.atmarkit.co.jp/fxml/ddd/ddd001/ddd001-namespaces1.html>