key, keyref, unique: その2

2002年12月22日(日)更新


■ID型・IDREF型 → key・keyref

たけち: まずは実際に実例を見てみようね。ID型・IDREF型のときの復習だけれど、こんな例をやったね

※※XMLデータ例: 歌集(Anthology)

<?xml version="1.0" encoding="Shift_JIS" ?>
<anthology>
<people>

<person id="p01">
<name>持統天皇</name>
<sex>female</sex>
<birth>0645</birth>
<death>0702</death>
</person>

<person id="p02">
<name>高市皇子</name>
<sex>male</sex>
<birth>0654</birth>
<death>0696</death>
</person>

<person id="p03">
<name>大伴家持</name>
<sex>male</sex>
<birth>0718</birth>
<death>0785</death>
</person>

<person id="p04">
<name>坂上郎女</name>
<sex>female</sex>
<birth>0700</birth>
<death>0750</death>
</person>

<person id="p05">
<name>柿本人麻呂</name>
<sex>male</sex>
<birth>0645</birth>
<death>0701</death>
</person>

</people>

<poems>
<poem poet="p01">春過ぎて夏来たるらし白妙の衣干したり天の香具山</poem>
<poem poet="p05">後見むと君が結べる磐代の小松がうれをまたも見むかも</poem>
<poem poet="p03">なでしこがその花にもが朝な朝な手に取り持ちて恋ひぬ日なけむ</poem>
</poems>

</anthology>

さらら: あっ、そのときの例だったわね。

たけち: でもこのXMLデータに相当する、ID型やIDREF型を使ってXML Schemaはどうだったかな?

