xsd:any(2)

2003年5月25日(日)更新


■XMLデータ例とXML Schema例(xsd:anyを使用)

たけち: 前回はDTDのANYについて学んだよね。

さらら: えぇ、DTDのANYだと次のような問題があったのね。

  1. ANYの部分にはDTDで定義されるすべての要素が出現可能であるため、意図しない要素まで出現を許してしまう。
  2. 参照する側のDTDでは、参照される側のDTDの中で定義されているのと同じ名前の要素の要素型宣言が出現してはならない。また参照されるDTDが複数あるとき、それらの中に同じ名前の要素の要素型宣言が存在してはならない。

たけち: そうだね。で、今回はxsd:anyについてお話ししようね。まずは以下のXMLデータとXML Schemaを見てみよう。前回の例では敢えて名前空間を持たないXMLデータを示したけれど、これは名前空間を設定しているよ。

XMLデータ例: 【report1.xml】
<?xml version="1.0" encoding="Shift_JIS" ?>
<rep:report xmlns:rep="http://www.example.com/report"
    xsi:schemaLocation="http://www.example.com/report   report.xsd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <rep:heading>万葉集総論</rep:heading>
    <rep:author>たけち</rep:author>
    <rep:regularContents> 万葉の時代に触れるために、まず万葉集を開いてみよう。<rep:lineBreak /> そこでは、万葉の人達の息遣いが聞こえるようだ。</rep:regularContents>
</rep:report>

XMLデータ例: 【report2.xml】
<?xml version="1.0" encoding="Shift_JIS" ?>
<rep:report xmlns:rep="http://www.example.com/report"
    xmlns:xh="http://www.w3.org/1999/xhtml"
    xsi:schemaLocation="http://www.example.com/report report.xsd
            http://www.w3.org/1999/xhtml
             http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<rep:heading>万葉集総論</rep:heading>
<rep:author>たけち</rep:author>
<rep:extendContents>
    <xh:img src="nara1.jpg" alt="奈良全景" />
    <xh:p>万葉の時代に触れるために、まず<xh:strong>万葉集</xh:strong>を開いてみよう。</xh:p>
    <xh:p>そこでは、<xh:br />万葉の人達の息遣いが聞こえるようだ。</xh:p>
</rep:extendContents>
</rep:report>

XML Schema例: 【report.xsd】
<?xml version="1.0" encoding="Shift_JIS" ?>
<xsd:schema targetNamespace="http://www.example.com/report"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     xmlns:rep="http://www.example.com/report">

<xsd:element name="report" type="rep:ReportType" />

<xsd:complexType name="ReportType">
<xsd:sequence>
<xsd:element ref="rep:heading" />
<xsd:element ref="rep:author" />
<xsd:choice>
<xsd:element ref="rep:regularContents" />
<xsd:element ref="rep:extendContents" />
</xsd:choice>
</xsd:sequence>
</xsd:complexType>

<xsd:element name="heading" type="xsd:string" />
<xsd:element name="author" type="xsd:string" />

<xsd:element name="regularContents" type="rep:RegularContentsType" />

<xsd:complexType name="RegularContentsType" mixed="true">
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
        <xsd:element ref="rep:lineBreak" />
    </xsd:choice>
</xsd:complexType>

<xsd:element name="lineBreak" type="rep:LineBreakType" />

<xsd:complexType name="LineBreakType" />

<xsd:element name="extendContents" type="rep:ExtendContentsType" />

<xsd:complexType name="ExtendContentsType">
    <xsd:sequence>
        <xsd:any namespace="##other" processContents="lax" maxOccurs="unbounded"/>
    </xsd:sequence>
</xsd:complexType>

</xsd:schema>


■【report1.xml】と【report2.xml】の違い

たけち: まず【report1.xml】と【report2.xml】の違いを見てみようね。【report2.xml】では、XHTML系の要素も使われているよね。

さらら: えぇ。

