第3回
XML文書間のカット&ペースト(2):名前空間

XML文書間のカット&ペーストに関する問題の中で、今回は名前空間を中心に考察する。文書間を移動するカット断片の名前空間は、それだけに注目すると比較的単純な問題に見える。しかし、実体参照と絡まると話は一気に複雑になる。

■話題 カット&ペースト、名前空間、実体
■程度 A (XMLアプリケーショ ンの設計者、研究者などを対象とする)
■目的 問題点の分析
この連載を初めてお読みになる方は、「XML深層探求について」をご覧ください。

■事前に読むとよい関連記事

檜山正幸
2000/9/29


今回のおもな内容
1. はじめに
2. お約束 (前提、用語、記法など)
3. 名前空間の取り扱い
4. 実体における名前空間
5. 名前空間クローズドな実体
6. 互換性の考慮
7. まとめ
1. はじめに

 第2回に引き続き、XML文書間のカット&ペーストの問題を扱う。カット&ペーストに際して、名前空間をどう扱うか、また、実体参照と名前空間の相互関係について考える。さらに、「名前空間クローズド実体」という概念を導入して全体を整理する。


2. お約束(前提、用語、記法など)

 「実体」は、常に解析対象実体を意味する。解析対象外実体はまったく考えない。そのほかは第2回のお約束に従う。


3. 名前空間の取り扱い

 文書Aの一部分を文書Bのある場所(挿入点)に挿入する場合、XMLソースレベルの単純テキスト挿入では、名前空間に関しても具合が悪い点がある。例1の文書Aの指定部分をそのまま文書Bに挿入すれば、名前空間接頭辞の束縛(名前空間接頭辞と名前空間URIの対応関係)が変わってしまう。

例1:単純テキスト挿入によるカット&ペースト
[文書A]

<div xmlns="XHTML NS">
<!--** ここから **-->
  <p>北斗七星は大熊座の一部です。</p>
<!--** ここまで **-->
</div>

[文書B]

<simplePic xmlns="SIMPLE-PIC NS">
  <group style="background-color:black;color:white">
    <p coord="1,3" /><!-- 'p' は点(point)を意味する -->
    …中略…
  </group>
  <comment>
    <!--** ここに **-->
  </comment>
</simplePic>

