XMLマスターへの道
〜「XMLマスター:ベーシック」試験対策〜

第5回 valid XMLとDTDの関係

武田栄子
ウチダ人材開発センタ
2003/3/11

 今回は、XML文書のスキーマを定義する手段の1つであるDTD(Document Type Definition)について解説します。また、前回「第4回 すべてのXML文書は整形式である」で予習問題として出題した下記の問題の解答も紹介します。

今回の問題
(Q1) DTDについて正しく説明しているものをすべて選択してください。

(a) DTDはXML 1.0仕様の中で規定されている
(b) すべてのXMLパーサはDTDによる妥当性を検証しなければならない
(c) 外部DTDと文書本体の文字エンコーディングは異なってもよい
(d) DTDの記述は大文字小文字を識別する
(e) 外部DTDと内部DTDに同じ名前の要素を宣言することができる
(f) 外部DTDと内部DTDに同じ名前の属性を宣言することができる
(g) A社とB社の間で合意した外部DTDを使うときのキーワードはPRIVATEである

(Q2) 以下のDTDに妥当なXML文書をすべて選択してください。

「DTD」
<!ELEMENT  root  (A | B+)>
<!ELEMENT  A  (#PCDATA)>
<!ELEMENT  B  (#PCDATA)>
<!ATTLIST  A  a (12 | 34 | 56)  "12">
<!ATTLIST  B  b  ID  #REQUIRED>

(a) <root/>
(b) <root>
         <A/><B/>
       </root>
(c) <root>
         <A/>
        </root>    
(d) <root>
         <A  a="12"/>
       </root>
(e) <root>
         <A   a="12"  a="34"/>
       </root> 
(f) <root>
         <A  a="78"/>
       </root>
(g) <root>
         <B/>
        </root>
(h) <root>
         <B  b="12"/>
       </root>
(i) <root>
         <B   b="x12"/>
      </root>
(j) <root>
         <B   b="x12"/>
         <B   b="x12"/>
      </root>
(k)
<root>
         <B  b="x12"/>
         <B  b="y12"/>
      </root>

 今回は、この問題に解答するうえで必要な知識となる5つの内容

  • スキーマ定義言語とDTD
  • valid XML(妥当なXML)
  • DTDの記述場所
  • 要素型宣言
  • 属性リスト宣言

について前回でも例として扱った社員リストを基に解説することで、XMLマスター:ベーシック試験に対応できるようにします。DTDも出題割合の高いカテゴリなので、サンプルファイルなどで動作を試しながら学ぶとよいでしょう。

 下記に、説明で使うXML文書のサンプルを示します。

<?xml version="1.0" encoding="Shift_JIS"?>
<社員データ>
  <社員 社員番号="5">
    <名前>山田 太郎</名前>
    <部署>営業</部署>
  </社員>
  <社員 社員番号="11">
    <名前>鈴木 花子</名前>
    <部署>教育</部署>
  </社員>
</社員データ>
リスト1 社員データのサンプル(test5_01.xml

スキーマ定義言語とDTD

 リスト1の文書本体を見ると、いくつかの規則に従っていることが分かります。この規則を文章で説明すると、次のようになります。

社員データには、1人以上の社員情報がある
社員情報には、付加情報として社員番号がある
この社員情報には、社員名と所属している部署名が含まれる
社員名、部署名の順で出現する
社員名、部署名は文字データで記述されている

 さらに、リスト1を図式化したものが図1です。

図1 リスト1を図式化すると上記のような構造となる

 では、test5_01.xmlを書き換えて、わざと「部署情報がない」「上司の名前も社員情報に含まれている」など、前述の規則に従っていないXML文書へ変更した場合どのようになるでしょうか。

<?xml version="1.0" encoding="Shift_JIS"?>
<社員データ>
  <社員 社員番号="5">
    <名前>山田 太郎</名前>
    <!--部署情報がない-->
  </社員>
  <社員 社員番号="11">
    <名前>鈴木 花子</名前>
     <部署>教育</部署>
    <!--上司の名前も社員情報に含まれている-->
    <上司>加藤 健二</上司>
  </社員>
</社員データ>
リスト2 リスト1の規則に従っていないXML文書へ変更(test5_02.xml

画面1 test5_02.xmlをIEで開いたが、特にエラーとならない

 Internet Explorer(以後IE)で開いてみても特にエラーとならないことが分かります。というのも、前回解説したように、整形式規約を満たしていればXML文書としては成立するため、エラーを出す理由がないからです。

 しかし、XMLに限らず、データをアプリケーションなどで読み込ませて活用したいときには、記述されているデータに規則性がある方がずっと扱いやすくなります。例えばXMLで記述された受発注書を企業間でやりとりするような場合、それぞれが情報を扱いやすいように、各項目の名前や順番、どんな項目が必要か、といったデータの記述の仕方にある程度の規則を持たせる必要があるでしょう。

 上記のように、要素や属性の名前、出現順などのことをXML文書の構造(スキーマ)と呼びます。そして、 そのスキーマを定義する言語として、XML 1.0の仕様では「DTD」が規定されています。

 スキーマ定義言語にはそのほかにXML SchemaXDR、RELAX NGなどがありますが、XMLマスター:ベーシックで試験範囲となっているのはDTDとXML Schemaだけです。

valid XML(妥当なXML)

 前回、「XML文書を制約という観点からみると、well-formed XML(整形式なXML)以外にvalid XML (妥当なXML)があります」と説明しました。well-formed XMLは、スキーマ定義に従って記述されていてもいなくても構いません。一方で、スキーマ定義であるDTDが記述されたうえで、文書本体がそのDTDに従って記述されているXML文書を「valid XML」といいます。

 well-formed XMLにもDTDを記述して構いませんが、DTDが記述されているだけではvalid XMLになりません(XML文書の本体がDTDに従っていなくてもwell-formed XMLにはなります。valid XMLでは本体がDTDに従っていなくてはなりません)。

 では、DTDの記述方法を紹介しましょう。DTDは、XML宣言と文書本体の間に記述します。DTDにはコメントを記述することも可能なので、注釈を入れる場合に便利です。リスト1の規則を基に、test5_01.xmlにDTDを追加したものがリスト3のtest5_03.xmlです。

<?xml version="1.0" encoding="Shift_JIS"?> XML宣言 (任意)
<!DOCTYPE 社員データ [
  <!ELEMENT 社員データ (社員+)>
  <!ELEMENT 社員 (名前, 部署)>
  <!ELEMENT 名前 (#PCDATA)>
  <!ELEMENT 部署 (#PCDATA)>
  <!ATTLIST 社員 社員番号 CDATA #REQUIRED>
]>
DTD
(well-formed XMLの場合は任意、valid XMLの場合は必須)
<社員データ>
  <社員 社員番号="5">
    <名前>山田 太郎</名前>
    <部署>営業</部署>
  </社員>
  <社員 社員番号="11">
   <名前>鈴木 花子</名前>
   <部署>教育</部署>
  </社員>
</社員データ>
文書本体 (必須)
リスト3 test5_01.xmlにDTDを追加。このXML文書はDTDのスキーマ定義を満たしているvalid XMLである(test5_03.xml

 では、わざと規則に従っていないXML文書として作ったtest5_02.xmlにも、このDTDを追加してみます。それをIEで開くと、どのようになるでしょうか。

画面2 test5_02.xmlにリスト4と同じDTDを追加しても、IEで開いたときにエラーとならない (test5_04.xml)

 エラーになりません。なぜエラーにならないのでしょうか。実は、XMLパーサはwell-formed XMLかどうかは解析しますが、文書本体がDTDに従っているかという妥当性の検証は任意となっています。

 なお、今回XMLパーサとして使っているMSXMLは、本来DTDによる妥当性を検証する機能を持つXMLパーサですが、IEに組み込んで動作させる場合はDTDによる妥当性を検証しません。IE上でDTDによる妥当性を検証したい場合、Internet Explorer Tools for Validating XML and Viewing XSLT Output (以後、IE for Validating XML) などの検証用ツールを使うと便利です。

 IE for Validating XMLで妥当性を検証する場合、ブラウザウィンドウ内で右クリックし、[validate XML] を実行します。DTDのスキーマ定義に妥当なtest5_03.xmlを検証すると、画面3のように検証が成功した旨のメッセージが返ってきます。

画面3 DTDのスキーマ定義に、妥当なtest5_03.xmlをIE for Validating XMLで検証したとき

 それに対して、DTDのスキーマ定義に妥当でないtest5_04.xmlを検証すると、画面4のように検証がエラーになった旨のメッセージが返ってきます。

画面4 DTDのスキーマ定義に妥当でないtest5_04.xmlをIE for Validating XMLで検証したとき

DTDの記述場所

 DTDを使うことで、XML文書のデータに規則性を持たせることができますが、同じスキーマ定義を複数のXML文書へ何度も記述するのは非効率ですし、スキーマ定義に変更があった場合すべてのファイルへ変更を反映しなければいけません。では、どのようにすればいいでしょうか。 

 DTDは、対象とするXML文書内もしくは、対象とするXML文書とは異なるファイルのいずれにも記述できます。XML文書内に記述したDTDを「内部サブセット」と呼び、対象となるXML文書とは異なるファイルに記述されたDTDを「外部サブセット」と呼びます。いままで紹介してきたtest5_03.xmltest5_04.xmlでは、内部サブセットでDTDが定義されていました。

 外部サブセットのメリットとしては、1つのスキーマ定義を複数のXML文書へ適用させることができる点です。企業間取引、標準化団体などで取り決めた記述ルールに従った多数のXML文書を記述する場合に有用です。

図2 内部サブセットと外部サブセット

 内部サブセットと外部サブセットでは、構文が多少異なるので以下にまとめました。

<!DOCTYPE  ルート要素名  [この中にDTDを記述]>
内部サブセットの構文

<!DOCTYPE  ルート要素名  SYSTEM  "外部サブセットが記述されているファイルのURI">
外部サブセットの構文 : SYSTEMキーワードを使う場合、双方の合意を意味する

<!DOCTYPE  ルート要素名  PUBLIC "公開識別子" "外部サブセットのURI">
外部サブセットの構文 (標準化団体などのDTDを利用する場合など)

 下記のリスト4が、test5_03.xmlを外部サブセットへ変更したときのサンプルです。

<?xml version="1.0"
       encoding="Shift_JIS"?>
<?xml version="1.0"
        encoding="Shift_JIS"?>
<!DOCTYPE 社員データ
     SYSTEM "test5_05.dtd">
<!ELEMENT 社員データ (社員+)>
<!ELEMENT 社員 (名前, 部署)>
<!ELEMENT 名前 (#PCDATA)>
<!ELEMENT 部署 (#PCDATA)>
<!ATTLIST 社員 社員番号
            CDATA #REQUIRED>
<社員データ>
  <社員 社員番号="5">
    <名前>山田 太郎</名前>
    <部署>営業</部署>
  </社員>
  <社員 社員番号="11">
   <名前>鈴木 花子</名前>
   <部署>教育</部署>
  </社員>
</社員データ>
リスト4 test5_03.xmlを外部サブセットへ変更(左がtest5_05.xml、右がtest5_05.dtd

 なお、test5_05.dtdのようにXML文書以外でXML宣言を行っているものを「テキスト宣言」と言います。テキスト宣言では、DTDファイルの文字エンコーディングをencodingで指定します。XML文書と外部サブセットで記述したDTDファイルとの文字エンコーディングが異なっていても構いません。文字エンコーディングが異なるファイル(test5_06.xmltest5_06.dtd)を用意しているので、XMLパーサで確認してみてください。

要素型宣言

 ここでは、DTDの内容について解説しましょう。DTDの中で、要素を定義するのが「要素型宣言」です。文書本体の中で出現する可能性のある要素を宣言します。同じ要素名の要素型宣言を重複して定義することはできません。これは、内部サブセット、外部サブセットそれぞれに記述した場合も同様です。

<!ELEMENT  要素名  内容モデル>
要素型宣言の構文

 内容モデルには、要素の内容が文字データか子要素か、子要素の場合は出現順序や出現回数を指定します。内容モデルを以下にまとめました。こちらもXMLマスター:ベーシックでポイントになる個所なので、前述のIE for Validating XMLを使って実機で学習されることをお勧めします。

種類 DTDの記述例 説明
(#PCDATA) <!ELEMENT a (#PCDATA)> 内容が文字データである
記号なし <!ELEMENT a (b)> 必ず1回 子要素が出現する
, <!ELEMENT a (b, c)> 左から記述された順に子要素が出現する
| <!ELEMENT a (b | c)> | で区切られた子要素のうち、いずれか1つが出現する
? <!ELEMENT a (b?)> 子要素は0回または1回出現する
+ <!ELEMENT a (b+)> 子要素は1回以上出現する
* <!ELEMENT a (b*)> 子要素は0回以上任意の回数で出現する
ANY <!ELEMENT a ANY> DTDで定義されている要素であれば、どんな順序、どんな回数出現してよい
EMPTY <!ELEMENT a EMPTY> 要素aは空要素である

表1 内容モデル

 そのほか、要素の内容として文字データと子要素が混在している「混合内容」がありますが、こちらはXML 1.0仕様および書籍などでご確認ください。

属性リスト宣言

 属性を定義するのが「属性リスト宣言」です。属性リスト宣言の場合、ある要素に同じ属性を重複して記述すると、先に記述されている方を有効とします。さらに、内部サブセット、外部サブセットへそれぞれ記述できますが、内部サブセットに記述された方を有効とします。

<!ATTLIST  要素名  属性名  属性の型  デフォルト値>
属性リスト宣言の構文

 属性リスト宣言で指定できる属性の型を表2にまとめました。

説明
CDATA 任意の文字データ
ID 文書内で一意な値を持つ名前
IDREF ID型で設定された属性値を参照する
IDREFS ID型で設定された属性値を複数参照する
(属性値は空白で区切る)
ENTITY 外部実体を参照する(属性値は空白で区切る)
ENTITIS 複数の外部実体を参照する
NMTOKEN 名前として使える文字
(2文字目以降で使える文字も属性値の先頭へ記述できる)
NMTOKENS NMTOKENの複数形(属性値は空白で区切る)
列挙型 属性値の候補値を | で区切る

表2 属性リスト宣言で指定できる型

 今回は、列挙型に焦点を絞って解説します。列挙型は属性値として記述できるものをパイプ(|)で区切って指定します。文書本体で属性値を記述するときは一重引用符(')または二重引用符(")でくくりますが、カッコ内で属性の候補値を列挙するときは引用符のくくりは不要です。XML文書中で候補値以外の値を記述すると、valid XMLとはいえなくなります。 例をリスト5、6で示します。

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE root [
  <!ELEMENT root (#PCDATA)>
  <!ATTLIST root attr (01 | 02) "01">
]>
<
root attr="02"/>
リスト5 候補値の属性値を記述しているので、valid XMLである(test5_07.xml
 
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE root [
  <!ELEMENT root (#PCDATA)>
  <!ATTLIST root attr (01 | 02) "01">
]>
<
root attr="03"/>
リスト6 候補値以外の属性値を記述しているので、valid XMLではない(test5_08.xml

 次に、デフォルト値について解説します。デフォルト値には、属性が必須か、省略可能か、固定値を設定するか、などを記述します。

種類 説明
#IMPLIED 属性は省略可能
#REQUIRED 属性は必須
"デフォルト値" 属性値が記述されていなかったときに渡されるデフォルト値
#FIXED  "デフォルト値" 固定値を指定

表3 属性リスト宣言で指定できるデフォルト値

 例えば、リスト7のように属性リスト宣言ではデフォルト値を指定しているが、文書本体では属性・属性値の記述がない場合、どのようになるでしょうか。

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE root [
  <!ELEMENT root (#PCDATA)>
  <!ATTLIST root attr CDATA "01">
]>
<
root/>
リスト7 文書本体に属性の記述はないけれど、デフォルト値が指定されている場合…… (test5_09.xml

画面5 XMLパーサによってデフォルトの属性値が渡される

 XML 1.0仕様では、属性が省略されている場合、XMLパーサはその属性が宣言されたデフォルト値を付けて動作するように規定しています。#FIXEDのときも同じようにデフォルト値がXMLパーサによって渡されますが、#REQUIREDは属性を省略することを許可しないため、省略されたXML文書はwell-formed XMLであっても、valid XMLではありません。

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE root [
<!ELEMENT root (#PCDATA)>
<!ATTLIST root attr CDATA #REQUIRED>
]>
<root/>
リスト8 文書本体に属性の記述はないけれど、デフォルト値が指定されている場合……(test5_10.xml
   
画面6 #REQUIREDが指定された場合、デフォルト値は渡されずvalid XMLとならない

 ただし、DTDの場合「社員番号は正の整数値である」「社員情報は1回以上5回以下の範囲で出現しなければならない」など、データの型や出現回数などを細かく定義できないのが欠点です。こうしたDTDの欠点を解消するための仕組みとして、XML SchemaがW3Cより勧告されています。XML Schemaについては、次回解説します。

今回の問題の解答

 今回の問題の解答は次のとおりです。先述の解説を読み直し、試験に向けて備えてください。

(Q1) DTDについて正しく説明しているものをすべて選択してください。

 答えは(a)(c)(d)(f)です。それぞれの選択肢についての解説は、下記を参照してください。

 (a) : (参考になる解説 「スキーマ定義言語とDTD」)
 (b) : (参考になる解説 「スキーマ定義言語とDTD」)
 (c) : (参考になる解説 「DTDの記述場所」)
 (d) : DTDでも大文字小文字は識別されます。SGMLのときから使われていたDOCTYPE、ELEMENTなどのキーワードは大文字で記述します。
 (e) : Q5_1e.xmlQ5_1e.dtdで妥当性を検証してみましょう(参考になる解説 「DTDの記述場所」)。
 (f) : Q5_1f.xmlQ5_1f.dtdでどちらのデフォルト値が有効になっているか確認しましょう(参考になる解説 「DTDの記述場所」)。
 (g) : 外部サブセットを使うときのキーワードは両者間合意のSYSTEMか、標準化団体が策定したDTDであることを示すPUBLICのいずれかです。PRIVATEというキーワードはありません(参考になる解説 「DTDの記述場所」)。

(Q2) 以下のDTDに妥当なXML文書をすべて選択してください。

 答えは(c)(d)(i)(k)です。このDTDで記述されたスキーマ定義を文章で説明すると、次のようになります。

  • 要素rootは子要素として1回のみ出現する要素A、または1回以上出現する要素Bを子要素として含める。
  • 要素Aの内容は文字データで、属性aを付加情報として持つことができる。
  • 属性aの値は12、34、56のいずれかであり、デフォルト値は12である。
  • 要素Bの内容は文字データで、属性bを付加情報として持つことができる。
  • 属性bの値はID型であり、この属性は必ず出現しなければならない 。

 この問題に対応する解説は、「要素型宣言」「属性リスト宣言」が参考になります。

 (e) : 要素の中に同じ属性を記述することはできません。このデータはwell-formed XMLではないため、当然valid XMLでもありません。

 なお、Q2の選択肢ファイルを用意していますので、DTDの記述に妥当なXML文書がどれか確認してみるとよいでしょう。

 前回同様、記事の最後に「まとめノート」を用意しました。このまとめノートには、試験対策のポイント、出題範囲となる仕様、参考になる@ITの記事のリンクをまとめています。自習のときに使う参考ページとして、お役立てください。

 そして、次回のための予習問題を掲載します。次回はこの問題について解説していく予定です。

予習問題

(Q1) 以下のXML文書について正しく説明しているものを選択してください(左端の行番号はXML文書に含まれません)。

「XML文書
1  <root xmlns="urn:hoge"
2        xmlns:test="urn:test"/>    
3    <child1 attr="01">
4    <test:child2/>
5    <child3 xmlns=""/>
6  </root>

(a) このXML文書は、デフォルトの名前空間を使って記述されている
(b) (1行目) 要素rootが属している名前空間はurn:hogeである
(c) (1行目) 要素rootはどの名前空間にも属さない
(d) (1行目) 要素rootが属している名前空間はurn:testである
(e) (1行目) 要素rootが属している名前空間はtestである
(f) (3行目) 要素child1が属している名前空間はurn:hogeである
(g) (3行目) 要素child1はどの名前空間にも属さない
(h) (3行目) 属性attrが属している名前空間はurn:hogeである
(i) (3行目) 属性attrはどの名前空間にも属さない
(j) (4行目) 要素child2が属している名前空間はtestである
(k)
(4行目) 要素child2が属している名前空間はurn:testである
(l) (5行目)  要素child3はどの名前空間にも属さない
(m) (5行目) 要素child3が属している名前空間はurn:hogeである
(n) (5行目) 要素child3が属している名前空間はurn:testである
 

(Q2) 要素aの内容が10以上20未満となるようにXML Schemaで記述するときに必要な制約ファセットをすべて選択してください。

(a) <xsd:minInclusive value="10"/>
(b) <xsd:minExclusive value="10"/>
(c) <xsd:maxInclusive value="20"/>
(d) <xsd:maxExclusive value="20"/>

(Q3) DOMについて正しく説明しているものをすべて選択してください。

(a) 参照、更新ともに可能である
(b) DOMを利用する場合、Javaでプログラミングする必要がある
(c) Documentは、XML文書全体を表すオブジェクトである
(d) W3Cで策定された仕様である 


まとめノート:valid XMLとDTDの関係

○今回の試験対策のポイント

  • スキーマ定義言語
  • DTD
  • valid XML(妥当なXML)
  • DTDの記述場所
  • 要素型宣言
    • 内容モデル
  • 属性リスト宣言
    • 属性の型
    • デフォルト値

○今回の学習内容で出題範囲となる仕様

○今回の学習内容で実機確認を行うときに役立つフリーツール

○今回の学習内容で参考になる@ITの記事

○今回の学習内容で参考になるXML用語集 @IT XML用語事典より)

(6)模擬問題:XMLの基本

Index
連載:XMLマスターへの道
  (1)XMLマスター:ベーシック試験のレベルは?
  (2)XMLの概要と起源、関連規格
  (3)XML文書の要素、エンコーディング、宣言
  (4)すべてのXM文書は整形式である
(5)valid XMLとDTDの関係
  (6)模擬問題:XMLの基本
  (7)模擬問題:W3C XML Schema
  (8)模擬問題:DOM
  (9)DTDの実体宣言と記法宣言
  (10)XSLTの基本構造を理解する
  (11)XSLTで必須の制御命令を覚える
  (12)XPathによるノードの指定法を理解する
  (13)名前空間を理解しDOMの概要をつかむ
  (14)XML Schemaを利用したスキーマ定義
  (最終回)XML Schema―型の再利用と名前空間


連載:XMLマスターへの道


XML & SOA フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日月間