さらら: え、......えっと、こうだったわよね(^^;

さらら

XML Schema: 歌集(Anthology)

<?xml version="1.0" encoding="Shift_JIS" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<xsd:element name="anthology" type="AnthologyType" />

<xsd:complexType name="AnthologyType">
<xsd:sequence>
<xsd:element ref="people" />
<xsd:element ref="poems" />
<xsd:element ref="anthologists" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="people" type="PeopleType" />

<xsd:complexType name="PeopleType">
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="person" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="person" type="PersonType" />

<xsd:complexType name="PersonType">
<xsd:sequence>
<xsd:element ref="name" />
<xsd:element ref="sex" />
<xsd:element ref="birth" />
<xsd:element ref="death" />
</xsd:sequence>
<xsd:attribute name="id" type="xsd:ID" use="required" />
</xsd:complexType>

<xsd:element name="name" type="xsd:string" />
<xsd:element name="sex" type="SexType" />
<xsd:element name="birth" type="xsd:gYear" />
<xsd:element name="death" type="xsd:gYear" />

<xsd:simpleType name="SexType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="male" />
<xsd:enumeration value="female" />
</xsd:restriction>
</xsd:simpleType>

<xsd:element name="poems" type="PoemsType" />

<xsd:complexType name="PoemsType">
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="poem" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="poem" type="PoemType" />

<xsd:complexType name="PoemType">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="poet" type="xsd:IDREF" use="required" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>

</xsd:schema>

たけち: そうだね。これをまずはID型とIDREF型をやめて、keyとkeyrefを使った書き方に改めてみようね。ID型やIDREF型であった部分は、NCName型としておくね。

XML Schema: 歌集(Anthology) ・・・・・keyとkeyrefを使用

<?xml version="1.0" encoding="Shift_JIS" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<xsd:element name="anthology" type="AnthologyType">

<xsd:key name="person-id">
<xsd:selector xpath="people/person" />
<xsd:field xpath="@id" />
</xsd:key>

<xsd:keyref name="poem-poet" refer="person-id">
<xsd:selector xpath="poems/poem" />
<xsd:field xpath="@poet" />
</xsd:keyref>


</xsd:element>

<xsd:complexType name="AnthologyType">
<xsd:sequence>
<xsd:element ref="people" />
<xsd:element ref="poems" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="people" type="PeopleType" />

<xsd:complexType name="PeopleType">
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="person" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="person" type="PersonType" />

<xsd:complexType name="PersonType">
<xsd:sequence>
<xsd:element ref="name" />
<xsd:element ref="sex" />
<xsd:element ref="birth" />
<xsd:element ref="death" />
</xsd:sequence>
<xsd:attribute name="id" type="xsd:NCName" use="required" />
</xsd:complexType>

<xsd:element name="name" type="xsd:string" />
<xsd:element name="sex" type="SexType" />
<xsd:element name="birth" type="xsd:gYear" />
<xsd:element name="death" type="xsd:gYear" />

<xsd:simpleType name="SexType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="male" />
<xsd:enumeration value="female" />
</xsd:restriction>
</xsd:simpleType>

<xsd:element name="poems" type="PoemsType" />

<xsd:complexType name="PoemsType">
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="poem" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="poem" type="PoemType" />

<xsd:complexType name="PoemType">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="poet" type="xsd:NCName" use="required" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>

</xsd:schema>


■key: id属性を宣言する

たけち: ここで見て欲しいのは

<xsd:key name="person-id">
<xsd:selector xpath="people/person" />
<xsd:field xpath="@id" />

</xsd:key>

<xsd:keyref name="poem-poet" refer="person-id">
<xsd:selector xpath="poems/poem" />
<xsd:field xpath="@poet" />

</xsd:keyref>

たけち: の部分なんだ。ここでid属性の値の一意性を保証したり、poet属性の値がid属性の値の参照であることを設定している部分なんだよ。

さらら: きゃ〜、全然わかんない (^ ^;)

たけち: いや、ゆっくり見ていけばわかるよ。まず

<xsd:key name="person-id">

 というのは、これからperson-idという名前の、一意性を保証するための設定をしますという意味になるんだね。

たけち

たけち: 次に、

<xsd:selector xpath="people/person" />

 に出てくるselector(セレクタ)というのは、一意な値、つまりIDを持つべき要素を設定する部分なんだ。ここではselector(セレクタ)people要素の子要素のperson要素になるよね。そして、このxsd:selector要素のxpath属性というのは文字通りXPathの意味なんだよ。XPathについては、以前XSLTの説明をした際に勉強したよね。

さらら: そういえば、そういうものがあったわね (^ ^;)

たけち: この場合、anthology要素の要素宣言の中でkeyの設定をしているんだけれど、anthology要素から見て、IDを持つべき要素であるセレクタ:person要素のXPathはpeople/personになるよね。だから、こんな書き方をしているんだ。

さらら: ふ〜ん。。。

たけち: そして、

<xsd:field xpath="@id" />

 なんだけれど、このフィールドというのは、実際にどういう要素や属性が一意な値、つまりIDになるか、ということを設定している部分なんだ。ここではperson要素のid属性が一意な値、つまりIDになるよね。これがフィールドなんだ。

さらら: うっ、うん。。。。。 (^ ^;)

たけち: ところでこのxpath属性の部分なんだけれど、さっきは
『anthology要素の要素宣言の中でkeyの設定をしているから、anthology要素から見て、IDを持つべき要素であるperson要素のXPathは「people/person」になる』
という説明をしたよね。同じ理屈でいくと、このXPathは「people/person/@id」になりそうだけど、そうじゃないんだ。この場合、今度はanthology要素を起点とするのではなくて、「セレクタとなっているperson要素から見た、id属性のXPath」を設定しないといけなくい。それで「@id」と書いているんだね。要するに「セレクタを起点としたフィールドのXPath」なんだね。まあこういう仕様の方が、自然だし短くなるよね。

さらら: う〜ん、ややこしいのねぇ (^ ^;)

たけち: ID型と比べると、ぐっとややこしくなった感じがするよね。でも、じっくり考えれば、至極あたりまえのことを設定しているだけだから、よく眺めて理解してね (^ ^)

さらら: うん。。。

たけち

たけち: じっ、じゃあ、この例でのkeyとkeyrefによる参照の関係を図にしておくね。 (^ ^;

xsd:keyとxsd:keyrefの関係 万葉歌の例で


■keyref: id属性の値を参照する

たけち: さて、次にそのid属性の値を参照するkeyrefの方を解説しようね。

<xsd:keyref name="poem-poet" refer="person-id">

たけち: これはperson-idという名前のkeyを、参照するための設定をします。その参照の名前をpoem-poetという名前にしますということを意味しているんだ。先ほど、「person-id」という名前のkeyを作ったわけだけれど、その名前を使って参照するわけだね。

さらら: あっ、どうしてkeyにわざわざ名前をつけるのかと思ったら、こういうところで参照するためなのね。

たけち: そうだね。ID型の場合、例え複数の要素の属性をIDに設定しても、そのIDはXMLデータ全体を対象として、それ自体が唯一無二のものだったんだ。だからそれに名前をつけなくても、IDREF型でそのまま参照できたんだね。
ところが後でまた説明するけど、keyの場合はいくつでもkeyを設定できるんだ。ということは、それぞれのkeyに名前をつけておかないと、参照する場合にどのkeyを参照しているのかがわからなくなるんだ。

さらら: なるほどね。

さらら

たけち: じゃ、次にいくね。

<xsd:selector xpath="poems/poem" />

たけち: というのは「参照したい値を持っているのはpoem要素ですよ」という意味だね。これがこのkeyrefのセレクタになるんだ。さっきと同じように、この場合のセレクタは、『anthology要素の要素宣言の中でkeyrefの設定をしているから、anthology要素から見て、IDの参照値を持つべき要素であるpoem要素のXPathは「poems/poem」になる』わけなんだ。

さらら: うっ、うん........

たけち: そして最後に、

<xsd:field xpath="@poet" />

たけち:  なんだけれど、これは参照値そのものを入れるpoet属性のXPathを設定している部分だね。ここではpoet属性がkeyrefのフィールドになるんだ。keyのセレクタとフィールドの関係と同じように、keyrefでも「セレクタとなっているpoem要素から見た、poet属性のXPath」を書かないといけなから、この場合フィールドのxpathの値は「@poet」になるわけなんだ。 以上のことをまとめると、つぎのようになるね。

keyとkeyref

たけち

さらら: だいたい、わかった気がするけれど。何か、ややこしいわね(^^;) ID型やIDREF型の方がはるかに簡単だわね。(^ ^;)

たけち: まあ、確かにID型やIDREF型の方が簡単ということはあるよね(^^;) keyやkeyrefの場合、本格的な仕組みを導入して、ID型やIDREF型の欠点を解消する分、これだけややこしくなっているんだね。でも、さっきも言ったように、じっくり見ていればわかるから、何回も見て覚えてね(^^)

さらら: ところで今回の例ではIDREFS型のところがないわね。IDREFS型に相当する参照はどう書けばいいの?

たけち: あっ、そうだったね。じゃ、それについては次回お話しようね。

さらら: は〜い。

次回はkey, keyref, unique: その3です。...... (^ ^)v


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