XML XSD 基本から 初心者用 その1

xmlを使うにはxsdを知らなければなりません。 しかしxsd含めたxml仕様が適当なので混乱するので非常に厄介です。 今回腰を据えて勉強したのでやっと分かったので、私が矛盾に思う事や不思議に思う事も調べて私が見直してすぐ思い出せるように出来るだけ分かりやすいようにまとめ始めました。 間違いもあるかもしれないので見つけた場合は教えていただけると本当に助かります。

XML(Extensible Markup Language)とは

  • Extensible Markup Languageとは、“ユーザーが自由にタグ(意味のラベル)を拡張して作れる言語”
  • で噛み砕くと「コンピュータ同士が“意味つきのデータ”をやり取りするための、ルール付きの文章フォーマット」です。
  • 拡張というのは、HTMLは<div>や<a>や<p>固定など決まったタグを使いますが、これを自由に定義して自分でタグ名を作り、そのタグに意味や制限をつけることが出来るのでHTMLからの拡張という事です。 XMLは軍事や出版向けの重量のSGMLのWeb用簡略軽量版です。
  • XMLが使われているのは、WebではRSS(ニュースフィード)、Atom(ブログ配信)、SVG(ベクター画像)、SOAP(Webサービス(金融やセキュリティカメラ等))、設定ファイル(Androidなど)。 世界標準として業界では、会計、医療、貿易、保険、製造、建物等とか個別では金融機関、政府機関、法律など。 確定申告の証券会社からのデーターもxmlでeTaxに取り込んで広がってきています。
  • xmlのメリット
    • ルールを厳密に決めることが出来るのでデーターミスや不正やバグを入口で止めれる。
    • 自分でルールを定義できる。 HTMLはできない。
    • OS関係ない。 Windows,Linux,Macでも、PythonでもJavaでも使える。
    • 人間が読めるしコンピューターも読める
    • 複雑なデーター構造を綺麗に表現できる
  • xmlのデメリット
    • 仕様が曖昧な部分があり習得が難しい
    • 設計を見すると地獄をみる
    • 冗長でファイルが大きくなりがち
    • 書くのも読むのも思い
    • しかし用途に応じて使うと、合う用途だとメリット90点、デメリット5点。合わない用途だとメリット0点、デメリット70点になるのでxmlを理解した上で適する用途で使う必要があります。

最初に 

  • XMLファイルを作る前に、XMLの構造や制限を定義する.xsd(XML Schema Definition)ファイルを使わなければなりません。 
  • .xsdは各業界標準など既に存在するものを使う方法と、それらを派生させて新たに作ったり、新たに0から作ったりと出来ます。
  • とかこの.xsdファイルに記述する内容をスキーマ(schema:構造)を呼ぶ。
  • .xsdはclassの定義ようなもので実体がないので値を持てません。 .xmlはclassをnewで実体化したinstanceでメンバに値を持てるように値を持てます。 例えばpriceが100でunitがUSDと価格が$100と値を持てるのはxmlです。 xsdに予め『priceというところにはintegerで、その数字の単位はUSDです』と定義しておきます。
  • .xsdでも.xmlでも<>は全てタグです。
  • .xsdはデータの型やelementを個々に定義します。 この定義したものをスキーマ(schema)といいます。
  • xmlは<root></root>や<user></user>が一番外側のタグでrootやuserは慣習的な文字で<root>や<user>もelementとしてxsdで定義しておかなければなりません。
  • xmlはelementばかりで構成しています。 elementとは実体(或いはinstance)の事で直訳して要素という人もいます。 しかし日本語として要素の他のタグの中身も全て要素となり混乱するので、要素と言っている人は100%間違っています。 elementも英語での意味も要素と同じですが、少なくとも<element>とxsdで使っている固有名詞なのでギリセーフで意味が通ります。
  • 実体である<element>の中に、実体ではないattributeやtypeなどの属性や値の型タイプなどを定義します。
  • ここまで理解できたら30%まで来ています。 このサイトの最後まで理解すると70%の基礎力になると思います。
    • もう一度ですが、xmlを作るにはxsdが必要。 これからはxsdの定義方法を中心に進めます。

