名前空間とスキーマ(1)

2003年1月12日(日)更新


■むやみに新しいスキーマを作らない

さらら: だいぶいろいろなXML Schemaの技術を学んできたけれど、実際にスキーマを作ろうと思ったら、結構、難しそうね。

たけち: そうだね。今まで学んできたもの、そしてこれからもしばらく学ばないといけないものは「こうしたい時にはどうしたらいいか」というXML Schemaのテクニックなんだよね。
でも、実際にスキーマを作ろうと思ったら、「この問題に対しては、どういうスキーマを作るべきか」という、XML Schemaを使う以前の大きな課題もあるから、また別にいろいろなことを考えないといけないんだよね。

さらら: う〜ん、大変そう。

たけち: でもねぇ。。

さらら: えっ?

たけち: そうだね。ここでスキーマを作る際の究極の奥義を、さららに教えとこうかな (^ ^)

さらら

さらら: え、なになに、スキーマを作る際の究極の奥義ってどんなの?

たけち: これはとても大事なことだからよく聞いてね。スキーマを作る際の究極の奥義とは...

さらら: えぇ、それは。。。

たけち: スキーマを作らないということ。

さらら: えっ? .....ねぇ、たけちって私のことを馬鹿にしてない?(- -;)

たけち: あ、ごめん。別にそんな意味じゃないんだよ。確かにこの言葉には、逆説的なことを言って人を驚かせているようなところがあるけれど、ちゃんと真面目な意味がこめられているんだよ。例えば
「剣の道の究極の奥義とは、剣を使わずにすますことである」
 とかいうと、結構奥深い言葉になるよね。

さらら: まあそう言われればそうだけど・・・・・

たけち: スキーマを作る際の究極の奥義とは、スキーマを作らないことであるというは、下手な、自分だけが満足しているスキーマを濫造するのではなくて、先人の作った考え抜かれた上手なスキーマをなるべく再利用し、どうしても必要な部分だけ、自分でスキーマを作りなさい、といった意味なんだ。

たけち

■いろいろなスキーマを作ってみましょう

さらら: あぁ。。。。なんとなくわかるわ。

たけち: 次のXMLデータを見てみようね。

XMLデータ例: 万葉歌と解説-1
<?xml version="1.0" encoding="Shift_JIS" ?>
<document>
<h1>第十八巻 : さ百合花ゆりも逢はむと思へこそ</h1>
<poem pno="4088">
<poet>大伴家持</poet>
<kana>左由理婆奈 由里毛安波牟等 於毛倍許曽 伊末能麻左可母 宇流波之美須礼</kana>
<yomi>さ百合花、ゆりも逢はむと、思へこそ、今のまさかも、うるはしみすれ</yomi>
</poem>

<kaisetsu>
<p>越中の秦伊美吉石竹の館で行われた宴会の席で、石竹が大伴家持たちに、<em>百合で作った髪飾り</em>を三つ贈りました。このときに大伴家持が詠んだ歌です。</p>
<p>「ゆり」とは、「後で」という意味です。</p>
</kaisetsu>
</document>

さらら: 家持さんの歌ね。

たけち: 一見、まったく問題がないように見えるXMLデータだけれど、これには問題点があるんだよ。

さらら: えっ?、全然問題がないように見えるわ。

たけち: そうだね。じゃあ、まずはDTDを書いてみようね(^ ^)

