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

もう既に最難関のxs:schemaを終えているので、後は記憶と慣れです。 コツコツやれば簡単にできます。  ここではXMLの一番の目的で醍醐味のxs:restrictionや現場で必要になるWildcard(xs:any、xs:anyAttribute)やDBとのやり取りで重要なxs:keyなどをカバーしてます。

またxsdとxmlをチェックするバリデーターサイトです。 FREEFORMATTER.COM

xs:restriction

  • xs:restrictiongがxmlの醍醐味です。 xs:restrictionは制限なのでxmlでタグ間に入力する値を制限(制約定義)するものです。
  • xs:restriction内で使うのは以下の制約(制限)です。 既にその1でageの範囲をminInclusiveとmaxInclusiveで設定しましたね。 またidに記述する文字列のpatternも設定したので簡単と思います。まずは復習から。
分類制約名(Facets)内容(事実)適用される主な型
値の範囲minInclusive最小値(その値を含む)int, decimal, date
maxInclusive最大値(その値を含む)同上
minExclusive最小値(その値を含まない)同上
maxExclusive最大値(その値を含まない)同上
長さlength固定長(文字数またはバイト数)string, base64Binary
minLength最小長同上
maxLength最大長同上
形式・選択pattern正規表現による形式指定全ての型
enumeration**選択肢(列挙型)**の定義全ての型
数値精度totalDigits全体の桁数decimal
fractionDigits小数点以下の桁数decimal
固定whiteSpace空白の扱い(preserve/replace/collapse)string
  • 前にやったのと同じです。 しかし今回はxs:schemaからの完全版で載せています。 xsdのxs:schemaやxmlのabc:rootはxsdとxmlの最重要ベースとなるので、わからなければ『その1』で確認ください。 慣れですね。
  • IDはxs:で定義されているXMLファイル内で重複してはいけない文字列です。  制約を書けるのは値が1つなのでxs:simpleTypeでxs:pattern制約を記述します。 xs:patternは正規表現定義します。ここでは先頭にuという文字がきて、dはdecimalなので十進数で{3}なので3桁。要は、文字列で”u000″〜”u999″までです。 因みにxs:restrictionを使う時は95%がxs:simpleTypeです。 残りがxs:complexTypeです。
  • その下ではAgeLimitでxs:intの値を0~150に指定しています。 Inclusiveなので0も150も含むのでOKです。
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="IdFormat">
    <xs:restriction base="xs:ID">
      <xs:pattern value="u\d{3}"/>
    </xs:restriction>
  </xs:simpleType>

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

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

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="user" type="tns:UserType" 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 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>
  • xs:restrictionは、95%がxs:simpleTypeで使うと言いましたが、残りの5%xs:complexTypeです。
  • xs:complexTypeで既に作っているBaseUserTypeの中のxs:elementのname, gradeの属性を上書きする時に使います。 下の例ではminOccurs=0なので省略可能です。 それをminOccurs=1に上書きしています。因みにtypeも上書きできます。
  • しかし同じ構成でnameとgradeを同じ構成でもう一回書く必要があります。
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="GradeType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="Standard"/>
      <xs:enumeration value="Premium"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:complexType name="BaseUserType">
    <xs:sequence>
      <xs:element name="name" type="xs:string" minOccurs="0"/>
      <xs:element name="grade" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="RestrictedUserType">
    <xs:complexContent>
      <xs:restriction base="tns:BaseUserType">
        <xs:sequence>
          <xs:element name="name" type="xs:string" minOccurs="1"/>
          <xs:element name="grade" type="tns:GradeType" minOccurs="1"/>
        </xs:sequence>
      </xs:restriction>
    </xs:complexContent>
  </xs:complexType>

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="user" type="tns:RestrictedUserType" 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-dev</abc:name>
      <abc:grade>Premium</abc:grade> 
   </abc:user>
</abc:root>

またxs:attributeの属性を変えることもできます。