たけち: 【report1.xml】では、
    xsi:schemaLocation="http://www.example.com/report   report.xsd"
 と書いてあるけど、【report2.xml】では
    xsi:schemaLocation="http://www.example.com/report report.xsd
            http://www.w3.org/1999/xhtml
             http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd"

 と書かれているよね。

さらら: ほんとだわ。/p>

たけち: 【report1.xml】では、名前空間とスキーマファイルのペアがひとつだけど、【report2.xml】では、ふたつになっているんだね。

【report1.xml】と【report2.xml】のxsi:schemaLocation


■DTDのDOCTYPE宣言とXML Schemaのxsi:schemaLocation属性

さらら: ふ〜ん。

たけち: ここでDTDとの違いについて考えてもらいたいんだけれど、DTDのDOCTYPE宣言で指定できるスキーマファイルは1つだけだったよね。だから、先に作った【extendReport2.dtd】のように、スキーマファイルを融合させるだけのためのDTDを作らなくてはいけなかったね。もちろんこれと同様のことはXML Schemaでもimportを使えばできるけど、わざわざこれをしなくても、xsi:schemaLocation属性を使えば、複数のスキーマファイルを指定できるんだね。

さらら: なるほど、これは便利よね!(^ ^)

さらら

たけち: さて、DTDと対応するXML Schema側の仕掛けをみてみようね。前回の、
    <!ELEMENT extendContents ANY>
 というDTDに相当する部分を、XML Schema 【report.xsd】では、
<xsd:element name="extendContents" type="rep:ExtendContentsType" />

<xsd:complexType name="ExtendContentsType">
    <xsd:sequence>
        <xsd:any namespace="##other" processContents="lax" maxOccurs="unbounded"/>
    </xsd:sequence>
</xsd:complexType>
 と書いているんだ。

さらら: 
        <xsd:any namespace="##other" processContents="lax" maxOccurs="unbounded"/>
というのが全然わからないわ。(^ ^;)


■xsd:any namesapce="##other"

たけち: この、xsd:any要素というのは、「この場所に任意のどんな要素が来てもいいですよ」ということを示している要素なんだ。
ここでまず注意したいのは、DTDのANYは「任意の内容モデル」を意味していたのに対し、xsd:any要素要素というのは、任意の要素を意味しているんだね。DTDのANYとxsd:any要素とでは、内容モデルなのか、それとも要素なのか、という違いがあるから気をつけてね。
DTDのANYは、テキストの混在も含む任意の内容モデルだったけれど、xsd:any要素は要素なので、内容モデルの中で使われるんだ。

さらら: う〜ん。それは何となくわかるけれど、namespace="##other"というのが全然わからないんだけど(^ ^;)

たけち

たけち: そうだねぇ。。。xsd:any要素というのは、「この場所に任意のどんな要素が来てもいいですよ」という意味だと説明したけれど、だけどやみくもに何でも良いというわけじゃなくて、名前空間ごとに条件を設定できるんだよ。

さらら: 名前空間ごと?

たけち: このnamespaceという属性によって、どういう名前空間の属性を許可するのかが設定できるようになるんだ。

さらら: あっ。そうなの。

たけち: 例えばこの場合のnamespace="##other"というのは、
対象名前空間以外の名前空間であれば、任意のどんな要素が来てもいいですよ
 という意味になるんだ。

さらら: そうなんだぁ。ということは、対象名前空間の要素は出現してはいけないのね。

たけち: そうそう。

たけち: そうそう。この場合の対象名前空間は、repという接頭辞であらわされるhttp://www.example.com/reportだから、この名前空間の要素だけは出現してはいけないんだ。だから、XMLデータは、エラーとしてはじくことができるんだよ。

XMLデータ例: report.xsdに合致しない例
<?xml version="1.0" encoding="Shift_JIS" ?>
<rep:report xmlns:rep="http://www.example.com/report"
     xsi:schemaLocation="http://www.example.com/report report.xsd"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<rep:heading>これっておかしい?</rep:heading>