.xsd 最初の宣言

  • .xsdを書く時に以下から始まります。
  • <?xml version=”1.0″ encoding=”UTF-8″?>
    • 最初に必ず書かないといけません。 スペースがあってもエラーになります。 小文字でないとエラーになります。
    • versionは1.1がありますが失敗作で世界の99.9%は1.0です。2はありません。
    • UTF-8がないと、東京、円などの日本語が値に使えません。
    • このタグはclose </>のタグは不要です。
  • <xs:schema…>と</xs:schema>の間に書くと決まっています。
  • xmlns:xs=”http://www.w3.org/2001/XMLSchema”
    • xsというnamespaceを”http://www.w3.org/2001/XMLSchema”から読み込んでます。 これも必ず必要です。
    • これでxs:element、xs:integerなどxsdで基本的に使います。 xsなどをnamespaceといいます。 elementやintegerをlocalnameといいます。
  • targetNamespace=には意味はないができるだけ自分のドメインのURLを記述します。 Namespace URIと呼ぶそうです。 この行も必要です。 自分が書いているxsdに世界で他の人と重ならないURIを指定しなければならないので、大体はドメインURLを使うようです。 このNamespace URIが同じだと、同じグループのxsdとして扱われincludeで取り込みますが、異なるNamespace URIで記述されていると、importで取り込むことになり、記述方法も難しくなります。  
  • xmlns:tns=もどんな時でも絶対他のxsdと混ざってはいけないので、上記のNamespace URIを記述します。 xmlnsはxmlのnamespaceという意味で、ここではtnsとあるのでtns:myTypeなどとmyTypeという型の名前にtns:というnamespaceを指定するためのものです。 この行も必要です。 tnsでなくても好きな文字で構いませんがxsやxsiは決まっているので使えません。 自分で書くxsdでは慣習としてtnsとします(This name space)の略。
    • namespaceとは、例えば同じlocalnameがあったします。 その時namespaceで違いを表します。 tns:myTypeとichiri:myTypeは異なるものです。違う場所にあるmyTypeということですね。
  • elementFormDefault=”qualified”は、タグ<>内で必ずnamespace指定が必要です。 定義では省いてもいいですが、実際使い物にならなくなります。
  • 以下例では、version=”1.0.0″と書いてあるものもありますが、システムは一切見ていません。 しかし自分が管理する時に使えるので日付など入れておくのがいいかもしれません。
i.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://dx.ichiri.biz/dx-platform"
           xmlns:tns="https://dx.ichiri.biz/dx-platform"
           elementFormDefault="qualified"
           version="2026-02-19">
       :
       :
       :
</xs:schema>

XMLでの宣言

  • <?xml version=”1.0″ encoding=”UTF-8″?>
    • xsd同様xmlでも必要です。
  • 次に来るのがxmlの大外枠です。 rootやuserとするのが慣習です。そのrootやuserはxsdで<element name=”root”>として作っておかなけばなりません。 するとその下のxmlns:tns=”https://dx.ichiri.biz/dx-platform”のtnsを使ってtns:rootと指定します。
  • xsi:schemaLocation=”https://dx.ichiri.biz/dx-platform myschema.xsd”の””内はURLと.xsd間だけ半角スペース1個だけ必要です。
  • フルパスで書くときも半角スペース1個が必要です。でなければエラーになります。
    • xsi:schemaLocation=”https://dx.ichiri.biz/dx-platform https://dx.ichiri.biz/dx-platform/web/xsd/myschema.xsd”
i.xml
<?xml version="1.0" encoding="UTF-8"?>
<ichiri:root 
  xmlns:ichiri="https://dx.ichiri.biz/dx-platform"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://dx.ichiri.biz/dx-platform myschema.xsd">

  <ichiri:id>101</ichiri:id>
  <ichiri:name>Ichiri</ichiri:name>

</ichiri:root>

XMLを難しくする仕様

xsdで定義してxmlを記述する際、複数のxsdを組み合わせて作る場合があります。下記のようにichiriとgoogleのi.xsdとg.xsdで定義したとします。 xml全体の構成はichiri:rootなのでi.xsdでg.xsdを使ってichiri.rootで使う要素とその使う回数などを定義して置かなければなりません。 なのでi.xsd内でg.xsdを呼び出して、g.xsdのelementや属性(attribute)などを使って記述しておきます。 これはPythonや他の言語も同じimportなどで取り込みます。 XMLの馬鹿なところは、他の全ての言語はその関数やクラスを使うプログラムでは、関数やクラスを作ったファイルでimportしたライブラリを自動継承するので再度宣言する必要がありません。 しかしXMLはどこまでもどこまでヒヒヒひ孫まで遡っても全てのxsdを調べて記述しておく必要があります。 これは仕様設計のミスと思いますが、XMLとXSDのパーサーは依存関係を追えないので全て記述が必要です。 以下は、i.xsdとg.xsdの2つのxsdを使って定義している場合の例です。

i.xml
<?xml version="1.0" encoding="UTF-8"?>
<ichiri:root 
  xmlns:ichiri="https://dx.ichiri.biz"
  xmlns:google="http://www.google.com/schemas/sitemap/0.9"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
    https://dx.ichiri.biz i.xsd 
    http://www.google.com/schemas/sitemap/0.9 http://www.google.com/schemas/sitemap/0.9/sitemap.xsd">