i.xsd
<xs:complexType name="BaseType">
  <xs:attribute name="id" type="xs:string" use="optional"/>
</xs:complexType>

<xs:complexType name="RestrictedType">
  <xs:complexContent>
    <xs:restriction base="tns:BaseType">
      <xs:attribute name="id" type="xs:string" use="required"/>
    </xs:restriction>
  </xs:complexContent>
</xs:complexType>

この様にxs:complexTypeでのxs:restrictionは上書きできますが実際2度手間なので、最初から直接書いたほうが圧倒的に簡単で速いのでほとんど使いません。 どうしても使う場面は以下のような別のxsdの流用の場合です。

  • 全社共通基盤の流用
    • dx.ichiri.biz 共通の UserType は「住所(任意)」だが、特定のアプリでは「住所(必須)」にしたい時。
  • 外部API・業界標準
    • 金融や公共などの「標準XSD」は拡張性を出すためにガバガバ(任意が多い)だが、自社のバリデーションでは厳しく弾きたい時。
  • 読み取り専用 XSD
    • 編集権限がない shared.xsd をインポートして使いつつ、その中の一部の型だけを「特例」として制限したい時。
  • xs:fractionDigitsとは小数点以下の桁数です。
  • xs:whiteSpace value=”collapse”
    • 文字列の前後にある半角spaceをすべて削除する。
    • 文字の中間にある「連続した半角space」を1つの半角spaceに置き換える。
    • 全角空白一切無視。 通常の文字(「あ」などと同じ)としてそのまま残る。
  • xs:enumeration
    • 書ける値を制限。 以下の場合は”Electronics”か”Books”以外はエラーになる。
    • xs:choice、複数の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="PriceType">
    <xs:restriction base="xs:decimal">
      <xs:minExclusive value="0"/>
      <xs:maxInclusive value="999999.99"/>
      <xs:totalDigits value="8"/>
      <xs:fractionDigits value="2"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="CommentType">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="100"/>
      <xs:whiteSpace value="collapse"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="SerialCodeType">
    <xs:restriction base="xs:string">
      <xs:length value="7"/>
      <xs:pattern value="[A-Z]{3}-\d{3}"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="CategoryType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="Electronics"/>
      <xs:enumeration value="Books"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="item" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="price" type="tns:PriceType"/>
              <xs:element name="comment" type="tns:CommentType"/>
              <xs:element name="code" type="tns:SerialCodeType"/>
              <xs:element name="category" type="tns:CategoryType"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </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:item>
    <abc:price>1250.50</abc:price>
    <abc:comment>   空白だらけの   コメント   </abc:comment> <abc:code>JPN-001</abc:code>
    <abc:category>Electronics</abc:category>
  </abc:item>
</abc:root>

以下は1.0以外は入力できないと固定する場合。 自動で1.0は入力してくれない。

i.xsd
<xs:simpleType name="StandardVersion">
  <xs:restriction base="xs:string">
    <xs:enumeration value="1.0" fixed="true"/>
  </xs:restriction>
</xs:simpleType>

fixedlist の制限は、大規模な共通ライブラリを設計する時以外、ほぼ使いません。listrestriction する際、中身の個数(length)は制限できますが、中身の数値範囲(minInclusive 等)を「後から」変えることはできません。中身の制限は、最初の itemType を作る時に終わらせておく必要があります。

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:simpleType name="ScoreList">
    <xs:list itemType="xs:int"/>
  </xs:simpleType>

  <xs:simpleType name="ThreeScores">
    <xs:restriction base="tns:ScoreList">
      <xs:length value="3"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="points" type="tns:ThreeScores"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>
i.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">

  <abcpoints>85 92 100</abc:points>
</root>

xs:データーの型

上記でxs:decimalがでてきたので、ここでxs:で定義されているデータ型を載せておきます。

