前回までの「はてなダイアリー形式」から「JUGEM形式」への変換の際には,はてなダイアリー形式のXML文書が図1の構造であると推測してXSLTスタイルシートを作成しました。

図1●はてなダイアリー形式XML文書の構造

 しかし本当は,はてなダイアリーが図1の構造であるのかどうかは,筆者がエクスポートしたはてなダイアリー形式のXML文書を見ただけでは判断できません。例えば,日記のタイトルが記述されていなかった場合,(1)title属性自体が全く指定されていないのか,あるいは(2)title属性は指定されているが値が””となっているのかは,分からないのです。もしtitle属性そのものが省略される可能性があるのであれば,変換時にもXSLTスタイルシートの中で考慮する必要が出てきます。

 実は,XML文書が「どのような構造であるか」は,スキーマ定義言語と呼ぶ言語で,あらかじめ定義しておくことができます。代表的なスキーマ定義言語には,DTD(Document Type Definition)XML Schemaなどがあります。

 今回はDTDを使って,はてなダイアリー形式のXML文書の構造を定義してみましょう(はてなはスキーマ定義を公開していませんので,今回はあくまでも筆者が推測した構造定義となります)。

 図1の構造をDTDで定義すると次のようになります。

例1 図1の構造のDTDの定義例

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

 DTDでは要素の定義を要素型宣言(ELEMENT宣言)で,属性の定義を属性リスト宣言(ATTLIST宣言)で行います。

◇要素型宣言(ELEMENT宣言)

 要素型宣言は要素1つに対して,必ず1つ定義します。指定順序には制約がありませんので,どの要素から定義しても構いません。

<!ELEMENT day (body)>

 これは,day要素に対する要素型宣言です。カッコ内はday要素の内容を定義しています。この定義内容から,day要素の内容は子要素のbody要素であることが分かります。

<!ELEMENT body (#PCDATA)>

 これは,body要素に対する要素型宣言です。body要素には子要素を含まず,要素の内容は文字データであることが定義されています。「#PCDATA」は任意の文字列を表す指定です。

<!ELEMENT diary (day+)>

 この宣言は,diary要素に対する要素型宣言です。diary要素の内容はdayという子要素であることが分かります。また「+」の指定はday要素が「1回以上の任意の回数出現する」ことを表しています。出現回数の指定には,このほかに表1に示す文字が利用できます。

表1●要素の出現回数の指定
指定する文字意味
+1回以上の任意の回数出現する
*0回以上の任意の回数出現する
?0回または1回出現する
指定なし必ず1回出現する

◇複数の子要素の指定

 仮にday要素がbody要素以外にも複数の子要素を持つ場合には,子要素を「,」で区切って次のように指定します。

例2 day要素がbody要素,comment要素,URL要素の3つの子要素を持つ場合

<!ELEMENT day (body,comment,URL)>

 また,複数要素のいずれか1要素だけが子要素となる場合には,「|」で区切って次のように定義します。

例3 day要素がbody要素,comment要素,URL要素のいずれかの子要素を持つ場合

<!ELEMENT day (body|comment|URL)>

 要素の内容として,子要素と文字データの両方を含めることもできます。これを混合内容と呼びます。次の例は混合内容の要素型宣言定義例です。

例4 body要素に日記本文(文字データ)とcolor子要素を含めることができる場合

<!ELEMENT body (#PCDATA|color)>

 この場合,body要素は下記のように文字データと要素を混在して記述することができます。

<body>今日は<color>小春日和</color>の1日でした。</body>

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

図2●確認問題1の文書構造
(a)
<!ELEMENT ProductList(Product)>
<!ELEMENT Product (ID,name, price)>
<!ELEMENT ID (#PCDATA)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT price (#PCDATA)>
(b)
<!ELEMENT ProductList(Product+)>
<!ELEMENT Product (ID,name, price?)>
<!ELEMENT ID (#PCDATA)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT price (#PCDATA)>
(c)
<!ELEMENT ProductList (Product+)>
<!ELEMENT Product (ID,name, price)?>
<!ELEMENT ID (#PCDATA)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT price (#PCDATA)>
(d)
<!ELEMENT ProductList (Product+)>
<!ELEMENT Product (ID|name|price)>
<!ELEMENT ID (#PCDATA)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT price (#PCDATA)>

 正解は(b)です。(a)は,Product要素,price要素が必ず1回だけ出現する指定となっています。(c)は,IDとnameとpriceがセットで0回または1回出現することになります。 従って,price要素の記述を省略する際にはID要素,name要素も省略しなければならないことになります。(d)はID要素,name要素,price要素のうちいずれか1要素のみが出現する指定となっています。属性リスト宣言は,次回に説明します。



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