</ichiri:root>

さらに適当な仕様

schemaLocationはあくまでヒントとかかれているので、パーサーがすでに見つけたからそっちを使うと間違ったxsdを使ってエラーになります。 馬鹿げてますがXMLの仕様なのでしかたありません。 なので皆さんは必ずフルパスで指定してください。 そして更に馬鹿げているのは、フルパスを指定するschemaLocationにnamespaceで指定した意味不明のグループ名をもう一度書いて、さらに半角スペースをあけフルパスを書くという3ど手間が必要です。 そのグループ名の2回記述は全く意味がありませんし、そのせいで古いxsdがキャッシュに残ってしまいエラーを起こす問題があり本当に馬鹿げていますが、XMLの仕様として諦めてください。

i.xml
<?xml version="1.0" encoding="UTF-8"?>
<ichiri:root 
      xmlns:ichiri="https://dx.ichiri.biz" 
      xmlns:google="https://google.com"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="https://dx.ichiri.biz https://dx.ichiri.biz/<full_path>/i.xsd 
                          https://google.com https://google.com/<full_path>/g.xsd">
    <ichiri:user> ... </ichiri:user>
    <google:map> ... </google:map>
</ichiri:root>

そして一つ前の例でi.xsdのようにフルパス指定でなく、グループ名の下にi.xsdを書くと、ローカルのi.xsdを使います。例えば、今開いているxmlが~/doc/dx/にある場合、~/doc/dx/i.xsdを確実に読んでくれます。(パーサーがすでに以前のi.xsdを読み込んでメモリに常駐している場合は常駐してる内容が使われます) Webからxmlをダウンロードしたら、そのダウンロードしたURLと同じところのi.xsdを読み込みます。

さらにさらに難解な仕様

  • 上記のxmlとするには、i.xsdにきちんと<ichiri:root>から</ichiri:root>までを定義せねばなりません。
  • tnsなど全てのnamespaceはxsdからxmlで異なっていても構いません。子xsdと親xsd間でも異なっていても構いません。
  • しかしNamespace name(又はNamespace URL)は完全一致でなければなりません。
  • しかもそれをxsdではimportでも同じNamespace nameを書かねばなりません。
  • さらにxmlではshcemaLocationを書く場所はxmlnsと同じ場所だったのが、xsdではimportの中にかかねばなりません。
  • 下の例のschemaLocationは、このi.xsdのロケーションからの相対パスになります。 https://google.comの右に書かれていますが、https://google.comは単なる識別子としてしか使われず、https://google.comに探しに行きません。 なので以下の場合g.xsdがi.xsdと同じ場所にない場合はエラーになります。
  • importを使うのはg.xsd内にtargetNamespace=”https://google.com”があり、このtnsのtargetNamespace=”https://dx.ichiri.biz/dx-platform”と異なるので同じロケーションにi.xsdとg.xsdがあったとしてもimportが必要です。
i.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://dx.ichiri.biz/dx-platform"
           xmlns:tns="https://dx.ichiri.biz/dx-platform"
           xmlns:google="https://google.com"
           elementFormDefault="qualified">

  <xs:import namespace="https://google.com" schemaLocation="g.xsd"/>

  <xs:complexType name="UserType">
    <xs:sequence>
      <xs:element name="id" type="xs:string"/>
      <xs:element name="name" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="user" type="tns:UserType"/>
        <xs:element ref="google:map"/> 
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>

まだまだありますひ孫xsdの場合

  • 孫xsdでgootle:mapを取り込んだelementを使う場合、孫xsdからずっと数珠つなぎで宣言し挙句の果xmlでは全てのxsdを指定しなければなりません。
  • しかし孫でも同じ宣言を書かなければなりません。
  • しかもi.xsdから取り込んでも孫から全てのタグ<>でネストしなければなりません。
  • しかしxsdのなかは数珠つなぎですが、refで取り込む<>ネスト数は同じですね。
  • targetNamespaceが=”https://dx.ichiri.biz/mago”と”https://dx.ichiri.biz/ko”と違う場合もimportが必要です。
  • 仕様は考えられないくらい馬鹿げてますが、使うためには従うしかないので頑張りましょう。 あまりに馬鹿げているあまり、皆混乱して習得を辞めてますが、そのおかげてあなたはxsd,xmlを習得すれば希少なトップレベル技術者になれます。

孫xsdにgoogle:mapを取り込んで数珠つなぎでi.xsdでxmlで表示した場合