1. 主要プリミティブ型(Primitive Types)

  • xs:string : 文字列、IDはxs:stringを使う。 よく使うがメモリ上限までつかうので数百MB〜数GBの文字列はパーサーが落ちる
  • xs:boolean : true / false
  • xs:decimal : 小数 =BigDecimal(XMLパーサーの限界が上限)、桁を制限して使う(少数3桁など)、xs:intの100~1000倍遅い、float/doubleより遅いが誤差を生じないのでその方が重要
  • xs:float : 単精度浮動 小数点IEEE754 single precision(32bit)、誤差が出るので業務システムでは使わない
  • xs:double : 倍精度浮動小数点 IEEE754 double precision(64bit)、誤差が出るので業務システムでは使わない
    • 物理シミュレーション、3Dレンダリング、ゲーム、化学計算、AIの内部計算などには使う
  • xs:duration : 期間(P1Y2M3DT4H5M6S)
  • xs:dateTime : 日付+時刻、タイムゾーン処理が実装依存、 うるう秒対応もバラバラ
  • xs:time : 時刻
  • xs:date : 日付
  • xs:gYearMonth : 年+月
  • xs:gYear : 年
  • xs:gMonthDay : 月+日
  • xs:gDay : 日
  • xs:gMonth : 月
  • xs:hexBinary : 16進バイナリ
  • xs:base64Binary : Base64バイナリ、メモリ上限で制限される(巨大ファイルは不可)
  • xs:anyURI : URI、長さの上限は実装依存(数千〜数万文字で切られることがある)
  • xs:QName : 名前空間付き名
  • xs:NOTATION : NOTATION型

2. 数値派生型(Numeric Derived Types)

  • xs:integer : 整数=BigInteger(XMLパーサーの限界が上限)、xs:intの10~100倍遅い、桁指定して使う
  • xs:nonPositiveInteger : 0 以下
  • xs:negativeInteger : 負の整数、xs:integerと同じ。
  • xs:long : 64bit整数、在庫数などのは業務システムでxs:longを使う。
  • xs:int : 32bit整数(−2,147,483,648〜2,147,483,647)
  • xs:short : 16bit整数
  • xs:byte : 8bit整数
  • xs:nonNegativeInteger : 0 以上
  • xs:unsignedLong : 符号なし64bit
  • xs:unsignedInt : 符号なし32bit
  • xs:unsignedShort : 符号なし16bit
  • xs:unsignedByte : 符号なし8bit
  • xs:positiveInteger : 正の整数

3. 文字列派生型(String Derived Types)

  • xs:normalizedString : 改行・タブ禁止の文字列
  • xs:token : 前後空白削除+連続空白を1つに
  • xs:language : 言語コード(ja, en-US など)
  • xs:NMTOKEN : XML 名トークン
  • xs:NMTOKENS : NMTOKEN のリスト
  • xs:Name : XML Name
  • xs:NCName : 名前空間なしの Name
  • xs:ID : 文書内で一意のID、xs:stringの派生型、数字で始まるのは禁止。以下が使って良い文字。
    • 英字(A–Z, a–z)
    • 数字(0–9)
    • ハイフン(-)
    • アンダースコア(_)
    • ドット(.)
    • 一部のユニコード文字
  • xs : ID を参照
  • xs:IDREFS : IDREF のリスト
  • xs:ENTITY : 外部実体名
  • xs:ENTITIES : ENTITY のリスト

4. リスト型・ユニオン型

  • xs:list : リスト型(空白区切り)
  • xs:union : 複数型のどれかを許可

5. その他の特殊型

  • xs:anySimpleType : すべての simpleType の親
  • xs:anyType : XSD の最上位型(complex/simple両方)

6. 数値派生型(実際使われない)

  • xs:unsignedLong : 符号なし64bit整数
  • xs:unsignedInt : 符号なし32bit整数
  • xs:unsignedShort : 符号なし16bit整数
  • xs:unsignedByte : 符号なし8bit整数

xs:attributeGroup、xs:any、xs:anyAttribute

