July 21, 2008

PHP - XML(3)

XMLにおける、複数のネームスペースと複数のスキーマによるバリデーションの考察。

user要素は以下のようなprofile要素(型)を持つとする。
<profile>
  <age>18</age>
  <prefecture>Tokyo</prefecture>
</profile>
このprofile型は他でも使えるかもしれない、という場合、profile型を定義するスキーマ"profile.xsd"を作成する。この時、このprofile型はネームスペース"prf"に属することとする。

profile.xsdにはprofile型(複合型)、age型(単純型)、prefecture型(単純型)が含まれるため、それらを宣言する。
<element name="profile" type="prf:PROFILE_CTYPE" />
<element name="age" type="prf:PROFILE_AGE_STYPE" />
<element name="prefecture" type="prf:PROFILE_PREFECTURE_STYPE" />
単純型の定義を行う。
<simpleType name="PROFILE_AGE_STYPE">
  <restriction base="integer">
    <minInclusive value="18" />
    <maxInclusive value="120" />
  </restriction>
</simpleType>

<simpleType name="PROFILE_PREFECTURE_STYPE">
  <restriction base="string" />
</simpleType>
定義した単純型を参照し、profile型を定義する。
<complexType name="PROFILE_CTYPE">
  <sequence>
    <element ref="prf:age" />
    <element ref="prf:prefecture" />
  </sequence>
</complexType>
出来上がったprofile.xsdの全体。
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://mydomain/profns"
        xmlns="http://www.w3.org/2001/XMLSchema"
        xmlns:prf="http://mydomain/profns">
  
  <element name="profile" type="prf:PROFILE_CTYPE" />
  <element name="age" type="prf:PROFILE_AGE_STYPE" />
  <element name="prefecture" type="prf:PROFILE_PREFECTURE_STYPE" />
  
  <simpleType name="PROFILE_AGE_STYPE">
    <restriction base="integer">
      <minInclusive value="18" />
      <maxInclusive value="120" />
    </restriction>
  </simpleType>
  
  <simpleType name="PROFILE_PREFECTURE_STYPE">
    <restriction base="string" />
  </simpleType>
  
  <complexType name="PROFILE_CTYPE">
    <sequence>
      <element ref="prf:age" />
      <element ref="prf:prefecture" />
    </sequence>
  </complexType>
</schema>
XMLでuserは以下のように記述される(プロフィールは除外してある)。
<user>
  <id>1</id>
  <registeredDate>2008-01-01T10:00:00</registeredDate>
</user>
userはネームスペース"usr"に属することとした場合、XMLは次のように変更される。
<usr:user>
  <usr:id>1</usr:id>
  <usr:registeredDate>2008-01-01T10:00:00</usr:registeredDate>
</usr:user>
ネームスペース"usr"のスキーマ定義を行う。
<element name="users" type="usr:USERS_CTYPE" />
<element name="user" type="usr:USER_CTYPE" />
<element name="id" type="usr:USER_ID_STYPE" />
<element name="registeredDate" type="usr:USER_REGISTERED_DATE_STYPE" />

<complexType name="USERS_CTYPE">
  <sequence>
    <element ref="usr:user" minOccurs="1" maxOccurs="unbounded" />
  </sequence>
</complexType>

<simpleType name="USER_ID_STYPE">
  <restriction base="integer" />
</simpleType>

<simpleType name="USER_REGISTERED_DATE_STYPE">
  <restriction base="dateTime" />
</simpleType>

<complexType name="USER_CTYPE">
  <sequence>
    <element ref="usr:id" />
    <element ref="usr:registeredDate" />
  </sequence>
</complexType>
次に、userはprofileを持つという定義の実装を行う。profile型は外部(profile.xsd)で定義されているため、それをインポートする。
<import namespace="http://mydomain/profns"
        schemaLocation="http://mydomain/xmlSchema/profile.xsd" />
インポートするとprofile型が参照できるようになる。
userにprofile要素を追加する。
<complexType name="USER_CTYPE">
  <sequence>
    ...
    <element ref="prf:profile" />
  </sequence>
</complexType>
出来上がったuser.xsdの全体。
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://mydomain/userns"
        xmlns="http://www.w3.org/2001/XMLSchema"
        xmlns:usr="http://mydomain/userns"
        xmlns:prf="http://mydomain/profns">
  
  <import namespace="http://mydomain/profns"
          schemaLocation="http://mydomain/xmlSchema/profile.xsd" />
  
  <element name="users" type="usr:USERS_CTYPE" />
  <element name="user" type="usr:USER_CTYPE" />
  <element name="id" type="usr:USER_ID_STYPE" />
  <element name="registeredDate" type="usr:USER_REGISTERED_DATE_STYPE" />
  
  <complexType name="USERS_CTYPE">
    <sequence>
      <element ref="usr:user" minOccurs="1" maxOccurs="unbounded" />
    </sequence>
  </complexType>
  
  <simpleType name="USER_ID_STYPE">
    <restriction base="integer" />
  </simpleType>
  
  <simpleType name="USER_REGISTERED_DATE_STYPE">
    <restriction base="dateTime" />
  </simpleType>
  
  <complexType name="USER_CTYPE">
    <sequence>
      <element ref="usr:id" />
      <element ref="usr:registeredDate" />
      <element ref="prf:profile" />
    </sequence>
  </complexType>
</schema>
これらのスキーマ定義に沿うXMLの例。
<?xml version="1.0" encoding="utf-8"?>
<usr:users xmlns:usr="http://mydomain/userns"
           xmlns:prf="http://mydomain/profns"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://mydomain/xmlSchema/user.xsd">
  <usr:user>
    <usr:id>1</usr:id>
    <usr:registeredDate>2008-01-01T10:00:00</usr:registeredDate>
    <prf:profile>
      <prf:age>20</prf:age>
      <prf:prefecture>Tokyo</prf:prefecture>
    </prf:profile>
  </usr:user>
  <usr:user>
    <usr:id>2</usr:id>
    <usr:registeredDate>2008-02-02T15:00:00</usr:registeredDate>
    <prf:profile>
      <prf:age>30</prf:age>
      <prf:prefecture>Aichi</prf:prefecture>
    </prf:profile>
  </usr:user>
</usr:users>
バリデーションのコード例。
$doc = new DOMDocument();
$doc->loadXML(file_get_contents("/path/to/users.xml"));

$xpath = new DOMXPath($doc);
$res = $xpath->evaluate("//@xsi:schemaLocation");
$doc->schemaValidate($res->item(0)->nodeValue);
試しに年齢を200にするとWarningが発生する。スキーマ定義やprofile.xsdのインポートなど、機能していることがわかる。
Warning: DOMDocument::schemaValidate() [function.DOMDocument-schemaValidate]:
  Element '{http://mydomain/profns}age': [facet 'maxInclusive'] The value '200' is greater than the maximum value allowed ('120').
  in /usr/local/www/data/sabel/app/index/controllers/Index.php on line 17


トラックバックURL

コメントする

名前:
URL:
  情報を記憶: 評価:  顔   星
 
 
 
Sabel

Sabel PHP Frameworkを開発しています。
http://www.sabel.jp/

Search
Categories
Tags
Recent Articles
Archives