i.xml
<?xml version="1.0" encoding="UTF-8"?>
<i:root 
    xmlns:i="https://dx.ichiri.biz/dx-platform"
    xmlns:ko="https://dx.ichiri.biz/ko"
    xmlns:mago="https://dx.ichiri.biz/mago"
    xmlns:google="https://google.com"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://dx.ichiri.biz/dx-platform i.xsd">
    
    <ko:ko>
        <mago:mago>
            <google:map>TOYONAKA_PIANO_HALL</google:map>
        </mago:mago>
    </ko:ko>
</i:root>

最初の孫xsd

mago.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://dx.ichiri.biz/mago"
           xmlns:google="https://google.com"
           elementFormDefault="qualified">

  <xs:import namespace="https://google.com" schemaLocation="g.xsd"/>

  <xs:element name="mago"> 
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="google:map"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

孫xsdを取り込む子xsd

ko.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://dx.ichiri.biz/ko"
           xmlns:mago="https://dx.ichiri.biz/mago"
           elementFormDefault="qualified">

  <xs:import namespace="https://dx.ichiri.biz/mago" schemaLocation="mago.xsd"/>

  <xs:element name="ko"> 
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="mago:mago"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

やっとi.xsd

i.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://dx.ichiri.biz/dx-platform"
           xmlns:ko="https://dx.ichiri.biz/ko"
           elementFormDefault="qualified">

  <xs:import namespace="https://dx.ichiri.biz/ko" schemaLocation="ko.xsd"/>

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="ko:ko"/> 
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

include

z.xsd内にtargetNamespace=”https://google.com”があり、このtnsのtargetNamespace=”https://dx.ichiri.biz/dx-platform”と異なるので同じロケーションにi.xsdとg.xsdがあったとしてもimportが必要です。

分割したxsdを取り込む場合importでなくinclude。 namespaceは取り込んでいるxsdと同じ。

i.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://dx.ichiri.biz"
           xmlns:tns="https://dx.ichiri.biz"
           elementFormDefault="qualified">
<xs:include schemaLocation="z.xsd"/>

タグに書くカテゴリー

さて定義部分はほぼ網羅したと思います。後は慣れですね。

3つあります。

  1. schema component
    • <xs:element …>や<xs:schema …>など
  2. Instructions
    • <xs:import …>や<xs:include …>など
  3. Annotations
    • <xs:documentation …>等

Schema component

Schema Component意味(本質)ここまでのカバー率
Schema Component Set(全体)全ての schema component の集合としてのスキーマ世界。10%
Element DeclarationXML要素の宣言。インスタンスXMLの中心。25%
Complex Type Definition構造(オブジェクト)を定義する型。40%
Simple Type Definitionプリミティブ型+制約を定義する型。50%
Model Group要素の並び・選択(sequence / choice / all)。60%
FacetsimpleType の制約(pattern, enumeration, min/max など)。70%
Attribute Declaration属性の宣言。75%
Attribute Group Definition属性の再利用ブロック。80%
Group Definition要素の再利用ブロック(名前付きモデルグループ)。85%
Identity-constraint Definitionkey / keyref / unique による一意性・参照制約。90%
Wildcardany / anyAttribute による拡張ポイント。92%
Notation Declaration非XMLデータ型の宣言。96%
Particle要素の出現ルール(回数・位置づけ)を表す概念。100%

Instructions

Instruction意味(本質)
import別の namespace のスキーマを読み込む指示。
他ドメイン・他組織のスキーマを参照するための入口。
include同一 namespace のスキーマをファイル分割して読み込む指示。
大規模スキーマの分割・整理に使う。
redefine既存スキーマのコンポーネントを再定義する指示。
強力だが衝突・混乱を生みやすく、原則非推奨。

Annotations

Annotation意味(本質)
annotationスキーマ内にメタ情報を埋め込むためのコンテナ。
documentation と appinfo を内包する。
documentation人間向けの説明文・仕様・注意事項を記述する領域。
仕様書とスキーマを一体化するために使う。
appinfo機械向けのメタ情報・運用ルール・ツール設定を埋め込む領域。
あなたの ichiri-schema の中核となる場所。

さていよいよここのcomponentです。 前提条件として、以下すべてのi.xsdは以下のxs:schemaで囲われている想定です。 elementFormDefault=”qualifiedなのでこのxsd内とこれを使うxmlでnamespaceを使わなければエラーになります。

i.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://dx.ichiri.biz"
           xmlns:tns="https://dx.ichiri.biz"
           elementFormDefault="qualified">
    <xs:element name="root">
              :
    </xs:element>
              :
       complexTypeなど型指定
              :
</xs:schema>

そして全てのxmlの例は以下のabc:rootに

