前回は例1に示すDTDを使って要素型宣言(ELEMENT宣言)の定義を説明しました。今回は属性リスト宣言(ATTLIST宣言)を見ていきます。

例1 DTD定義例

<!ELEMENT diary (day+)>
<!ELEMENT day (body)>
<!ELEMENT body (#PCDATA)>
<!ATTLIST day date CDATA #REQUIRED>
<!ATTLIST day title CDATA #REQUIRED>

◇属性リスト宣言(ATTLIST宣言)

 属性は,属性リスト宣言(ATTLIST宣言)で定義します。属性1つに対して属性リスト宣言(ATTLIST宣言)を1宣言ずつ定義していきます。定義順序には,意味はありません。

<!ATTLIST day date CDATA #REQUIRED>

 day要素にdate属性が指定されることを宣言しています。「CDATA」は属性値として任意の文字データが指定されることを定義しています。また,「#REQUIRED」の指定はこの属性が必須属性であることを示しています。指定を省略することができる属性の場合には,「#IMPLIED」と指定します。

<!ATTLIST day title CDATA #REQUIRED>

 上のdate属性と同様に,day要素にはtitle属性も指定されることを宣言しています。「#REQUIRED」の指定がありますので,この属性も指定が必須となります。

 属性リスト宣言(ATTLIST宣言)では下記の例2のように,属性の指定を省略したときのデフォルト値を指定することもできます。

例2 title属性のデフォルト値を”タイトルなし”と定義する

<!ATTLIST day title CDATA "タイトルなし">

 この定義により,title属性の指定を省略すると”タイトルなし”という属性値がtitleの値となります。

確認問題1
図1に示す構造を正しく定義しているDTDを選択してください。

図1●確認問題1の文書構造
(a)
<!ELEMENT ProductList (Product+)>
<!ELEMENT Product (#PCDATA)>
<!ATTLIST Product ID CDATA #REQUIRED>
<!ATTLIST Product name CDATA #IMPLIED>
<!ATTLIST Product price CDATA #IMPLIED>
(b)
<!ELEMENT ProductList (Product*)>
<!ELEMENT Product (#PCDATA)>
<!ATTLIST Product ID CDATA #REQUIRED>
<!ATTLIST Product name CDATA #IMPLIED>
<!ATTLIST Product price CDATA "open">
(c)
<!ELEMENT ProductList (Product+)>
<!ELEMENT Product (#PCDATA)>
<!ATTLIST Product ID CDATA #REQUIRED>
<!ATTLIST Product price CDATA "open">
<!ATTLIST Product name CDATA #IMPLIED>
(d)
<!ELEMENT ProductList (Product*)>
<!ELEMENT Product (ID,neme,price)>
<!ATTLIST Product ID CDATA #REQUIRED>
<!ATTLIST Product name CDATA #IMPLIED>
<!ATTLIST Product price CDATA "open">

 正解は(c)です。(a)はprice属性のデフォルト値が指定されていません。(b)はProduct要素の出現回数が0回以上となっています。(c)はATTLISTの指定順が図の順番ではありませんが,ATTLISTも定義順序に意味はありませんので,どの属性から定義してもかまいません。(d)はID,name,priceがProduct要素の子要素として定義されています。

◇文書型宣言(DOCTYPE宣言)

 XML文書がどのDTDと対応しているのかを,文書型宣言(DOCTYPE宣言)で指定することができます。

 DTDが定義されている"hatena.dtd"というファイルが,XML文書と同一フォルダー内に格納されている際に,下記のようにDTD定義ファイル名を文書型宣言(DOCTYPE宣言)で指定できます。このように,別ファイルで定義されたDTDを外部サブセットDTDと呼びます。

例3 外部サブセットDTDの例

<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE diary SYSTEM "hatena.dtd">
<diary>
<day date="2006-08-30" title="ようやくXML Schemaの勉強開始" >
<body>今日XML Schemaの勉強を開始しました。結構難しい・・・</body>
</day>
<day date="2006-08-31" title="はやくもXML Schema完全制覇!" >
<body>なんとXML Schemaを自力で作成できるようになりました。</body>
</day>
</diary>

 DTDはXML文書内に直接記述することもできます。これを内部サブセットDTDと呼びます。

例4 内部サブセットDTDの例

<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE diary [
<!ELEMENT diary (day+)>
<!ELEMENT day (body)>
<!ELEMENT body (#PCDATA)>
<!ATTLIST day date CDATA #REQUIRED>
<!ATTLIST day title CDATA #REQUIRED>
]>
<diary>
<day date="2006-08-30" title="ようやくXML Schemaの勉強開始" >
<body>今日XML Schemaの勉強を開始しました。結構難しい・・・</body>
</day>
<day date="2006-08-31" title="はやくもXML Schema完全制覇!" >
<body>なんとXML Schemaを自力で作成できるようになりました。</body>
</day>
</diary>

 <!DOCTYPEの後には,ルート要素となる要素名を記述します(図2)。

図2●文書型宣言でのルート要素の指定

確認問題2
次の中から妥当なXML文書を選択してください(複数選択)。

person.dtdファイルの内容
<!ELEMENT person (name,age?)+>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>

(a)
<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE person SYSTEM "person.dtd">
<person/>
(b)
<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE person SYSTEM "person.dtd">
<name/>
(c)
<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE person SYSTEM "person.dtd">
<person><name>Taro</name></person>
(d)
<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE person SYSTEM "person.dtd">
<person><name>Taro</name><name>Yuko</name><age>24</age></person>

 正解は(c)と(d)です。第2回で説明したように,整形式でかつ指定されたDTDの定義内容とも一致するXML文書を「妥当なXML文書」と言います。(a)は必ず1回出現するべきname要素が指定されていませんのでDTDの定義内容と一致しません。(b)はルート要素がperson要素となっていませんので,こちらもDTDの定義内容と一致しません。

野中 康弘
インフォテリア 教育部 エンジニア。十数年間システム開発に携わり,そのうちの半分をデータベース管理者として奮闘する。現在は,インフォテリア認定教育センターのサポートや,XML技術者認定制度の「XMLマスター」に対応したコーステキストの開発などを担当している。