<rep:author>変野一郎</rep:author>
<rep:extendContents>
    <rep:author>変野二郎</rep:author>
    <rep:heading>おかしいよね</rep:heading>
    <rep:heading>やっぱりおかしいか</rep:heading>
</rep:extendContents>
</rep:report>


■xsd:any namesapce="##targetNamespace"

さらら: なるほどねぇ〜。これは使えるわね!(^ ^)

たけち: 逆にこういうXMLデータを通そうと思うと、
    <xsd:any namesapce="##targetNamespace" />
 と書けばいいんだよ。

さらら: へぇ、さっきは##otherだったけれど、これは##targetNamespaceなのね。

たけち: 他にもいくつものパターンを知っておこうね。

  • <xsd:any namesapce="##any" />
    すべての任意の要素が出現可能(namespace属性が省略された場合、これがデフォルトとなる)
  • <xsd:any namesapce="##local" />
    名前空間を持たない任意の要素が出現可能
  • <xsd:any namesapce="http://example.com/ex1 http://example.com/ex2" />
    名前空間http://example.com/ex1と名前空間http://example.com/ex2の任意の要素が出現可能

■xsd:anyの記述例

たけち: ここで注意して欲しいのは、
   <xsd:any   namesapce="##local   http://example.com/ex1" />
 とか、
   <xsd:any   namesapce="##targetNamespace   http://example.com/ex1" />
 のような書き方はできるけれど、
   <xsd:any   namesapce="##any   http://example.com/ex1" />
 という書き方や、
   <xsd:any   namesapce="##other   http://example.com/ex1" />
 という書き方はできないということなんだ。何故なら、##anyや##otherが示す名前空間の中にhttp://example.com/ex1も当然含まれるよね。


■processContents="lax"など

さらら: そう言われればそうよね。それからあと、processContents="lax"という属性がどういう意味なのかわからないんだけれど。

たけち: うん、このprocessContentsという属性なんだけれど、これはXMLデータをVailidatorが検証するする際に、どういうふうに検証するかとか、しないとかいったことを設定する属性なんだよ。

さらら: あっ、そっ、そう...(^ ^; ?

たけち: このprocessContentsは、strict、lax、skipの3つの値のどれかをとるんだ。それぞれの意味は次のようなんだよ。

さらら
  • <xsd:any processContents="strict">
    このxsd:anyの箇所に出現した要素を、きちんと検証する (processContents属性が省略された場合には、これがデフォルトとなる)
  • <xsd:any processContents="lax">
    このxsd:anyの箇所に出現した要素についてのスキーマが判明していれば検証する。 判明していなければ検証せずに、そのまま通す。
  • <xsd:any processContents="skip">
    このxsd:anyの箇所に出現した要素についてのスキーマが判明していてもいなくても、検証せずにそのまま通す。

さらら: う〜ん、laxとかskipっていい加減なのね(^ ^;)

たけち: まあ、そう言えるかもしれないね。ただ、DTDは定義されているけれど、XML Schemaでは定義されていないようなXMLの応用規格は実際には少なくないから、laxやskipなども場合によっては使うことも現実的な手段だね。

さらら: あっ、そっか。。。なるほどね。

たけち: もう一つだけ覚えておきたいのは、このxsd:any要素は、<xsd:element ref="○○">などと同様に、minOccursやmaxOccursなどの出現制約を設定できるということなんだ。例えば、
    <xsd:any   namesapce="http://example.com/ex1"   minOccurs="3"   maxOccurs="3" />
 と書くと、http://example.com/ex1の名前空間に属する要素が必ず3回出現しないといけない、ということになるんだ。

さらら: へぇ〜、こんな設定まで可能なのね。

たけち: 任意のどんな要素が出現してもよい、というxsd:anyについてはこれでおしまい。次回は、任意のどんな属性が出現してもよい、というxsd:anyAttributeについて解説するね。

さらら: あっ、は〜い。ありがと。

次回はxsd:anyAttributeです...... (^ ^;

さらら

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