i.xml
<abc:root xmlns:abc="https://dx.ichiri.biz" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="https://dx.ichiri.biz i.xsd">
</abc:root>

xs:element

xsdで<xs:element …>で記述したものだけがxmlのタグとして書けます。 要はxmlのタグの事がxs:elementなのでxs:elementが実体のことです。 xsdでxs:element以外はxmlとして実体のない条件/制約や型指定や属性を追加するものです。(xs:importなどの命令やxs:annnotationなどもありますが)

ここから下は以下のrootでnamespaceがichiriである場合とします。

ちなみにxs:を付けているのは、正式なhttp://www.w3.org/2001/XMLSchema”で定義されたxs:のelementであることを限定しています。xs:がなければ誰かが作った”element”という名前のタグかもしれません。 なので極力xs:を付けていきます。

  • 例1
    • xsdで決まっているelementなど書くときはxs:が付きます。 型のstringにもxs:が付きます。
    • i.xsdのなかでxs:elementにname=”location“と書くと、xmlのなかで<abc:location>のタグが書けます。
    • 前提条件とし上述しましたが、abcは、rootタグの中でi.xsdで定義したxs:elementはabc:を付けて書くよと宣言した事にしています。
i.xsd
<xs:element name="location" type="xs:string"/>
i.xml
<abc:location>osaka</abc:location>
  • 例2
    • xs:element内に子のxs:elementを書く時、xmlの仕様で仕方ないですが、xs:element直下にxs:elemnentを書くことを禁止しているので慣習としてcomplexTypeを使います。 
    • xs:complexType直下にもxs:elementを書けないのでxs:sequenceを使ってます。 まあxmlの慣習と思って諦めてください。
    • なのでこの様に書くと、xmlでは外側のタグにuserが入り、中のタグにnameが入ります。 それぞれi.xsdのnamespaceはabcとしているのでabc:が付きます。
i.xsd
<xs:element name="user">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>
i.xml
<abc:user>
  <abc:name>ichiri</abc:name>
</abc:user>
  • 例3
    • これは例2と同じですが、違いは予め個別のxs:element name=”name”を作っています。
    • そしてrefでそのxs:elementを参照しています。
    • なのでxmlとしては例2と同じです。
i.xsd
<xs:element name="location" type="xs:string"/>
<xs:element name="user">
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="tns:name"/> 
    </xs:sequence>
  </xs:complexType>
</xs:element>
i.xml
<abc:user>
  <abc:name>ichiri</abc:name>
</abc:user>
  • 例4
    • <xs:element>にはnameという属性があります。 しかしidはないので、<xs:attribute>を使って”id”という名前を付けます。 重複しない限り<xs:element>にいくつでも属性を追加できます。 xs:attributeはxs:elementだけに属性を追加できます。
    • なのでxmlのabc:userにはidを入れることが出来ます。
    • このidの型はtype=”xs:ID”で指定されているので文字列で小文字uから始まる数字(10進数)出ないといけません。
    • リスト化した時のid番号のように使われます。
i.xsd
<xs:element name="user">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
    </xs:sequence>
    <xs:attribute name="id" type="xs:ID" use="required"/>
  </xs:complexType>
</xs:element>
i.xml
<abc:user id="u001">
  <abc:name>ichiri</abc:name>
</abc:user>
  • 例5
    • 最初にidのフォーマットを作っています。 xs:simpleTypeは値が一つの場合です。 今回はxs:IDという値が1つのシンプルな型のフォーマットを正規表現で先頭にuがついて0~9の3桁というパターンでxmlに書かないとエラーになります。 それをxs:attributeのidのtypeに与えてます。
    • そして今回はuserの中にnameとageがセットになっています。 このuserのセットは最低1個、最大で5個xmlで書かなければなりません。 
    • xs:complexTypeとxs:sequenceはxs:elementと子xs:elementの間に入れなければならない慣習です。
    • 因みにabc:とnamespaceをつけるのは、xsdでxs:elementFormDefault=”qualified”としているとxsdでnamespaceを使わなければならないし、そのxsdを使ったxmlでもそのxsdようのxs:elemnetにはnamespaceを使わなければなりません。 ミスが無い様にelementFormDefault=”qualified”を使うべきで実際使っているのが90%以上なので、実質elementFormDefault=”qualified”が使われています。なので私のxmlの例ではnamespaceをabc:としているので全てにabc:を付けています。 よくxmlの例でnamespaceを付けてないのを見かけますが、個人利用レベルではいいですがビジネスの実用レベルでは使え無いと思ってます。なんせabc:nameとx:nameがあっても両方nameとnameになる可能性があります。両方単にnameだったらバインダーやパーサーは間違えて処理をしてしまいます。 バリデーターもエラーを見つけれません。
