key, keyref, unique: その3

2002年12月29日(日)更新


■複数のID値を参照したい

たけち: IDREFS型に相当する参照ってことなんだけど、実は直接的にはIDREFS型に相当する書き方は存在しないんだよ。

さらら: え、ないの? それじゃあ困るじゃない。複数のID値を参照したい場合、どうすればいいの?

たけち: いや、別のやり方で複数のID値を参照できるんだよ。例えば、

<anthologists people="p01 p02" />

 だった部分を、

<anthologists>
<anthologist person="p01" />
<anthologist person="p02" />
</anthologists>

 というふうに書き換えるんだ。実際こういう書き方の方が、XSLTやDOMなどで処理しやすくて、自然だよね。

さらら: ふ〜ん。ひとつひとつのIDを参照するのね。

たけち: 全部書いて見ると次のようなXMLデータになるよね。

XMLデータ: 歌集(Anthology) ....... 複数のID値を参照
<?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>

<anthologists>
<anthologist person="p01" />
<anthologist person="p02" />
</anthologists>


</anthology>

さらら: えぇ。

たけち: このXMLデータに相当するXML Schemaは次のように書けばいいよね。

XML Schema: 歌集(Anthology) ....... 複数のID値を参照

<?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:keyref name="anthologist-person" refer="person-id">
<xsd:selector xpath="anthologists/anthologist" />
<xsd:field xpath="@person" />
</xsd:keyref>


</xsd:element>

<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: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:element name="anthologists" type="AnthologistsType" />

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

<xsd:element name="anthologist" type="AnthologistType" />

<xsd:complexType name="AnthologistType">
<xsd:attribute name="person" type="xsd:NCName" use="required" />
</xsd:complexType>


</xsd:schema>


■要素の内容でIDを参照する

さらら: なるほど。こういう風にできるのね。

たけち: じゃ、今度は、idの部分やpoetの部分を属性ではなくて要素に変更してみようね。ID型, IDREF型, IDREFS型で問題のひとつだと取り上げた、ID型、IDREF型では解決できなかった例の1番目だよ。

さらら: えっ? あっ。

たけち: 次のような問題だったよね。

※ID型、IDREF型、IDREFS型によるIDの管理方法の欠点

1.IDとなるもの、そしてIDを参照するものは属性でなければならない。要素の内容をIDにしたり、要素の内容でIDを参照するような場合の検証は不可能である。

2.〜5.は省略

