XML/XMLスキーマ

Last-modified: 2008-03-10 (月) 12:12:05

XMLスキーマ

XMLスキーマとは

XML文書を定義するためのスキーマ言語です。DTDに変わるスキーマ言語としてW3Cより勧告されました。
XMLスキーマとDTDの違いなどや細かいことはググってみてください。このページでは基本的なxmlスキーマの書き方などは紹介しません。というのはWEBで調べればいくらでも出てくるからです。ここでは筆者が困ったことなどを中心に書かれています。

注意点

記述の統一

可読性を向上させるという意味でも最低プロジェクト単位での記述の統一は必要です。個々が統一性のないものを作成すると使用者側での可読性が薄れてしまいます。下記にあげる項目は筆者が最低は統一しておいたほうがよいと思われる項目です(一般的にも下記のようにしたほうがよいみたいです)。

名前空間とは

XMLスキーマを学ぶ上でもっとも重要なキーワードです。XMLスキーマはWEB上のいたるところで公開されています。そこでそのスキーマ1つ1つに対して名前を持たせることによりスキーマを特定する仕組みが名前空間というものです。なのでそのスキーマの名前空間は基本的に一意でなければなりません。この名前空間はよくURLのほうな記述でかかれることが一般的となっているようです(URLはアドレスが一意なのでページが特定できます)。XMLスキーマ文書の始めは基本的に下記のようになります。

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsd:schema
3:             targetNamespace="http://www.garnet.hiro.com/test"
4:             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
5:             xmlns:tst="http://www.garnet.hiro.com/test">

1行目はこのスキーマ文書がXMLであることを宣言するものです。これ自体はXMLスキーマとは関係ありません。なので1行目が必須というわけではありませんが、記述しておくのが一般的のようです。encoding はUTF-8である必要はありません。基本的にXML文書を書く場合、UTF-8であることが多いためサンプルではUTF-8としています(Shift_JISでももちろんOKです)。
2行目はXMLスキーマであることの宣言です。XMLスキーマを記述する際は必ず必要になる宣言(要素)です。
3行目はこのXMLスキーマが http://www.garnet.hiro.com/test という名前空間に属することを宣言しています。
4行目はこのスキーマで xsd が接頭辞として記述されているタグは、そのタグが xmlls:xsd の名前空間に属していることを宣言しています。xsdである必要はありません。ただ一般的にはxsdの名前空間に属することを示す接頭辞には、xsdxsなどが使用されます。
5行目はこのスキーマで tst が接頭辞として記述されているタグは、そのタグが xmlls:tst の名前空間に属していることを宣言しています。

ローカル要素は使用しない

ローカル宣言された要素はデフォルト名前空間を使用しているXML文章には使用できないからです。
例)下記のようなスキーマがあるとします。
test.xsd

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://www.garnet.hiro.com/test">
  <xsd:element name="User">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="UserName" type="xsd:string" />
        <xsd:element name="Age" type="xsd:integer" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

上記のスキーマに対して下記のようなXML文章を作成してみました。
test.xml

<User xmlns="http://www.garnet.hiro.com/test">
  <UserName>テスト 太郎</UserName>
  <Age>20</Age>
</User>

はたしてtest.xmlはtest.xsdの検証に引っかかないでしょうか?
答えは検証チェックに引っかかります。
Userの子要素であるUserName、Age、UserIdはtargetNameSpaceの名前空間に属さないからです。検証が正常に通るようにするには下記のように行います。

<tst:User xmlns:tst="http://www.garnet.hiro.com/test">
  <UserName>テスト 太郎</UserName>
  <Age>20</Age>
</tst:User>

ポイントはデフォルト名前空間を使用しないということです。デフォルト名前空間を使用してしまうとすべての要素について名前空間の接頭辞がついていないものについてデフォルト名前空間が適用されてしまいます。では下記のようなXML文書ではどうでしょうか?

<User xmlns="http://www.garnet.hiro.com/test"
      xmlns:tst="http://www.garnet.hiro.com/test">
  <tst:UserName>テスト 太郎</tst:UserName>
  <tst:Age>20</tst:Age>
</User>

これも当然検証に引っかかります。一番最初に述べましたがローカル宣言されている要素には名前空間が適用されないというXMLスキーマの仕様がありました。基本的にプロジェクトで使用するようなものでそうそういろいろなスキーマを駆使しているようなものはあまり見かけません(基本的に1つのスキーマで1つの名前空間というのがほとんどです)。なのでXML文書を作成する側では名前空間などはあまり意識したくありません。このような場合方法は2つあります。一つは要素をローカル宣言しないという方法です。この方法の場合、下記のようになります。

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://www.garnet.hiro.com/test"
           xmlns:tst="http://www.garnet.hiro.com/test">
  <xsd:element name="User">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="tst:UserId" />
        <xsd:element ref="tst:UserName" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
  <xsd:element name="UserName" type="xsd:string" />
  <xsd:element name="Age" type="xsd:integer" />
</xsd:schema>

もう一つがelementFormDefault="qualified"をスキーマに指定するという方法です。この方法の場合は下記のようになります。

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://www.garnet.hiro.com/test"
           elementFormDefault="qualified">
  <xsd:element name="User">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="UserName" type="xsd:string" />
        <xsd:element name="Age" type="xsd:integer" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

となります。

グローバル属性は使用しない

デフォルト名前空間は要素のみサポートされているためです。

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://www.garnet.hiro.com/test"
           elementFormDefault="qualified"
           attributeFormDefault="qualified">
  <xsd:element name="User">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="UserName" type="xsd:string" />
        <xsd:element name="Age" type="xsd:integer" />
      </xsd:sequence>
      <xsd:attribute name="Id" type="xsd:integer" use="required" />
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

Userの属性としてIdをつけました。またこれをグローバル属性にするためにattributeFormDefault="qualified"を指定しています。この場合下記のようなXML文章は検証に引っかかるでしょうか?

<User xmlns="http://www.garnet.hiro.com/test" Id="1">
  <UserName>テスト 太郎</UserName>
  <Age>20</Age>
</User>

答えは検証に引っかかります。先ほどいったようにデフォルト名前空間は要素のみサポートされているからです。なので下記のように記述する必要があります。

<User xmlns="http://www.garnet.hiro.com/test"
      xmlns:tst="http://www.garnet.hiro.com/test" tst:Id="1">
  <UserName>テスト 太郎</UserName>
  <Age>20</Age>
</User>

要素・属性名の説明

  • schema要素
    • targetNamespace="xsd:string"属性
      このスキーマが属する名前空間を指定する属性です。この名前空間はユニークIDみたいなもので一意にする必要があります。
  • elementFormDefault="[qualified | unqualified]"属性
    値にqualifiedが指定された場合、ローカル宣言されている要素のすべてをtargetNamespceに属するという意味になります。これはすべてのローカル要素に対してform="qualified"を宣言することと同じ意味を指します。unqualifiedが指定された場合は、ローカル宣言はtargetNamespaceに属さないという意味なります。デフォルトはunqualifiedとなります。
  • attributeFormDefault="[qualified | unqualified]"属性
    値にqualifiedが指定された場合、ローカル宣言されている属性のすべてをtargetNamespceに属するという意味になります。これはすべてのローカル属性に対してform="qualified"を宣言することと同じ意味を指します。unqualifiedが指定された場合は、ローカル宣言はtargetNamespaceに属さないという意味なります。デフォルトはunqualifiedとなります。

参考サイト

XML Schema - THECHSCORE
XML Schema:やるべきこと、やってはいけないこと
SEのためのXML Schema入門