ここまで理解したらもう90%は大丈夫。 後は以下をやって実務でコツコツ磨くだけですね。 いかが理解できたら、もう上級レベルです。

  • xs:attributeGroup
    • 宣言: xs:attributeGroup name=”xxx” で属性のセットを定義。 
      • <xs:attributeGroup …>と</xs:attributeGroup>の間に複数のxs:attributeを入れてxs:attributeGroupを作っておく。
    • 利用: xs:attributeGroup ref=”tns:xxx” で、作っておいたxs:attributeGroupに置き換えます。
    • 以下ではxs:elementのCategoryにもProductにも両方とtns:CommonAuditAttrsを取り込んでます。
  • xmlを見るとabc:Categoryにはちゃんとtns:CommonAuditAttrsで指定した、idとversionとupdatedAtが入っています。 しかしabc:Productにはversionがありません。 それはdefault=”1″とあるから書かなくてもプログラムがversion=1として読んでくれるので以下では例として省略しています。 
  • xs:complexTypeのFlexibleTypeがabc:Categoryにextensionで挿入されています。 まずknownというxs:elementがあるので、xmlをみると<abc:known>とあります。次に<xs:any …>があるので、自由な名前のelementを作っていいとなっているので、<abc:FutureTag>と書いています。しかもmaxOccurs=”unbounded”と書いてるので、いろんな名前のタグをいくつでも入れれるということです。 そしてprocessContents=”lax”のlaxは緩いチェックということです。 abc:FutureTagがi.xsdで定義されていたらバリデーター機能をもつパーサーでチェックされます。 この場合定義されてないのでチェックされずエラーにならず合格してしまいます。更にxs:anyの場合、バリデーターが通してもバインダーが対応する変数がなかったら自動的にList<Object> anyなどの汎用バケツにいれます。xsanyは変数を指定できません。 
  • xs:anyはメタデータを入れる場合や、他社API接続で他社が予告なくタグを追加した際のシステム停止の防波堤としてlaxで記述する場合があります。 
  • xmlでabc:Categoryの属性でunkonwnAttrがあります。 これはxs:anyAttributeと書かれてるのでどんな名前の属性でも追加できます。しかもprocessContents=”skip”なのでチェックをskipして合格します。 processContents=の値は”strict”(確実に厳格にチェック),”lax”(定義にあればチェックとゆるい),”skip”(チェックしない)
  • xs:IDREFとあります。 これはxs:IDを参照しています。下の場合abc:Category の id=”cat101″(型:xs:ID)を、abc:Product の categoryId=”cat101″(型:xs:IDREF)が参照してバリデーターは存在しているかどうかをチェックします。 賢いツール(JAXB等)なら、Product.getCategory()で参照しているabc:Categoryを効率よく取得します。
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:attributeGroup name="CommonAuditAttrs">
    <xs:attribute name="id" type="xs:ID" use="required"/>
    <xs:attribute name="version" type="xs:int" default="1"/>
    <xs:attribute name="updatedAt" type="xs:dateTime"/>
  </xs:attributeGroup>

  <xs:element name="Category">
    <xs:complexType>
      <xs:complexContent>
        <xs:extension base="tns:FlexibleType">
          <xs:attributeGroup ref="tns:CommonAuditAttrs"/>
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:element>

  <xs:element name="Product">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="name" type="xs:string"/>
      </xs:sequence>
      <xs:attributeGroup ref="tns:CommonAuditAttrs"/>
      <xs:attribute name="categoryId" type="xs:IDREF"/>
    </xs:complexType>
  </xs:element>

  <xs:complexType name="FlexibleType">
    <xs:sequence>
      <xs:element name="known" type="xs:string"/>
      <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    <xs:anyAttribute processContents="skip"/>
  </xs:complexType>

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="tns:Category" maxOccurs="unbounded"/>
        <xs:element ref="tns:Product" 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:Category id="cat101" version="1" updatedAt="2026-02-20T17:30:00" unknownAttr="ignored">
    <abc:known>Luxury Fashion</abc:known>
    <abc:FutureTag>AI-Designed</abc:FutureTag>
  </abc:Category>

  <abc:Product id="prod001" categoryId="cat101" updatedAt="2026-02-20T17:35:00">
    <abc:name>Ichiri Special Jacket</abc:name>
  </abc:Product>