[文書B'(ペーストの結果)]

<simplePic xmlns="SIMPLE-PIC NS">
  <group style="background-color:black;color:white">
    <p coord="1,3" /><!-- 'p' は点(point)を意味する -->
    …中略…
  </group>
  <comment>
    <p>北斗七星は大熊座の一部です。</p>
  </comment>
</simplePic>

  ペースト前とペースト後のフルネーム展開(第1回記事を参照)は次のようになる。

ペースト前:
<{XHTML NS}p>北斗七星は大熊座の一部です。</{XHTML NS}p>

ペースト後:
<{SIMPLE-PIC NS}p>北斗七星は大熊座の一部です。</{SIMPLE-PIC NS}p>

 段落(paragraph)が点(point)に変わってしまった。この難点を解決するのは比較的簡単である。次のように、ペーストされる部分に名前空間宣言を追加することで、束縛の変更から保護することができる。

例2:名前空間宣言を追加してペースト
[文書B'(ペーストの結果)]

<simplePic xmlns="SIMPLE-PIC NS">
  <group style="background-color:black;color:white">
    <p coord="1,3" /><!-- 'p' は点(point)を意味する -->
    …中略…
  </group>
  <comment>
    <p xmlns="XHTML NS">北斗七星は大熊座の一部です。</p>
  </comment>
</simplePic>

 名前空間宣言が入れ子のスコープを持てる点がここでは幸いしている。名前空間を保護するために必要な処理は、カット断片(第2回の「お約束」を参照)に対して、その中に出現するすべてのタグ名・属性名のフルネーム展開に必要な名前空間情報を一緒にした形で、クリップボードに入れることである。

 以上の例から、名前空間の問題は簡単に解決するように思える。しかし、実体参照と絡まると、がぜん話がややこしくなる。節を改めて述べよう。


4. 実体における名前空間

 次の例を考えよう。

<!DOCTYPE doc [
  <!ENTITY hello "<x:greet>hello</x:greet>">
]>
<doc>
  <foo>&hello;</foo>
  <bar xmlns:x="BAR NS">&hello;</bar>
  <zot xmlns:x="ZOT NS">&hello;</zot>
</doc>

 まず、DTD内部サブセット内の実体宣言であるが、XML 1.0の範囲内で考えると、このような実体宣言を拒絶する理由は何もない(名前空間仕様を考慮すると微妙な問題がある、これは後述する)。次に、要素 fooの内容に現れた実体参照&hello;を見てみよう。これはエラーとなる。&hello;出現段階では、名前空間接頭辞 xは束縛されていないから、「未定義の名前空間接頭辞の出現」としてエラーなのだ。

 文書からfoo要素を取り除けば、構文的なエラーは起こらない。しかし、同一の実体を参照する2つの&hello;がまったく異なる内容に展開される。第1回記事の記法を使うと、次のようになる。

<!-- bar の内部の&hello; -->
<{BAR NS}greet>hello</{BAR NS}greet>
<!-- zot の内部の&hello; -->
<{ZOT NS}greet>hello</{ZOT NS}greet>

 「XMLの実体メカニズムは、しょせん表層構文に対するテキストマクロ機能だ」と割り切ればあきらめもつくが、「実体が、それ自体として何らかのセマンティックスを持つ」と考えたい者には釈然としない状況である。この不安定性は、実体参照の置換テキストに未解決の名前空間接頭辞が出現することに起因する。

 では、名前空間仕様で、実体宣言の置換テキストに何らかの制約を設けているだろうか。私の解釈では、制約は何もないように思える。 現存する処理系のなかには、

<!ENTITY hello "<x:greet>hello</x:greet>">

をエラーとするものがあるが、次の例をエラーとすることはできまい。そして、この例でも、問題点は何も変わらない。

<!DOCTYPE doc [
  <!ENTITY hello "<greet>hello</greet>">
]>
<doc>
  <bar xmlns="BAR NS">&hello;</bar>
  <zot xmlns="ZOT NS">&hello;</zot>
</doc>

Note: 名前空間仕様では、文書の適合性を定義している。それによれば、宣言されていない名前空間接頭辞はエラーとなる。しかし、この制約は文書に関するも ので、解析対象実体(内部であれ外部であれ)にまでこの制約が及ぶとは書いてない。仮に、実体にも宣言済みの名前空間接頭辞を要求するにしても、実体宣言の時点における「宣言済み」という概念がハッキリしない。

Note: 実体宣言において、引用符で囲まれてたリテラル部分は実体値(entity value)と呼ぶ。置換テキストは、実体値とは多少異なる概念だ。実体値リテラル内の文字参照とパラメータ実体参照を展開した結果が置換テキストである。 しかし、この記事の文脈では、実体値と置換テキストを同じとみなしても差し支えない。


5. 名前空間クローズドな実体

 さて、ここでカット&ペーストに話題を戻す。今まで(第2回も含む)の考察から、われわれは次の方針を得た。

  1. [実体の保持] 実体参照を含むカット断片には、実体宣言を一緒に付ける。場合により、実体名のリネームを行う必要があるが、実体参照と実体の関係は保持する。
  2. [名前空間の保持] カット&ペーストの際に、カット断片に名前空間の情報を付加する。名前空間接頭辞と名前空間URIの関係は保持する。

 以上の方針を前提に、例1のbar内の&hello;部分をカット&ペーストすることを考えよう。「実体の保持」の方針により、カット断片は実体helloの実体宣言ともども移動される。しかし、ペーストの結果として、文書Bのスコープ内で名前空間の束縛が行われるから、「名前空間の保持」はできない。

図1 実体参照をそのままコピーすると、名前空間の束縛関係(オレンジ色の波線)が壊れる

 では、「名前空間の保持」を優先させてみよう。それには、名前空間の束縛(接頭辞と名前空間URIの対応関係)をカプセル化して運ぶべきだ。つまり、実体参照&hello;を出現位置で展開した上で、その文脈での名前空間宣言を書き加えなくてはならない(<x:greet xmlns:x="BAR NS">hello</x:greet>となる)。つまり、実体参照を実体参照のまま運ぶわけにはいかず、実体展開後に加工しなくてはならない。

図2 実体参照を展開してコピーすると、実体の参照関係(青の実線)が壊れる

 状況は「あちらを立てればこちらが立たず」だ。何らかの妥協をしなければ先には進めない。私の妥協案は、「名前空間束縛を持たない置換テキストを排除する」というものだ。例えば、"<x:greet>hello</x:greet>"は認めない。"<x:greet xmlns:x='X NS'>hello</x:greet>"または "<greet xmlns='X NS'>hello</greet>"のようにする。つまり、置換テキストだけで、フルネームへの展開が完全にできることを要求するのだ。そもそも、置換テキストに、何だかハッキリしないタグ名や属性名を含めるのは気持ち悪いではないか。

 今仮に、すべての名前がフルネームに展開可能な実体を、名前空間クローズドな実体(namespace-closed entity)と呼ぶことにしよう。すると、上の要求は次のように述べられる。

すべての実体は、名前空間クローズドであるべし。

 実体が名前空間クローズドなら、それへの参照は、出現位置(occurrence)に関わらず、常に同じ展開形(expanded form)を持つ。カット&ペーストに伴う不安定な状況は改善される。


6. 互換性の考慮

 次のXHTML文書を考えよう。

<!DOCTYPE html [
  <!ENTITY link
     '<a href="hogehoge.html">ホゲホゲのページ</a>' >
  ]>
<html xmlns="http://www.w3.org/1999/xhtml">
 <head><title>link to the hogehoge page</title></head>
  <body>
    <p>詳しくは、&link;を参照</p>
  </body>
</html>

 実体linkの宣言は、名前空間クローズドではない。実体宣言だけを見たのでは、

<a href="hogehoge.html">ホゲホゲのページ</a>

のタグ名aが、どの名前空間に属するかは分からない。しかし、われわれの今までの習慣と直感に従うなら、XHTMLの名前空間内のaのはずだ。つまり、次の解釈を採用する。

<!ENTITY link
  <a xmlns="http://www.w3.org/1999/xhtml" href="hogehoge.html">
  ホゲホゲのページ</a>
>

 「すべての実体は名前空間クローズドであるべし」という規約を厳守するなら、 実体内に名前空間宣言が必須となる。しかし、互換性の観点からいえば、名前空間接頭辞が付いていないなら、文書要素の名前空間を補完するのが自然だろう。この規約により、現存する実体宣言の多くを救済できる。もちろん、明示的に接頭辞が付いているタグ名・属性名が出現したら、その接頭辞の宣言を同じ実体内で要求することになる。


7. まとめ

 今回扱った内容をまとめると、次のようになる。

  1. カット断片と名前空間情報を一緒にして、カット&ペースト操作の対象とすれば、名前空間の保持は可能である。
  2. カット&ペーストに際して、実体参照の保持と名前空間の保持を両立させることはできない。
  3. 名前空間クローズドな実体だけの範囲なら、実体参照と名前空間の保持が可能である。
  4. 互換性の観点から、実体内に現れる接頭辞なしタグ名には、文書要素と同じ名前空間を与えるのは自然である。

■履歴
2000/9/29 公開

「XML深層探求」

 



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

注目のテーマ

HTML5+UX 記事ランキング

本日月間