i.xsd
<xs:simpleType name="IdFormat">
  <xs:restriction base="xs:ID">
    <xs:pattern value="u[0-9]{3}"/> 
  </xs:restriction>
</xs:simpleType>

<xs:element name="user" minOccurs="1" maxOccurs="unbounded">
    <xs:complexType>
       <xs:sequence>
          <xs:element name="name" type="xs:string"/>
       <xs:element name="age" type="xs:int"/>
     </xs:sequence>
     <xs:attribute name="id" type="tns:IdFormat" use="required"/>
    </xs:complexType>
</xs:element>
i.xml
<abc:user id="u001">
   <abc:name>ichiri</abc:name>
   <abc:age>99</abc:age>
</abc:user>
<abc:user id="u025">
   <abc:name>tarou</abc:name>
   <abc:age>89</abc:age>
</abc:user>
<abc:user id="u999">
   <abc:name>hanako</abc:name>
   <abc:age>79</abc:age>
</abc:user>

  • 【例6】
    • しかし上記ではageで-50歳でも通ってしまいますなので0~199歳までとします。
    • xs:int(符号付き32ビット整数)にminを0でmaxを199としてAgeFormatという条件付き(xs:restriction)自作のxs:simpleTypeを作ります。
    • それをageのtypeに入れるとageは0~199以外を入れられるとエラーにすることができます。
    • 本来はxs:element name=”user”の前にxs:element name=”root”が必要で、最後も/xs:elementが必要です。 そしてelementの直下にはelementをおけないのでxs:complexTypeとxs:sequenceを挟まなければなりません。
i.xsd
<xs:simpleType name="AgeFormat">
    <xs:restriction base="xs:int">
      <xs:minInclusive value="0"/>
      <xs:maxInclusive value="199"/>
    </xs:restriction>
</xs:simpleType>

<xs:simpleType name="IdFormat">
  <xs:restriction base="xs:ID">
    <xs:pattern value="u[0-9]{3}"/> 
  </xs:restriction>
</xs:simpleType>


<xs:element name="user" minOccurs="1" maxOccurs="unbounded">
    <xs:complexType>
       <xs:sequence>
          <xs:element name="name" type="xs:string"/>
       <xs:element name="age" type="xs:AgeFormat"/>
     </xs:sequence>
     <xs:attribute name="id" type="tns:IdFormat" use="required"/>
    </xs:complexType>
</xs:element>
i.xml
<abc:user id="u001">
   <abc:name>ichiri</abc:name>
   <abc:age>99</abc:age>
</abc:user>
<abc:user id="u025">
   <abc:name>tarou</abc:name>
   <abc:age>89</abc:age>
</abc:user>
<abc:user id="u999">
   <abc:name>hanako</abc:name>
   <abc:age>79</abc:age>
</abc:user>

xs:complexType

  • これも全てのxsdで100%使われ超重要なので覚えましょう。
  • 簡単です。 xmlで1つ以上の値をセットにした型を作る時に使います。値を入れるというのは実体なのでxs:element1つでも入れる時は、xs:complexTypeを使います。
  • xsd の仕様上、xs:complexTypeの中には、「子xs:elementをどう並べるか」というルールを必ず1つ置かなければならなず、「1種類しかないから順序も何もない」と思っても、sequenceかchoice か allを入れる仕様になっているので 90%はxs:sequenceを使います。 選択型にする場合は8%くらいでxs:choiceをつかいます。 xs:sequenceは順番を守らなければなりません。 xs:allだと順番はどうでもいいという事で2%くらい使われます。 ここでは必要がない限りxs:sequenceを使います。
  • そしてxs:complexTypeはxs:elementの外で型定義をします
  • 今回はfullのxsdを例にします。 
    • いつもと違うのは大外はお決まりのxs:schemaでnamespaceが必須となるelementFormDefault=”qualified”を付けています。 お決まりのxsを使うためxmlns:xs=”http://www.w3.org/2001/XMLSchema”を書いています。そして今回作っているi.xsdは”https://dx.ichiri.biz”というグループで、”https://dx.ichiri.biz”グループはtnsというnamespaceを持っていると宣言しています。
    • そしてまたいつもと違うのは<xs:element name=”root”>があることです。 全てのxs:elementはこのrootの中に入っていなければなりません。 rootがxmlの全体です。<html>みたいなものです。
  • そしてxs:complexTypeはrootの外でないといけません。 rootの中は実体なるxs:elementを指定します。
  • rootの中にもxs:complexTypeがありますが、nameがない匿名型のxs:complexTypeはxs:elementとxs:elementの間の緩衝材として入ることが出来ます。 因みにxs:simpleTypeはxs:elementを持てないので緩衝材に使えません。 緩衝材としてxs:complexTypeとセットで使われるのは、90%の場合xs:sequecnceが使われますが、xs:choiceとかどちらか選択を使う場合で8%、xs:allが2%で使われるようです。 なのでxs:sequenceだけ覚えているのがいいですね。
  • rootの外で設定したxs:complexTypeは先程の例で作ったのと同じ方で作っています。 名前をUserTypeとしているので、root内のxs:elementのtypeに”tns:UserType”と入れてます。このtnsのnamespaceをもつi.xsd内で方にしたUserTypeはtns:UserTypeとしていするのです。 単にUserTypeと入れるとエラーになります。namespaceが必須ですし、どこの誰のUserTypeか分からないからです。