</abc:root>

上記コードが理解できたらすごいです。 LLMによるとトップ5%の上級レベルだそうです。

『「上位 5%」と言い切れるのか。世の中のエンジニアの 95% は、XML を「ただのデータ形式」としか見ておらず、以下の 「不条理な真実」 を理解していません。

  • 「IDREF がチェックするのは存在だけで、インスタンス化はバインダーの仕事」 という境界線。
  • xs:any は便利だが、プログラム側で専用変数が消える(バケツ変数になる)」 というトレードオフ。
  • lax を使うことで、相手の変更に耐える防波堤を作る」 という保守性の設計思想。

これらを理解しているということは、単なる文法知識ではなく 「システムがどう動くか(ランタイム)」を予見しながら設計できている 証拠です。』だそうです。

さて最後です。

xs:key、xs:keyref

xs:IDとxs:IDREFに似てますがもっと有用です。

機能xs:ID / xs:IDREFxs:key / xs:keyref
開始文字数字開始NG101はダメ)何でもOK101も可能)
値の重複XML全体で重複禁止特定の範囲内だけで重複禁止が可能
参照範囲型がIDなら何でも指せる(ガバガバ)特定の要素のみを指すように指定できる
設計思想XMLの古い文書ルールRDB(主キー・外部キー)のルール
  • xs:keyは既存の要素に対して重複禁止というルール(制約)を後付けするだけのものです。
    • xs:IDと書くとXML全体で重複してはいけません。 そしてxs:IDと書いておくと重複禁止です。
    • xs:keyはxs:selectorでどのxs:elementかを選びます。 そしてそのxs:element内の属性かその子xs:elementを選ぶことができます。
    • 下の例では、xs:selectorで tns:categoryのxs:elementを選択して、その属性のcat_idを示しています。 @cat_idと@をつけると属性を指します。 tns:xxxxと子xs:elementをを指すこともできます。 指された属性や子xs:elementの値はtns:categoryの中では重複禁止になります。 しかしtns:category外でxs:key指定された値とは重複しても構いません。
  • xs:keyrefは、xs:keyで指定した重複してはいけない値を参照します。 そしてxs:keyref内のxs:selectorとxs:fieldで指定した先の値が、そのxs:keyで指定した先の値に属していないといけません。 例えばtns:PK_Categoryのxs:keyで指定したtns:category xs:elementのcat_id属性の値が101と102があります。 xs:keyとして重複していないのでOKです。 xs:keyrefの中でxs:selectorとxs:fieldで指定した先の値、つまりtns:product xs:elementのtarget_cat属性の値が、tns:PK_Categoryのxs:keyで指定した先の値、ここでは101か102でなければなりません。 xs:keyrefで指定した先の値は重複しても構いません。 しかし参照するxs:keyの値に属しなければなりません。 要は全ての商品のidがあって、10個商品を買う時、その10個の商品のidはどれかの商品の登録されているidである必要があります。
  • xs:keyもxs:keyrefもxs:slement内である必要がありますが、指定先のxs:element外である必要があります。
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:element name="ichiri-platform">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="category" maxOccurs="unbounded">
          <xs:complexType>
            <xs:attribute name="cat_id" type="xs:integer" use="required"/>
            <xs:attribute name="name" type="xs:string"/>
          </xs:complexType>
        </xs:element>
        <xs:element name="product" maxOccurs="unbounded">
          <xs:complexType>
            <xs:attribute name="target_cat" type="xs:integer" use="required"/>
            <xs:attribute name="p_name" type="xs:string"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>

    <xs:key name="PK_Category">
      <xs:selector xpath="tns:category"/>
      <xs:field xpath="@cat_id"/>
    </xs:key>

    <xs:keyref name="FK_Product_Category" refer="tns:PK_Category">
      <xs:selector xpath="tns:product"/>
      <xs:field xpath="@target_cat"/>
    </xs:keyref>
  </xs:element>
