2002年12月8日(日)更新 |
■データにID(Identification)をつけて管理
たけち: 何か平成の世では「住基ネット」だかで騒いでいるよね。 さらら: そうみたいね。でもやっぱり私も、自分に背番号みたいなものがつけられていたら、何か嫌な気がするわ。 たけち: 確かに心情としてそう思う人は少なくないだろうね。ただ、こういうやり方が良いか悪いかは別として、コンピュータでデータを管理しようと思ったら、それぞれの人や物、データにID(Identification)をつけて管理することは一般的なことなんだよね。 さらら: ふ〜ん、でも、人の名前そのもので管理すればいい気がするけれど。 たけち: それだと、例えば「鈴木一郎」なんていう名前の同姓同名の人が、日本に何人もいると思われるんだけど、人名だけで管理していたら、こういう同姓同名の人が出てくると、それが同一人物なのか、違う人なのか区別ができなくなってしまうよね。だから、IDを別途設けて管理する必要性があるんだ。 さらら: あ、そうか。でも、今までそんなことをしなくても、何とかなっていたんでしょ。 |
■データの一意性
たけち: そうだね。今まではIDを設ける代わりに、同姓同名の人をどう区別するか、ということで本籍地を使っていたんだ。本籍地というのは、日本国内だったら、出身地や現住所などとまったく関係なく、どこにでも定めても良いとされている。何故こんな「出身地や現住所と関係なくてもかまわない地名」が必要かというと、結局、人名だけでは同姓同名の人を区別できないから、それに本籍地を付けることにより「○○県○○市○○町○○番地の鈴木一郎」さんということで、一人に絞り込むことができるからなんだ。ただし、この方式の欠点はとにかく「長い」ということなんだよ。それに対してコンピュータだと、人とは違って、意味が通じないような記号数字の羅列でもきちんと高速で検索できるから、比較的短いID番号を使って管理したほうが良いということになるんだね。IDに求められている条件はただ一つ、どんな文字や数字を使ってもいいから、それの「一意性」が保証されているということなんだ。 さらら: 「一意性」って? たけち: それを扱っている範囲で、同じ名前の物が2つ以上ない、ということだよ。一つの名前が指し示すものが、一つしかない、ということなんだ。コンピュータのプログラミングはコンピュータ用の「言葉」を使って操作するよね。だから、その「言葉」に対応するものが、2つも3つもあっては困る。一つの言葉に対応するものは一つだけでなければいけない、ということだね。 さらら: そっか。まあ、そう言われてみれば、何か常識的な感じがするわね (^ ^;) |
■XMLデータ例: 歌番号による歌の一意性(まずい例)
たけち: さて、話をXMLの方に移すと、XMLの前のドキュメント指向が中心であったSGMLの時代といえども、やっぱり「データをID管理する」ということは、とても重要なことだったんだよね。SGMLのドキュメント指向の文書でも、データを参照して文書の中に埋め込むことはあるし、そのデータ自身をIDを使って管理したい、というような要望はあったと思うんだよ。 さらら: ふ〜ん。 たけち: ここで大事なのは、そういう基本的な要望はSGMLの時代からあったし、そしてSGMLの時代にスキーマを書くことができる方法はDTDしかなかった、ということなんだ。そしてDTDは、要素についてはデータ型を適用できないけれど、属性についてはデータ型を適用できる。そして、データをID管理するためには、要素の内容をID管理の対象としようとすると、結構大きくDTDの仕様を拡張しないといけないという問題点があるけれど、属性の値をID管理の対象にするには特殊なデータ型を使えば何とかなる、という解決策が見出されたんだね。 さらら: え?(@o@) よくわからないけど (^ ^;) たけち: あ、まあ、まずは実例を見てみるね(^^;) 僕とさららが歌集の選者(Anthologist)として、歌集(Anthology)を作ることにするね。以下がそのXMLデータだよ。 |
※XMLデータ例: 歌集(Anthology) <?xml version="1.0" encoding="Shit_JIS" ?> |
たけち: 「歌が3つしかないものを歌集と呼べるか?」と言われそうだけれど、これはあくまで単純化した例だから、これで許してね(^^;) このXMLデータでは最初にpeopleという要素の内容として、人物データベースというべきものを構築しているんだ、peopleの子要素であるpersonでは、それぞれの人物について、名前、性別、生年、没年のデータを持ち、そしてid属性としてIDの値を入れているデータになっている。そして実際の歌集の中身poems要素を構成するpoem要素では、歌の作者poet属性の値として、person要素のid値が参照されている。また、実際にこの歌集を編纂した編者達を示すanthologists要素では、そのpoeple属性によってperson要素のid値が参照されているんだ。これをDTDで書いたらどうなると思う。 さらら: え、えーと、こうかしら(^^;) |
|
※DTD例: 歌集(Anthology) ..... by さらら
<!ELEMENT anthology (people, poems, anthologists)> |
たけち: そうだね、こういう書き方でもさっきのXMLデータと合致するよね。 さらら: あぁ、良かった(^^) たけち: だけど、この書き方だと2つ問題があるんだ。 |
※さららの書いたDTDの問題点 1.people要素のid属性の一意性が保証されていない。 2.poem要素のpoet属性が参照している値や、anthologists要素のpeople属性が参照している値が、people要素のid属性の値であるという保証がない。 |
さらら: え? (^ ^;) たけち: 例えば以下のXMLデータを見てみようね。 |
※XMLデータ例: idが一意でない
<?xml version="1.0" encoding="Shift_JIS" ?> |
たけち: このデータは実はわざとでたらめなことをしているんだ。どういうところがでたらめかというと、まずperson要素のid属性の値が、p03とp04なんて2回だぶって出てきているよね。つまり一意性が破綻していて、IDとしての役割を果たしていないんだね。それからpoem要素のpoet属性はp07という存在しないデータのIDを参照しようとしているし、anthologists要素のpeople属性もp08という存在しないデータのIDを参照しようとしている。つまりIDの管理がきちんとできていないんだ。 さらら: う〜ん、確かにこれは変なデータだわ。 たけち: だけど、さっきのさららが書いたDTDだと、これでも問題なしということで、パスしてしまうんだね。 |
|
■ID型, IDREF型, IDREFS型
さらら: あ、そうなのね(^^;) でも、DTDが検証すべきなのは要素と属性の出現といった文法上の問題よね。こういうデータの中身がおかしいものまで検証させようというのは、スキーマ言語が検証すべき範囲を越えているんじゃないかしら。 たけち: 確かに厳密に考えると、これもスキーマ言語が検証すべきことなのかどうか、さららの言うとおり、ちょっと怪しい感じがするよね。だけど、やっぱりこういったものもDTDがチェックしてくれると便利だ、という要望はSGMLの昔から強いものがあったと思うよ。 さらら: うーん、それは確かに便利よね。 たけち: そこで、ID型, IDREF型, IDREFS型といった特殊なデータ型を使って、IDの管理をする方法をDTDは採用したんだ。これらのデータ型を使ったDTDの書き方を以下に示すね。 |
|
※DTD例: 歌集(Anthology) ..... by たけち
<!ELEMENT anthology (people, poems, anthologists)> |
さらら: あら、さっきの私が書いたDTDとほとんど変わらないじゃない? たけち: そうだね、要素型宣言と属性リスト宣言の出現の仕方は、まったくさららの書いたDTDとは変わっていない。実は変更になったのは属性リスト宣言の中のデータ型のところだけなんだ。NMTOKEN型と書かれていたperson要素のid属性はID型に変更されているし、poem要素のpoet属性はIDREF型に変更されている。そしてanthologists要素のpeople属性も、NMTOKENS型からIDREFS型に変更されているんだよ。 さらら: あ、この3箇所が変更されたのね。 たけち: こういうふうな書き方によってIDを管理し、そしてそれを安心して参照する仕組みが提供されているんだね。まずperson要素のid属性がID型として定義されている。これによって、idという属性の値の一意性が保たれているかどうかを検証する、つまり2つと同じものがないかどうかということを検証するようになるんだ。 さらら: へ〜、こんなデータ型を使うことによって、IDの管理ができるのね。割と簡単なことなのね。 |
|
■ID型, IDREF型, IDREFS型
たけち: そうだね、ID型、そしてIDREF型とIDREFS型を使ってID管理する利点は「簡単」ということなんだ。何しろ本来、NMTOKEN型やNMTOKENS型、またはCDATA型を使うべきところを、これらのデータ型に置き換えるだけでIDの管理ができるようになるんだから、簡単なんだよね。 さらら: じゃあこれでXMLデータのIDの管理は完璧なのね(^^) たけち: いや、確かに「簡単に使える」という意味では素晴らしい方法なんだけれどね、でも、その一方でいろいろな欠点があるんだよ。 さらら: え、どんな欠点が? たけち: ID型、そしてIDREF型とIDREFS型を使ったIDの管理方法には、以下のようないくつもの欠点があるんだ。 |
※ID型、IDREF型、IDREFS型によるIDの管理方法の欠点 1.IDとなるもの、そしてIDを参照するものは属性でなければならない。要素の内容をIDにしたり、要素の内容でIDを参照するような場合の検証は不可能である。 2.複数の要素型の中の属性をIDとして設定した場合、それぞれを別々に独立した一意性を持った対象としての検証は不可能であり、XMLデータ全体が一意性の検証対象となる。 3-1.一つの要素型においては、IDとして取り扱うことができるのは一つの属性のみである。一つの要素型の中で、複数の属性をIDとして取り扱うことはできない。 4.IDの有効範囲はそのXMLデータ全体であると最初から決められている。そのため、一部の特定の範囲をIDの有効範囲として指定することは不可能である。 5.ID型は、データ型の形式としてはNCName型となっている。 |
さらら: うわー、いっぱい欠点があるのね(^^;) たけち: まず1.の意味はわかるよね。次のデータをみて。 |
※ID型、IDREF型、IDREFS型によるIDの管理方法の欠点-(1) 1.IDとなるもの、そしてIDを参照するものは属性でなければならない。要素の内容をIDにしたり、要素の内容でIDを参照するような場合の検証は不可能である。
<person> |
たけち: このような書き方ではid要素の内容をIDとしては設定できない、ということだね。 さらら: こういう要素を使った書き方でも、やはり同じことができて欲しいわよね。それから、2.はどんな意味なの? たけち: 例えば次のようなXMLデータを考えようか。 |
※ID型、IDREF型、IDREFS型によるIDの管理方法の欠点-(2) 2.複数の要素型の中の属性をIDとして設定した場合、それぞれを別々に独立した一意性を持った対象としての検証は不可能であり、XMLデータ全体が一意性の検証対象となる。
<?xml version="1.0" encoding="Shift_JIS" ?> |
たけち: ここではpoem要素の属性としてさらに歌番号であるpno属性を加えてみたけれど、本来、このpno属性も通し番号だからIDとして扱いたいよね。ところがID型を使ってIDの管理をしようとすると、idの中だけの一意性と、pnoの中だけの一意性とを、別々に独立させて検証することができないんだ。一つのXMLファイルの中では、id属性もpno属性も同一の検証範囲になってしまう。そのため両方に同じ値が出現するとエラーになるんだ。 さらら: あら、それって面倒だわ。 たけち: そうだね、ちょっとこの制限には気をつけないといけないよね。 |
|
さらら: 3はどういう意味なの? たけち: 例えば、次のXMLデータを見てみようね。 |
※ID型、IDREF型、IDREFS型によるIDの管理方法の欠点-(3) 3-1.一つの要素型においては、IDとして取り扱うことができるのは一つの属性のみである。一つの要素型の中で、複数の属性をIDとして取り扱うことはできない。
<?xml version="1.0" encoding="Shift_JIS" ?> |
たけち: この場合、歌の通し番号であるpno属性だけでは一意性は保証されないんだ。でも、pno属性とanthology属性を組み合わせれば、その一意性は保証されるはずだよね。でもこういう組み合わせで一意性を保証する方法が、ID型ではできないんだ。 さらら: あ、なるほどね。じゃあ 4.の「IDの有効範囲」って何? たけち: 今度は、さっきのXMLデータを少し変更して、次のようなXMLデータを考えてみようね。 |
※ID型、IDREF型、IDREFS型によるIDの管理方法の欠点-(4) 4.IDの有効範囲はそのXMLデータ全体であると最初から決められている。そのため、一部の特定の範囲をIDの有効範囲として指定することは不可能である。
<?xml version="1.0" encoding="Shift_JIS" ?> |
たけち: この場合、XMLデータ全体としてはpno属性の一意性は保たれていない。でもそれぞれのanthology要素の中だけを見ると、pno属性の一意性が保たれているよね。ところがこういう場合もID型では、設定することができないんだ。 さらら: なるほど。あ、それから5.の数字だけのものが使えない、というのも痛いわね。 たけち: そうだね。世の中には数字だけのIDなんていくらでもあるからね。まあ最初の一文字に適当にアルファベットでも付ければそれで何とかなるとはいえ、やっぱりそのまま使えないのもちょっと苦しいよね。 |
|
■XML SchemaでもID型があります
さらら: ということはXML SchemaではID型がなくなって、新しくIDの管理をするための仕組みが提供されているのね(^^) たけち: いや、確かにXML SchemaではIDの管理をするための新しい仕組みが提供されているけれど、ID型、そしてIDREF型とIDREFS型は生き残っているんだよ(^^;) さらら: あら?(^^;) たけち: どうしてかというと、XML Schemaでこれらを廃止してしまったら、DTDからの移行が難しくなるからなんだ。だからXML SchemaでもDTDとの互換性のために残しているんだよ。 さらら: 結局、XML Schemaにも同じものがあるのね (^ ^;) たけち: ただし、ここで注意しておかないといけないのは、XML Schemaのこれらのデータ型はあくまでDTDとの互換性のために残されている、ということなんだよ。以前、単純型というのは「要素にも属性にも使えるデータ型」として紹介したけれど、こういうDTDとの互換性のために残されたデータ型は、属性だけで使うべきなんだ。 |
|
さらら: 要素に使ってはいけないの? たけち: うーん、そこが微妙なところだけれど... 一応、W3Cの仕様書「XML Schema Part 2: Datatypes」(http://www.w3.org/TR/xmlschema-2/)には、「使ってはいけない」とまでは書いていないんだ。実際、要素にID型を使ってもそれを通してしまうValidatorは存在するんだよ。だけど、 ID should be used only on attributes. と書かれているんだよね。だから、やっぱりここは要素に使うのはやめておいた方がいいよね。 さらら: そうなののね。 たけち: さて、じゃあ実際にさっきのDTDをXML Schemaにしてみようね。もうだいたい書くことができるよね(^^) さらら: どきっ..... (^ ^;) |
※XML Schema: 歌集(Anthology)
<?xml version="1.0" encoding="Shift_JIS" ?> |
たけち: こういう形になるんだよね。 さらら: 結局、DTDと使い方は同じね(^^;) たけち: そうだね。こういうふうに気軽に簡単に使えるのがID型、そしてIDREF型とIDREFS型の良いところなんだよ。ただしその一方で、これらには上記にあげたような欠点と限界を持っていることにも気をつけてね。次回は、このID型の欠点を解消した本格的なID管理方法である「key」について勉強しようね。今回と比べてだいぶ難しくなるけれど、頑張ろうね。 さらら: は〜い。 次回はkey, keyref, unique: その1です。(^ ^)v |
|
■(*注1) XMLの仕様書「Extensible Markup Language (XML) 1.0 (Second Edition)」(http://www.w3.org/TR/REC-xml)では、 |
■XMLスキーマのコーナーは、TAKABEさま(XSLTの遊び部屋)の全面的なご協力をいただいて作成しています。 |