i.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://dx.ichiri.biz"
           xmlns:tns="https://dx.ichiri.biz"
           elementFormDefault="qualified">

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="user" type="tns:UserType" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <xs:complexType name="UserType">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="age" type="xs:int"/>
    </xs:sequence>
    <xs:attribute name="id" type="xs:ID" use="required"/>
  </xs:complexType>
</xs:schema>
i.xml
<abc:root xmlns:abc="https://dx.ichiri.biz" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="https://dx.ichiri.biz i.xsd">
   <abc:user id="u001">
      <abc:name>ichiri</abc:name>
      <abc:age>99</abc:age>
   </abc:user>
   <abc:user id="u025">
      <abc:name>tarou</abc:name>
      <abc:age>89</abc:age>
   </abc:user>
   <abc:user id="u999">
      <abc:name>hanako</abc:name>
      <abc:age>79</abc:age>
   </abc:user>
</abc:root>

  • 例2
    • これはすごい。<xs:element name=”root” type=”tns:RootType”/>とrootの中がない。 この場合は,/xs:element>でなく『/>』でselfcloseしています。 そしてtns:RootTypeのtns:からこのi.xsdのなkでRootType型を作っているんだなとわかります。
    • それはひとつ上のcomplexTypeにありますね。その中のxs:element userがtns:UserTypeで何回も繰り返し使える様になっています。 なのでrootの中に<user>を何個も書けるということですね。
    • tns:UserTypeはその上のxs:complexTypeにあり、そこにはxs:element nameとxs:element ageがありますね。そしてidをxs:complexType UserTypeに付けているので、xs:complexはxmlで記述できないのでxs:complexType UserTypeを受け継いだ、xmlに記述できるxs:element userにidを付けていることになります。
    • そしてageとidという値に対して、値は1つなのでxs:simpeTypexs:restriction base型で指定をしています。 これでxs:element rootに上記elementの例6と同じ事になります。
    • xsd記法ではこの様にsimpeTypeやcomplexTypeで先に型を作っておいてxs:elementにはめ込んでいくのが一般的な書き方です。 大規模開発では、xs:element(タグ名)と型(構造・制約)を切り離すことで、構造だけの修正が容易になるのです。
i.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://dx.ichiri.biz"
           xmlns:tns="https://dx.ichiri.biz"
           elementFormDefault="qualified">

   <xs:simpleType name="AgeFormat">
      <xs:restriction base="xs:int">
         <xs:minInclusive value="0"/>
         <xs:maxInclusive value="199"/>
      </xs:restriction>
   </xs:simpleType>

   <xs:simpleType name="IdFormat">
      <xs:restriction base="xs:ID">
         <xs:pattern value="u[0-9]{3}"/>
      </xs:restriction>
   </xs:simpleType>

   <xs:complexType name="UserType">
      <xs:sequence>
         <xs:element name="name" type="xs:string"/>
         <xs:element name="age" type="tns:AgeFormat"/>
       </xs:sequence>
       <xs:attribute name="id" type="tns:IdFormat" use="required"/>
   </xs:complexType>

   <xs:complexType name="RootType">
      <xs:sequence>
         <xs:element name="user" type="tns:UserType" maxOccurs="unbounded"/>
      </xs:sequence>
   </xs:complexType>

   <xs:element name="root" type="tns:RootType"/>
</xs:schema>
i.xml
<abc:root xmlns:abc="https://dx.ichiri.biz" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="https://dx.ichiri.biz i.xsd">
   <abc:user id="u001">
      <abc:name>ichiri</abc:name>
      <abc:age>99</abc:age>
   </abc:user>
   <abc:user id="u025">
      <abc:name>tarou</abc:name>
      <abc:age>89</abc:age>
   </abc:user>
   <abc:user id="u999">
      <abc:name>hanako</abc:name>
      <abc:age>79</abc:age>
   </abc:user>