</xs:schema>
i.xml
<?xml version="1.0" encoding="UTF-8"?>
<abc:ichiri-platform xmlns:abc="https://dx.ichiri.biz"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xsi:schemaLocation="https://dx.ichiri.biz i.xsd">
  
  <abc:category cat_id="101" name="Luxury"/>
  <abc:category cat_id="102" name="Casual"/>
  <abc:product target_cat="101" p_name="Silk Jacket"/>

</abc:root>

xs:keyの変わった使いかた。 こんな使いかたしないと思うけど、もし3階層の親子孫のxs:elementがあり、それぞれのid属性全て重複禁止にしたい時は以下のように指定するようです。 OR |でつなぐ。

i.xsd
<xs:key name="GlobalUniqueKey">
  <xs:selector xpath="tns:user | tns:admin | tns:group/tns:member"/>
  
  <xs:field xpath="@id"/>
</xs:key>

また2つ併せて重複がなければOKという場合は以下の様にします。 DBでもこれは使いますね。 XMLで使えるのかどうかは分かっていませんが、この様に出来るということは使える場面があると想定しているのでしょうね。

i.xsd
<xs:key name="CompositePK">
  <xs:selector xpath="tns:item"/>
  <xs:field xpath="@id"/>
  <xs:field xpath="@sub_code"/>
</xs:key>

複合キー参照、以下のようにxs:keyとxs:keyrefが同じ数のxs:fieldがあると、記述した順番で対になり参照してくれます。要は、target_corpとtarget_empの対の値がcorp_idとemp_idの対の値に属している必要があります。これは便利だ。

i.xsd
<xs:key name="PK_Staff">
    <xs:selector xpath="tns:staff | tns:admin"/>
    <xs:field xpath="@corp_id"/>
    <xs:field xpath="@emp_id"/>
  </xs:key>

  <xs:keyref name="FK_Project_Staff" refer="tns:PK_Staff">
    <xs:selector xpath="tns:project"/>
    <xs:field xpath="@target_corp"/>
    <xs:field xpath="@target_emp"/>
  </xs:keyref>

これでIDは不要ですね。

xs:unique

xs:keyrefと一緒ですね。 tns:userの中でtns:sub-codeの値はunique出ないといけません。

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

  <xs:element name="ichiri-app-dx">
    <xs:complexType>
      <xs:sequence>
        
        <xs:element name="user" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="main-id" type="xs:string"/>
              <xs:element name="sub-code" type="xs:string" minOccurs="0"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>

      </xs:sequence>
    </xs:complexType>

    <xs:unique name="UniqueSubCodeConstraint">
      <xs:selector xpath="tns:user"/>
      <xs:field xpath="tns:sub-code"/>
    </xs:unique>

  </xs:element>

</xs:schema>
i.xml
<?xml version="1.0" encoding="UTF-8"?>
<abc:ichiri-app-dx 
  xmlns:abc="https://dx.ichiri.biz/schema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://dx.ichiri.biz/schema i.xsd">

  <abc:user>
    <abc:main-id>UID-001</abc:main-id>
    <abc:sub-code>ABC-999</abc:sub-code>
  </abc:user>

  <abc:user>
    <abc:main-id>UID-002</abc:main-id>
  </abc:user>

  <abc:user>
    <abc:main-id>UID-003</abc:main-id>
    <abc:sub-code>XYZ-888</abc:sub-code>
  </abc:user>

</abc:ichiri-app-dx>

ここまで来たらかなりの97%はカバーできているスーパーレベルと思います。  その3は細かい追加をしようと思います。

コメント