さらら: あっ。う〜ん。。。こうかしら。(^ ^;

さらら

DTD例: 万葉歌と解説-1
<!ELEMENT document (h1, poem, kaisetsu)>

<!ELEMENT h1 (#PCDATA)>

<!ELEMENT poem (poet, kana, yomi)>
<!ATTLIST poem pno NMTOKEN #REQUIRED>
<!ELEMENT poet (#PCDATA)>
<!ELEMENT kana (#PCDATA)>
<!ELEMENT yomi (#PCDATA)>


<!ELEMENT kaisetsu (p*)>
<!ELEMENT p (#PCDATA | em)*>
<!ELEMENT em (#PCDATA)>

たけち: そうだね、こういう書き方で一応通るよね。それじゃあ今度は次のXMLデータのDTDも考えてみようね。

XMLデータ例: 万葉歌と解説-2
<?xml version="1.0" encoding="Shift_JIS" ?>
<poems>
<poem pno="4086">
<poet>大伴家持</poet>
<kana>安夫良火乃 比可里尓見由流 和我可豆良 佐由利能波奈能 恵麻波之伎香母</kana>
<yomi>油火の、光りに見ゆる、吾がかづら、さ百合の花の、笑まはしきかも</yomi>
</poem>
<poem pno="4087">
<poet>内蔵縄麻呂</poet>
<kana>等毛之火能 比可里尓見由流 左由理婆奈 由利毛安波牟等 於母比曽米弖伎</kana>
<yomi>灯火)の、光りに見ゆる、さ百合花、ゆりも逢はむと、思ひそめてき</yomi>
</poem>
<poem pno="4088">
<poet>大伴家持</poet>
<kana>左由理婆奈 由里毛安波牟等 於毛倍許曽 伊末能麻左可母 宇流波之美須礼</kana>
<yomi>さ百合花、ゆりも逢はむと、思へこそ、今のまさかも、うるはしみすれ</yomi>
</poem>

</poems>

さらら: え〜と、これのDTDなら同じようなパターンを何度もしてきたから、だいたいわかるわ。え〜っと......

DTD例: 万葉歌と解説-2
<!ELEMENT poems (poem*)>

<!ELEMENT poem (poet, kana, yomi)>
<!ATTLIST poem pno NMTOKEN #REQUIRED>
<!ELEMENT poet (#PCDATA)>
<!ELEMENT kana (#PCDATA)>
<!ELEMENT yomi (#PCDATA)>

たけち: そうだね (^ ^*) じゃあ、たて続けに第3弾行くよ。次のDTDはちょっと難しいかな(^ ^;)

さらら: えっ。まだやるの?!

XMLデータ例: 万葉歌と解説-3
<?xml version="1.0" encoding="Shift_JIS" ?>
<font color="navy">第十八巻の歌</font>
</h1>
<p align="right">672年10月9日更新</p>
<hr align="center" width="480" size="3" />
<p class="takechi"><strong>たけち</strong>: 前回は万葉集17巻の歌について見てみたよね。今回は18巻の歌についてみてみるね。</p>
<p class="sarara"><strong>さらら</strong>: お手柔らかにね。</p>
<p class="takechi"><strong>たけち</strong>: まずは次の歌を見てみようか。</p>
<poem pno="4088">
<poet>大伴家持</poet>
<kana>左由理婆奈 由里毛安波牟等 於毛倍許曽 伊末能麻左可母 宇流波之美須礼</kana>
<yomi>さ百合花、ゆりも逢はむと、思へこそ、今のまさかも、うるはしみすれ</yomi>
</poem>

<p class="takechi"><strong>たけち</strong>: この歌は越中の秦伊美吉石竹の館で行われた宴会の席で、石竹が大伴家持たちに、<em>百合で作った髪飾り</em>を三つ贈ったんだ。このときに<font color="red">大伴家持</font>が詠んだ歌なんだよ。</p>
<p class="sarara"><strong>さらら</strong>: へぇー、そうなのね。</p>
</document>

さらら: きゃ〜、何、このHTMLもどきは(^ ^;) こんなのとてもできないわ(^ ^;)......

たけち: これは、例えば次のような書き方のDTDに合うかなぁ。本物のXHTMLのDTDとは程遠いけどね。(^ ^;)

DTD例: 万葉歌と解説-3
<!ENTITY % Inline "(#PCDATA | font | strong | em)*">
<!ENTITY % coreattrs
        "class          CDATA          #IMPLIED"
>
<!ENTITY % TextAlign "align (left|center|right|justify) #IMPLIED">


<!ELEMENT document (h1 | p | hr | poem)*>

<!ELEMENT h1 %Inline;>
<!ATTLIST h1
        %coreattrs;
        %TextAlign;
>
<!ELEMENT p %Inline;>
<!ATTLIST p
        %coreattrs;
        %TextAlign;
>

<!ELEMENT hr EMPTY>
<!ATTLIST hr
        %coreattrs;
        align          (left|center|right)      #IMPLIED
        noshade      (noshade)          #IMPLIED
        size          CDATA          #IMPLIED
         width       CDATA          #IMPLIED
>
<!ELEMENT font %Inline;>
<!ATTLIST font
        %coreattrs;
        size          CDATA          #IMPLIED
        color         CDATA          #IMPLIED
        face          CDATA          #IMPLIED
>
<!ELEMENT em %Inline;>
<!ATTLIST em %coreattrs;>

<!ELEMENT strong %Inline;>
<!ATTLIST strong %coreattrs;>

<!ELEMENT poem (poet, kana, yomi)>
<!ATTLIST poem pno NMTOKEN #REQUIRED>
<!ELEMENT poet (#PCDATA)>
<!ELEMENT kana (#PCDATA)>
<!ELEMENT yomi (#PCDATA)>

たけち

さらら: あ〜ん。。やっぱりややこしそう。(^ ^;)

たけち: 本物のXHTMLのDTD(http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd(注1))はもっと凄いよ。。。(^ ^;) でも、綺麗にまとめられていて、とても勉強になるから是非見てみようね。

さらら: えっ、えぇ。。。(^ ^;

たけち: .さて、3つの異なるXMLデータとそのDTDを見てもらったんだけれど、この3つに共通するものってわかるかい?

さらら: え〜と。。。。。次の部分だわね。

上記3つのXMLデータの共通部分
<poem pno="4088">
<poet>大伴家持</poet>
<kana>左由理婆奈 由里毛安波牟等 於毛倍許曽 伊末能麻左可母 宇流波之美須礼</kana>
<yomi>さ百合花、ゆりも逢はむと、思へこそ、今のまさかも、うるはしみすれ</yomi>
</poem>

たけち: そうだね。

さらら: DTDだと次の部分なのよね。そうでしょ。

上記3つのDTDの共通部分
<!ELEMENT poem (poet, kana, yomi)>
<!ATTLIST poem pno NMTOKEN #REQUIRED>
<!ELEMENT poet (#PCDATA)>
<!ELEMENT kana (#PCDATA)>
<!ELEMENT yomi (#PCDATA)>


■無駄にスキーマを量産しないようにしましょう

たけち: そうだね。1番目の例は歌をあげてその解説をしている、いわゆる「解説」型のドキュメントだね。そして2番目は歌を並べている「歌集」型のドキュメントだね。そして最後の3番目は会話の中に歌が出てくる「会話」型のドキュメントになっているんだね。
「解説」と「歌集」と「会話」では、DTDが違ってきて当然だし、実際にそうなっているよね。でも、歌という共通点を持ち、そして歌の部分では同じDTDの構造を持っているわけだね。というところで、考えてみると、同じようなDTDを3回も新たに書くというのは無駄なことをしているように思えるよね。

さらら: そうね。無駄と言えば無駄よね。似たようなものや同じものを3回も書くというのは、ね。

たけち: さらにh1要素やp要素やem要素の定義を考えると、1番目に出てきたDTDの

たけち

<!ELEMENT h1 (#PCDATA)>

<!ELEMENT p (#PCDATA | em)*>
<!ELEMENT em (#PCDATA)>

たけち:  という部分は、3番目に出てきたDTDの、

<!ENTITY % Inline "(#PCDATA | font | strong | em)*">
<!ENTITY % coreattrs
        "class          CDATA          #IMPLIED"
>
<!ENTITY % TextAlign "align (left|center|right|justify) #IMPLIED">

<!ELEMENT h1 %Inline;>
<!ATTLIST h1
        %coreattrs;
        %TextAlign;
>
<!ELEMENT p %Inline;>
<!ATTLIST p
        %coreattrs;
        %TextAlign;
>
<!ELEMENT em %Inline;>
<!ATTLIST em %coreattrs;>

たけち:  と実は同じなんだよね。3番目の方がより詳しい定義のしかたをしているので、一見別物に見えるけれど、この3番目のh1要素やp要素やem要素の定義の仕方で、1番目のXMLデータのh1要素やp要素やem要素を検証することも可能だよね。結局1番目も3番目も、少し違う形でXHTMLの真似をしているだけなんだね。

さらら: そう言われればそうだわね。

たけち: ここでは、3つの例を出したけれど、これからさらに歌にまつわる別のドキュメント構造が必要になればなるほど、一部が同じで一部が違うというDTDがどんどん増えていくことになるね。
これって効率が悪くて無駄が多いことだよね。特にh1要素やp要素やem要素なんかは、既にW3Cが定めたきちんとしたXHTMLのDTDがあるのに、それとは別に、それと似たようなDTDをいくつも書かないといけないなんて、特に無駄な気がするよね。

さらら: それは、そうだわ。とっても無駄なことをしているわね。

たけち

たけち: そう考えると、ほとんどその共通部分からできているたとえば2番目のDTDについては、これを共通部分を持っているDTDから参照したくなるよね。それからXHTML系要素について書いた部分についても、こんな偽物のXHTMLのDTDを何回も書くくらいだったら、本物のW3Cが定めたXHTMLのDTDを参照したいよね。

さらら: えぇ、それはそうだわね。でも、そんなことができるの? (^ ^;)


■XHTMLのDTDを参照する

たけち: それが可能なんだよ。まずは実例を見てもらった方が早いよね。これをするにはまずXHTML系のDTDは、インターネット対応のDTDのパーサーがあればいいんだけれど、あまりそういうのがなさそうだから、
ここでは本物のXHTMLのDTDである
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
を、同じフォルダにxhtml1-transitional.dtdとしてダウンロードしておこうね。
さらにこれが必要としている
http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent
http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent
http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent
などについても、それぞれ同じフォルダにxhtml-lat1.ent, xhtml-symbol.ent, xhtml-special.entとしてダウンロードしておくことにするよ。

さらら: えぇ。

たけち: そうすると、1番目の例のDTDは次のように書くことができるんだよ。

たけち

DTD例: 万葉歌と解説-1 他のDTDを参照
<!ENTITY % manyouPoem SYSTEM "manyouPoem.dtd">
%manyouPoem;

<!ENTITY % XHTML SYSTEM "xhtml1-transitional.dtd">
%XHTML;

<!ELEMENT document (h1, poem, kaisetsu)>
<!ELEMENT kaisetsu (%block;)*>


manyouPoem.dtd
<!ELEMENT poem (poet, kana, yomi)>
<!ATTLIST poem pno NMTOKEN #REQUIRED>
<!ELEMENT poet (#PCDATA)>
<!ELEMENT kana (#PCDATA)>
<!ELEMENT yomi (#PCDATA)>

たけち: それから、3番目の例のDTDは、こう書くことができるんだよ。

DTD例: 万葉歌と解説-3 他のDTDを参照
<!ENTITY % manyouPoem SYSTEM "manyouPoem.dtd">
%manyouPoem;

<!ENTITY % XHTML SYSTEM "xhtml1-transitional.dtd">
%XHTML;

<!ELEMENT document (%block; | poem)*>

たけち: さっきのDTDと比較してみるとわかるけれど、DTDが随分短くなったよね。(^ ^) こういうふうに、共通となる他のDTDを参照することによって、新たに書かなくても良くなったんだね。

さらら: そうね。本当に短くなっているわ。(^ ^)

たけち:  ちなみにここに出てくる「%block;」というのは、xhtml1-transitional.dtd の中に出てくるけれど、

さらら

<!ENTITY % block
      "p | %heading; | div | %lists; | %blocktext; | isindex |fieldset | table">

 というもので、p要素だけでなくて、h1のようなheading系の要素、div要素、table要素等を含むものなんだ。だから、

<!ELEMENT document (%block; | poem)*>

 というのは、

<!ELEMENT document
    (p | %heading; | div | %lists; | %blocktext; | isindex |fieldset | table | poem)*>>

  という意味になって、p要素やh1要素だけでなく、それ以外のこれらのXHTML系要素も使えるようになるんだね。

さらら: よくわからないけど、凄〜い! あんなに長かったDTDがこんなに短くまとまった上に、さらに複雑なことができるDTDになっているのね! これだと完璧ね!(^ ^)

たけち: そう、確かに凄く綺麗に簡潔になったよね。まあもっとも、実は完璧じゃなくて、大きな問題点もあるんだけどね...(^ ^;)

さらら: あらま (^ ^;)

たけち: 確かに素晴らしいテクニックなんだけれど、このテクニックをDTDで利用する際の問題点は、
参照する側のDTDでは、参照される側のDTDの中で定義されているのと同じ名前の要素の要素型宣言が出現してはならない。また参照されるDTDが複数あるとき、それらの中に同じ名前の要素の要素型宣言が存在してはならない
 ということなんだ。
例えば参照される「manyouPoem.dtd」の方にはyomi要素が要素型宣言されているよね。ということは、参照する側のDTDでは、また別のyomiという名前の要素の要素型宣言はできないんだ。
つまり、まず最初に参照される外部DTDにどんな要素があるか全て知った上でないと、スキーマを決めることができないということだね。
例え参照される外部DTDの要素の一部しか使わなくてもね。さらに言うと、上記のように複数のDTDを参照したい場合、それらの中に名前が同じ要素の要素型宣言が出てくると、例えそれらが同じ定義であっても、そしてそれらを使わなくても、エラーになってしまうんだね。
例えばXHTMLにはtitleという名前の要素があるけれど、これにもし「manyouPoem.dtd」の方にもtitleという名前の要素型宣言があったら、それだけでエラーになってしまうんだ。ということは、別々の人が作ったDTDをいろいろと組み合わせて使いたいとき、当然、同じ名前の要素が出てくる可能性があるから、そうなったらもうその組み合わせは使えないんだよね。

たけち

さらら: う〜ん、それは困るわ。

たけち: この問題を解決するためには、要するに、皆それぞれが作るスキーマの要素名が、全部違っていればいいんだよね。つまりそれぞれの人が作る要素の名前の衝突が起きなければうまくいくんだ。

さらら: え、そんなことができるの?

たけち: うん、それじゃあ次回は本格的に「名前空間」について話すことにするね。

さらら: あっ、は〜い!!

次回は名前空間とスキーマ(2)です。...... (^ ^)v


XMLスキーマのコーナーは、TAKABEさま(XSLTの遊び部屋)の全面的なご協力をいただいて作成しています。