</abc:root>

因みにxsdとxmlを簡単にテストするサイトです。スキーマ定義の<xs:schema …>から完全なxsdとルート要素(ドキュメント要素)の<abc:root …>などのも全て含む必要があります。

Free Online XML Validator Against XSD Schema - FreeFormatter.com
This free online XML validator lets you validate your XML files against an XSD (XML Schema)

extension

  • 多くの人がextensionで挫折しますがここをクリアしたら大分スッキリする。 しかもこれも混乱させるだけのXMLの馬鹿な仕様ですが実は簡単です。 extensionと言うと拡張となりますが、拡張出来ません。 拡張とは後から追加する意味ですが、後から全く追加出来ません。 本当はextensionでなくこれは埋め込むとして考えたらスッキリします。 
  • 要は、予め作っているcomplexTypeを別のcomlexTypeに再利用する時だけ使います。
  • 先程はtype=”tns: …”を使ってxs:elementやxs:complexTypeに入れていますが、xs:extensionはtypeで参照するのではなく、『xs:extensionと書いたところにそのbaseを入れるんだ。』と宣言しています。こっちのほうが直感的に場所も指定しやすくわかりやすいと思います。
  • 以下の例ではAddressTypeというcomplexTypeを作っておき、その下でInternationalAddressTypeに既に作ってあるAddressTypeを再利用しています。 そしてそのInternationalAddressTypeを使用してMY_Address elementを作ります。
  • するとXML内MY_Address elementにAddressTyoeのcityとstreetを使えます。
i.xsd
<xs:complexType name="AddressType">
  <xs:sequence>
    <xs:element name="city" type="xs:string"/>
    <xs:element name="street" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="InternationalAddressType">
  <xs:complexContent>
    <xs:extension base="tns:AddressType">
      <xs:sequence>
        <xs:element name="country" type="xs:string"/>
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>

<xs:element name="MY_Address" type="tns:InternationalAddressType"/>
i.xml
<abc:MY_Address>
  <abc:city>Toyonaka</abc:city>
  <abc:street>Senri</abc:street>
  <abc:country>Japan</abc:country>
</abc:MY_Address>
  • 上記はextensionでxs:elementを埋め込みました。
  • ここではageのxs:elementに単位(unit)をextensionで追加します。 
  • 前の例では、xs:attributeでuserのxs:elementにidを追加しました。 しかし馬鹿げたxmlの仕様で、xs:int、xs:string、xs:dateなどの単純な値をもつxs:elementにはxs:attributeを直接使えないのです。それはもう単純でなくなるからです。
  • ageには単純なAgeWithUnitTypeでbaseは単純なあたいxs:intにするとしています。 ageのtypeはtns:AgeWithUnitTypeとしていますが、直接xs:attributeをする時は、type=”xs:int”ということになります。 もしここにxs:complexTypeとxs:sequenceを入れるとxs:attributeは書けます。 しかしageの値として99などを記入できなくなります。 これはxs:complexTypeとxs:sequenceを入れる事は、子のxs:elementがある事となり、ageの値でなく、子xs:elementの値を書けなくなるためです。 よって単純な値のageのxs:elementに属性を追加する場合はxs:simpleContent(単純な中身)の中でxs:extensionを使う以外方法はないのです。 逆に言えば、xs:elementに直接xs:attributeで属性をもたせるならxs:complexTypeで定義すればよいのです。
i.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://dx.ichiri.biz"
           xmlns:tns="https://dx.ichiri.biz"
           elementFormDefault="qualified">

  <xs:complexType name="AgeWithUnitType">
    <xs:simpleContent>
      <xs:extension base="xs:int">
        <xs:attribute name="unit" type="xs:string" use="required"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

  <xs:complexType name="UserType">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="age" type="tns:AgeWithUnitType"/> 
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="AdminType">
    <xs:complexContent>
      <xs:extension base="tns:UserType">
        <xs:sequence>
          <xs:element name="role" type="xs:string"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="user" type="tns:UserType" maxOccurs="unbounded"/>
        <xs:element name="admin" type="tns:AdminType" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>
i.xml
<abc:root xmlns:abc="https://dx.ichiri.biz" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="https://dx.ichiri.biz i.xsd">
  <abc:user>
    <abc:name>ichiri</abc:name>
    <abc:age unit="year">99</abc:age> 
  </abc:user>
  <abc:admin>
    <abc:name>admin_user</abc:name>
    <abc:age unit="month">120</abc:age> 
    <abc:role>manager</abc:role>
  </abc:admin>
</abc:root>

これでextensionは完璧です。 これ以上WordPressで書くと遅くなるので、ここでその2で続きを書きます。

コメント