さらら: あっ、そうだったわね。(^ ^;

たけち: つぎに、そのような例を載せるね。

XMLデータ: 歌集(Anthology) ....... IDとその参照が要素の内容
<?xml version="1.0" encoding="Shift_JIS" ?>
<anthology>

<people>
<person>
  <id>p01</id>
  <name>持統天皇</name>
  <sex>female</sex>
  <birth>0645</birth>
  <death>0702</death>
</person>
<person>
  <id>p02</id>
  <name>高市皇子</name>
  <sex>male</sex>
  <birth>0654</birth>
  <death>0696</death>
</person>
<person>
  <id>p03</id>
  <name>大伴家持</name>
  <sex>male</sex>
  <birth>0718</birth>
  <death>0785</death>
</person>
<person>
  <id>p04</id>
  <name>坂上郎女</name>
  <sex>female</sex>
  <birth>0700</birth>
  <death>0750</death>
</person>
<person>
  <id>p05</id>
  <name>柿本人麻呂</name>
  <sex>male</sex>
  <birth>0645</birth>
  <death>0701</death>
</person>
</people>

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

</anthology>

たけち: これに対応するXML Schemaは次のようになるね。

XML Schema: 歌集(Anthology) ....... IDとその参照が要素の内容
<?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="id" />
<xsd:element ref="name" />
<xsd:element ref="sex" />
<xsd:element ref="birth" />
<xsd:element ref="death" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="id" type="xsd:NCName" />
<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:sequence>
<xsd:element ref="poet" />
<xsd:element ref="yomi" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="poet" type="xsd:NCName" />
<xsd:element name="yomi" type="xsd:string" />

</xsd:schema>

さらら: あぁ、これならわかりそう。

たけち: id要素はpersonの子要素に、そしてpoet要素はpoem要素の子要素になるから、

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

 というふうにフィールドのXPathの値が変わるんだね。

さらら: これなら私でもわかるわぁ〜 (^ ^*)

たけち

■2つのkeyを設定する

たけち: それから今度はkeyが2つある例を出してみるね。前回問題になったID型、IDREF型では解決できなかった2番目の例だよ。

さらら: はっ、はい。(^ ^;

たけち: 次のような問題だったよね。

※ID型、IDREF型、IDREFS型によるIDの管理方法の欠点

1.は省略

2.複数の要素型の中の属性をIDとして設定した場合、それぞれを別々に独立した一意性を持った対象としての検証は不可能であり、XMLデータ全体が一意性の検証対象となる。

3.〜5.は省略

さらら: あっ、こんなのあったわね。

たけち: じゃ、2つのkeyを設定したXMLデータの例をみてみようね。

XMLデータ: 歌集(Anthology) ....... 2つのkeyを設定
<?xml version="1.0" encoding="Shift_JIS" ?>
<anthology>
<people>

<person id="p0001">
<name>雄略天皇</name>
<sex>male</sex>
<birth>0418</birth>
<death>0479</death>
</person>

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

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

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

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

</people>

<poems>
<poem pno="p0001" poet="p0001">籠もよ、み籠持ち、掘串もよ、み掘串持ち、この岳に菜摘ます兒、家聞かな、告らさね、そらみつ大和の国は、おしなべてわれこそ居れ、しきなべてわれこそ座せ、われにこそは告らめ、家をも名をも </poem>
<poem pno="p0146" poet="p0005">後見むと君が結べる磐代の小松がうれをまたも見むかも</poem>
<poem pno="p0408" poet="p0003">なでしこがその花にもが朝な朝な手に取り持ちて恋ひぬ日なけむ</poem>
</poems>

</anthology>

たけち: これに対応するXML Schemaは次のようになるね。

XML Schema: 歌集(Anthology) ....... 2つのkeyを設定
<?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:key name="poem-pno">
<xsd:selector xpath="poems/poem" />
<xsd:field xpath="@pno" />
</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="pno" type="xsd:NCName" use="required" />
<xsd:attribute name="poet" type="xsd:NCName" use="required" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>

</xsd:schema>

たけち: ここで見て欲しいのは次のところだよ。

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


<xsd:key name="poem-pno">
<xsd:selector xpath="poems/poem" />
<xsd:field xpath="@pno" />
</xsd:key>

たけち:  というふうに、2つのkeyが設定されているけれど、名前が違っているから混乱しないよね。

さらら: これもわかる気がするわ。こういうのをいくつ作ってもいいわけね。

たけち: うん、そうだね。


■複数のフィールドを設定

たけち: さて、つぎは、「※ID型、IDREF型、IDREFS型によるIDの管理方法の欠点-(3)」として載せた例を見てみようね。歌集(anthology)と歌番号(pno)との組み合わせで一意性を確保する例だよ。

XMLデータ: 和歌 ....... 歌集(anthology)と歌番号(pno)の組合わせ
<?xml version="1.0" encoding="Shift_JIS" ?>
<poems>
<poem pno="0028" anthology="万葉集">春過ぎて夏来たるらし白妙の衣干したり天の香具山</poem>
<poem pno="0146" anthology="万葉集">後見むと君が結べる磐代の小松がうれをまたも見むかも</poem>
<poem pno="0408" anthology="万葉集">なでしこがその花にもが朝な朝な手に取り持ちて恋ひぬ日なけむ</poem>
<poem pno="0028" anthology="古今和歌集">ももちどりさへづる春は物ごとにあらたまれども我ぞふり行く</poem>
<poem pno="0146" anthology="古今和歌集">郭公なくこゑきけばわかれにしふるさとさへぞこひしかりける</poem>
<poem pno="0408" anthology="古今和歌集">都いでて今日みかの原いづみ河かは風さむし衣かせ山</poem>
</poems>

たけち

たけち: pno属性だけでは一意性が保たれない。だけど、anthology属性と併せると一意性が保たれる、という例だね。

さらら: え〜っ、これのXML Schemaはちょっと想像がつかないわ。

たけち: あっ、実は答は簡単なんだけれどね(^ ^;) 次のXML Schemaをみて。

XML Schema: 和歌 ....... 歌集(anthology)と歌番号(pno)の組合わせ
<?xml version="1.0" encoding="Shift_JIS" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

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

<xsd:key name="poem-pno-anthology">
<xsd:selector xpath="poem" />
<xsd:field xpath="@pno" />
<xsd:field xpath="@anthology" />
</xsd:key>

</xsd:element>

<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="pno" type="xsd:positiveInteger" use="required" />
<xsd:attribute name="anthology" type="xsd:NCName" use="required" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>

</xsd:schema>

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

<xsd:key name="poem-pno-anthology">
<xsd:selector xpath="poem" />
<xsd:field xpath="@pno" />
<xsd:field xpath="@anthology" />
</xsd:key>

 だった部分を、

<anthologists>
<anthologist person="p01" />
<anthologist person="p02" />
</anthologists>

 の部分で、一つのセレクタに対してフィールドが2つあるんだよね。そしてこの2つのフィールドの組み合わせで一意性が保証されるようになるんだ。

さらら: あ、フィールドをいくつも設定して良かったのね(^^;)

たけち: そうなんだ。こうすると複数のフィールドの組み合わせが、IDのようになるということも知っておいてね。

さらら: はい。

さらら

■IDが通用する範囲を限定

たけち: さて、つぎは、「※ID型、IDREF型、IDREFS型によるIDの管理方法の欠点-(4)」として載せた例を見てみようね。IDが通用する範囲を限定する例だよ。

XMLデータ: 和歌 ....... pnoの有効範囲
<?xml version="1.0" encoding="Shift_JIS" ?>
<anthologies>
<anthology name="万葉集">
<poem pno="0028">
春過ぎて夏来たるらし白妙の衣干したり天の香具山</poem>
<poem pno="0146">
後見むと君が結べる磐代の小松がうれをまたも見むかも</poem>
<poem pno="0408">
なでしこがその花にもが朝な朝な手に取り持ちて恋ひぬ日なけむ</poem>
</anthology>
<anthology name="古今和歌集">
<poem pno="0028">
ももちどりさへづる春は物ごとにあらたまれども我ぞふり行く</poem>
<poem pno="0146">
郭公なくこゑきけばわかれにしふるさとさへぞこひしかりける</poem>
<poem pno="0408">
都いでて今日みかの原いづみ河かは風さむし衣かせ山</poem>
</anthology>
</anthologies>

たけち: XML Schemaは次のように書くんだよ。

XML Schema: 和歌 ....... anthologyの中で使われるkey
<?xml version="1.0" encoding="Shift_JIS" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<xsd:element name="anthologies" type="AnthologiesType" />

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

<xsd:element name="anthology" type="AnthologyType">
<xsd:key name="poem-pno">
<xsd:selector xpath="poem" />
<xsd:field xpath="@pno" />
</xsd:key>

</xsd:element>

<xsd:complexType name="AnthologyType">
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="poem" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>

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

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

</xsd:schema>

さらら: あ、anthology要素の中でkeyを設定しているのね。

たけち: こういう書き方をすると、このkeyの有効範囲は一つのanthology要素の中だけなんだね。だから複数のanthology要素が存在しても、その内部での一意性が保たれていることを検証できるんだ。これでID型、IDREF型を使ったのではできないようなことが、keyやkeyrefを使うとできることがわかったよね。

さらら: えぇ、分かった気がするわ。(^ ^*

たけち: あ、それから一つ注意だけど、xsd:key要素やxsd:keyref要素は、要素宣言の子要素として出現するんだけれど、要素宣言が匿名の型定義を使う場合はちょっと注意が必要だよ。

たけち

XML Schema: 和歌 ....... anthology(匿名の型定義)の中で使われるkey
<?xml version="1.0" encoding="Shift_JIS" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

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

<xsd:element name="anthology">
<xsd:complexType>
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="poem" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
<xsd:key name="poem-pno">
<xsd:selector xpath="poem" />
<xsd:field xpath="@pno" />
</xsd:key>

</xsd:element>

<xsd:element name="poem">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="pno" type="xsd:positiveInteger" use="required" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>

</xsd:schema>

たけち

たけち: この例でわかるように、xsd:key要素やxsd:keyref要素の親要素となる要素宣言が、匿名の型定義を含む場合は、その匿名の型定義となるxsd:simpleType要素またはxsd:complexType要素は、xsd:key要素やxsd:keyref要素の前に存在しないといけないんだ。
逆に言うと、xsd:key要素やxsd:keyref要素が出現できるのは、匿名の型定義となるxsd:simpleType要素またはxsd:complexType要素の後じゃないといけないんだ。

さらら: へ〜、そんな決まりがあるのね。

たけち: これでkeyについての説明を終わるね。

さらら: は〜い。あ〜、今回は疲れちゃった(^ ^;)

たけち: でも、この際だからkeyに似た機能であるuniqueについても一緒に説明しておくね。

さらら: えっ、まだあるの(^ ^;)


■unique

たけち: あ、そんなに長くは話さないから(^^;) 次のXMLデータをみてごらん。

XMLデータ: 歌人 ....... idのあるpersonとidの無いperson
<?xml version="1.0" encoding="UTF-8" ?>
<people>

<person>
<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>
<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>
<name>柿本人麻呂</name>
<sex>male</sex>
<birth>0645</birth>
<death>0701</death>
</person>

</people>

さらら: えっ、これってどういうこと?

たけち: この場合、一部のデータにはid値が存在しないよね。でも、id値が設定されているところでは一意性は保たれている、という場合だよ。

さらら: あっ、そうなんだぁ。

たけち: こういうXMLデータではこれまでの例のようなkeyを使った方法だと、これはエラーになってしまうんだ。でも、id値が設定されているところでは、一意性は保たれているのだから、せめてその部分だけでもチェックしたい、というケースなんだ。

さらら: でも、こういう場合にはkeyはエラーを返すだけなんでしょ。

たけち: そうだね、でもID型を使うと、次のようなDTDやXML Schemaで、これもチェックできるんだよ。

たけち

DTD
<!ELEMENT people (person*)>
<!ELEMENT person (name, sex, birth, death)>
<!ATTLIST person id ID #IMPLIED>
<!ELEMENT name (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ELEMENT birth (#PCDATA)>
<!ELEMENT death (#PCDATA)>

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

<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="optional" />
</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:schema>

たけち: このDTDやXML Schemaが今まで見たようなDTDやXML Schemaとちょっと違うのは、
<!ATTLIST person id ID #IMPLIED>

<xsd:attribute name="id" type="xsd:ID" use="optional" />
 というふうにid属性の出現が#IMPLIED、つまりoptionalになっていることなんだ。これだとID型を使った書き方でも大丈夫なんだよ。

さらら: そうなの。。。あら、ID型だとできるのに、keyでできないなんて困るわ。

たけち: そこでこういう場合はkeyではなくて、keyとよく似たuniqueという仕組みを使うんだ。

さらら: unique?

さらら

XML Schema: uniqueを使用
<?xml version="1.0" encoding="Shift_JIS" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

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

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


</xsd:element>

<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" />
</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" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>

</xsd:schema>

たけち

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

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

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


</xsd:element>

 の部分なんだ。見てもらったらわかるように、今まで「key」と書いてあった部分が、そのまま「unique」に置き換わっただけだよね。つまりこのuniqueの文法はkeyと変わらないんだ。
ただ、このuniqueがkeyとちょっとだけ使うのは、さっきのXMLデータのように、フィールドにあたる部分が存在しないデータがあっても、存在するものの間で一意性が保たれていれば、エラーにはせずに正しいと検証してくれる点なんだ。

さらら: そうなんだ。。。

たけち: IDの管理の仕方についてはこれでおしまい。次回は「再帰的定義」の話をするね。

さらら: は〜い!!

次回は再帰的定義です...... (^ ^)v


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