CDuceはXMLスキーマ勧告(入門、構造、データ型)を部分的にサポートしている。CDuceの機能を用いて、リーフが整数、日付、バイナリデータなどのような型付けされた値であるXML文書を扱うことができる。
CDuceのXMLスキーマサポートでは、次の機能が実装されている。
このマニュアルページでは、CDuceでこれらの機能を使う方法を説明し、例で使われている文書の全ては、マニュアルのXMLスキーマのサンプル文書の項で利用可能である。
注意: XMLスキーマのサポートは、現在のところ分割コンパイルと相性が良くない。XMLスキーマを使うCDuceのユニットscript.cdがコンパイルされると、結果となるscript.cdoのオブジェクトはXMLスキーマを名前で参照する。つまり、ユニットが実行されると、XMLスキーマはまだ同じディレクトリで利用できなければならず、かつコンパイルされてから変更がなされてはならない。
XMLスキーマ文書は、4種類の異なるコンポーネントを定義することができ、そのそれぞれをCDuceにインポートし、CDuceの型として使うことができる。
#PCDATAの改良版と考えると良い。XMLスキーマは定義済み単純型と、新しい単純型を定義する手段を提供する。後者は、XML要素の内容モデル及び属性を制約するのに使うことができる。XMLスキーマの複合型は、DTDの要素定義より厳密に表現力が高い。属性宣言は、現在のところCDuceの型を生成せず、それ自体を評価に用いることはできない。
XMLスキーマコンポーネントをCDuceにインポートするためには、まず最初にCDuceにXMLスキーマ文書をインポートするように指示する必要がある。スキーマキーワードを用いて、大文字で始まる識別子をローカルのスキーマ文書に束縛することで、これを行うことができる。
# schema Mails = "tests/schema/mails.xsd";; Registering schema type: attachmentType Registering schema type: mimeTopLevelType Registering schema type: mailsType Registering schema type: mailType Registering schema type: bodyType Registering schema type: envelopeType Registering schema element: header Registering schema element: Date Registering schema element: mails Registering schema attribute group: mimeTypeAttributes Registering schema model group: attachmentContent
上の宣言は、スキーマ文書mails.xsdの中に含まれる全てのスキーマコンポーネントをCDuceの型としてインポートする(しようとする)。ドット演算子を用いて参照することができる。例えば、S.mails。
XMLスキーマでは、コンポーネント名に曖昧さを許している。CDuceでは、要素、型、モデルグループ、属性グループの順序でスキーマコンポーネントを解決することを選択した。
スキーマコンポーネントの参照の結果は、通常のCDuceの型となり、関数定義、パターンマッチなどで通常通りに使うことができる。
let is_valid_mail (Any -> Bool) | Mails.mailType -> `true | _ -> `false
正当性に関する備考: XMLスキーマ文書をパースする際、CDuceは、文書がXMLスキーマ勧告に対して正当であると仮定する。少なくとも、スキーマに対するXMLスキーマに対して妥当であることが要求される。CDuceにインポートする前に正当性を検査することを推奨する。そうしないと、奇妙な振る舞いが予想される。
トップレベル命令#envはスキーマをサポートしており、現在定義されているスキーマを列挙する。
トップレベル命令#print_typeもスキーマをサポートしており、スキーマコンポーネントに対応する型を印字するのに使うことができる。
# #print_type Mails.bodyType;; [ Char* ]
詳しくは、マニュアルのトップレベル命令の項を見ること。
| XMLスキーマの定義済みの型 | CDuceの型 |
|---|---|
duration、dateTime、time、date、gYear、gMonth、… | 次のフィールドの幾つかを持つ(スキーマ型による)閉じたレコード型。year、month、day、hour、minute、second、timezone |
boolean | Bool |
anySimpleType、string、base64Binary、hexBinary、anyURI | String |
integer | Int |
nonPositiveInteger、negativeInteger、nonNegativeInteger、positiveInteger、long、int、short、byte | 適切な制限付きの整数 |
string、normalizedString、及びstringを制限して(直接的、間接的に)導出された他の型 | String |
NMTOKENS、IDREFS、ENTITIES | [String*] |
decimal、float、double | Float |
(正しくサポートされていない)decimal、float、double、NOTATION、QName | String |
単純型の宣言は、XMLスキーマ導出規則にしたがって構築される。
XMLスキーマの複合型宣言は、どんなタグでもいいが、属性及び内容は元の複合型にしたがって妥当であるようにXML要素を表すCDuceの型にマップされる。
例として、次のXMLスキーマ複合型(mails.xsdで定義されている同形envelopeTypeの簡略化版)、
<xsd:complexType name="envelopeType"> <xsd:sequence> <xsd:element name="From" type="xsd:string"/> <xsd:element name="To" type="xsd:string"/> <xsd:element name="Date" type="xsd:dateTime"/> <xsd:element name="Subject" type="xsd:string"/> </xsd:sequence> </xsd:complexType>
は、型StringのFrom属性と4つの子供を持っていなければならないCDuceのXML型にマップされる。Dateの子供は、dateTimeスキーマ型で表されるレコードを含むXML要素でなければならない
# #print_type Mails.envelopeType;;
<(Any)>[
<From>String
<To>String
<Date>{
positive = Bool;
year = Int; month = Int; day = Int;
hour = Int; minute = Int; second = Int;
timezone =? { positive = Bool; hour = Int; minute = Int }
}
<Subject}>String
]
XMLスキーマ要素の宣言により、XML要素を複合型又は単純型に束縛することができる。前者では、規約は複合型の規約で見たものとほとんど同じになる。唯一の違いは、要素のタグが、前のはAny型であったのだが、今度はXML要素の名前と一致しなければならないことである。
後者(単純型の内容を持った要素)では、対応するCDuceの型は要素型で、そのタグはスキーマ要素宣言のXML要素の名前と一致しなければならず、内容の型は、要素宣言で提供された単純型をCDuceに翻訳したものである。
例えば、次のXMLスキーマ要素(mails.xsdで定義されている同形要素に対応する)、
<xsd:element name="header">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute ref="name" use="required" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
は次のCDuceの型に翻訳される。
# #print_type Mails.header;; <header name = String>String
(上の例で気付くように、)要素の内容の型は、XMLスキーマ型を翻訳したものがそれ自体シーケンスでなければ、シーケンスとはならない。要素の内容がシーケンスでなく、単一のレコードとなる次と比較すると良い。
# #print_type Mails.Date;;
<Date>
{
positive = Bool;
year = Int; month = Int; day = Int; hour = Int;
minute = Int; second = Int;
timezone =? { positive = Bool; hour = Int; minute = Int }
}
XMLスキーマワイルドカード(xsd:any)及び空にできる要素(xsi:nil)がサポートされている。
XMLスキーマの属性グループ定義は、グループ中に含まれる各属性宣言のフィールドを含むレコード型にマップされる。使用における制約が遵守され、オプションの属性はオプションのフィールドに、必須の属性は必須のフィールドにマップされる。XMLスキーマの属性ワイルドカードは、部分的にサポートされている。単純に閉じたレコード型でなく開いたレコード型を生成するが、ワイルドカードの実際の制約は捨てられる。
次のXMLスキーマの属性グループ宣言、
<xsd:attributeGroup name="mimeTypeAttributes"> <xsd:attribute name="type" type="mimeTopLevelType" use="required" /> <xsd:attribute name="subtype" type="xsd:string" use="required" /> </xsd:attributeGroup>
は、したがって、次のCDuce型にマップされる。
# #print_type Mails.mimeTypeAttributes;;
{ type = [
'image' | 'text' | 'application' | 'audio' | 'message' | 'multipart' | 'video'
];
subtype = String }
XMLスキーマのモデルグループ定義は、CDuceのシーケンス型にマップされる。minOccursおよびmaxOccursの制約は遵守され、CDuceの再帰型を使ってunboundedの反復(つまり、クリーンスター)を表現する。
all制約、別名、制約の挟み込みは、型のサイズの爆発を防ぐため、CDuceの型システムでは表現できない。したがって、この種類の内容モデルは一般化され、型システムでは、シーケンス型として扱われる(検査器は実際のXML文書の順序付けをする)。
混合内容モデルがサポートされている。
例として、次のXMLスキーマのモデルグループ定義、
<xsd:group name="attachmentContent">
<xsd:sequence>
<xsd:element name="mimetype">
<xsd:complexType>
<xsd:attributeGroup ref="mimeTypeAttributes" />
</xsd:complexType>
</xsd:element>
<xsd:element name="content" type="xsd:string" minOccurs="0" />
</xsd:sequence>
</xsd:group>
は、次のCDuceの型にマップされる。
# #print_type Mails.attachmentContent;; [ X1 <content}>String | X1 ] where X1 = <mimetype S.mimeTypeAttributes>[ ]
XMLスキーマの検証及び査定の処理は、XMLスキーマインスタンス文書がXMLスキーマ文書に対して妥当であることを検査し、デフォルト値にような欠落している情報を付加することである。CDuceの概念でのスキーマ検証は、ちょっと変わっている。
CDuceはXMLの値が任意の型でできていることを許していて、例えば、整数の属性を持つXML要素を持つことができる。この機能は、XML文書をロードするのに使われる関数(load_xml)が、PCDATA型の値をリーフとして持つXMLの値を返すので、滅多に使われることはない。
一度CDuceでXMLスキーマをインポートすると、これを使い、load_xmlで返るXMLの値を、定義されたXMLスキーマコンポーネントに対して検査することができる。検証の処理は、基本的には、検証時にCDuceの型に対して使われるコンポーネントの、XMLスキーマの型規約に対応する型を持っているCDuceの値を組み立てることである。規約は、前の項目で説明したのと同じである。入力のXMLの値がload_xmlによる必要はなく、PCADATA値をリーフとして持っていれば十分であることに注意。
検証の際、PCDATA文字列はパースされ、XMLスキーマの単純型に対応するCDuceの値を組み立て、空白はXMLスキーマのwhiteSpaceファセットによって明示されるとおりに扱われる。例えば、1234567890というPCDATA文字列をxsd:integer単純型に対して検査すると、型Intで型付けされたCDuce値を返す。
欠落している属性又は要素のデフォルト値も、明示された場所に追加される。
CDuceのプログラムにおいて検査を実行するために、validateキーワードを使うことができる。構文は次のようになる。validate <expr> with <schema_ref>ただし、schema_refをXMLスキーマコンポーネントのインポートで説明したように定義してあるとする。同じ曖昧規則がここでも適用される。
さらに詳しく言うと、検証は、検証に対して使われるスキーマコンポーネントの型によって、異なる種類のCDuceの値に適用することができる。
検証の典型的な使用法は、要素宣言に対する検証である。この場合は、検証は、次の例にあるように、CDuceのXML値に対して呼び出されるべきである。
# let xml = <Date>"2003-10-15T15:44:01Z" in
validate xml with Mails.Date;;
- : S.Date =
<Date> {
time_kind=`dateTime;
positive=`true;
year=2003; month=10; day=15;
hour=15; minute=44; second=1;
timezone={ positive=`true; hour=0; minute=0 }
}
与えられた要素のタグは、要素宣言との整合性を検査される。属性及び内容は、要素に対して宣言されたスキーマの型に対して検査される。
要素を、要素宣言を用いずに、XMLスキーマの混合型に対して検査したいこともあるかもしれない。この場合は、前のものと大変似ているが、使うべきスキーマコンポーネントが複合型の定義であるということが違っており、この検証はどんなXMLの値に対しても適用することができる。他の重要な違いは、与えられた値のタグ名が完全に無視されることである。
例として、
# let xml = load_xml "envelope.xml" ;;
val xml : Any = <ignored_tag From="fake@microsoft.com">[
<From>[ 'user@unknown.domain.org' ]
<To>[ 'user@cduce.org' ]
<Date>[ '2003-10-15T15:44:01Z' ]
<Subject>[ 'I desperately need XML Schema support in CDuce' ]
<header name="Reply-To">[ 'bill@microsoft.com' ]
]
# validate xml with Mails.envelopeType;;
- : S.envelopeType =
<ignored_tag From="fake@microsoft.com">[
<From>[ 'user@unknown.domain.org' ]
<To>[ 'user@cduce.org' ]
<Date> {
time_kind=`dateTime;
positive=`true;
year=2003; month=10; day=15;
hour=15; minute=44; second=1;
timezone={ positive=`true; hour=0; minute=0 }
}
<Subject>[ 'I desperately need XML Schema support in CDuce' ]
<header name="Reply-To">[ 'bill@microsoft.com' ]
]
同様に、モデルグループに対して検査したいかもしれない。この場合、CDuceのシーケンスをモデルグループに対して検査することができる。与えられたシーケンスはXML要素の内容として扱われる。
例として、
# let xml = load_xml "attachment.xml";;
val xml : Any =
<ignored_tag ignored_attribute="foo">[
<mimetype type="application"; subtype="msword">[ ]
<content>[ '\n ### removed by spamoracle ###\n ' ]
]
# let content = match xml with <_>cont -> cont | _ -> raise "failure";;
val content : Any = [
<mimetype type="application"; subtype="msword">[ ]
<content>[ '\n ### removed by spamoracle ###\n ' ]
]
# validate content with Mails.attachmentContent;;
- : Mails.attachmentContent =
[ <mimetype type="application"; subtype="msword">[ ]
<content>[ '\n ### removed by spamoracle ###\n ' ]
]</pre>
最後に、レコードを属性グループに対して検査することができる。属性グループの中で宣言されている全ての必須の属性に、与えられたレコードの中に対応するフィールドがなければならない。そのそれぞれの内容が、属性グループの中の対応する属性に対して定義された単純型に対して検証される。必須でないフィールドは、欠落していれば、対応するデフォルト値を(もしあれば)用いて付加される。
例として、
# let record = { type = "image"; subtype = "png" };;
val record :
{ type = [ 'image' ] subtype = [ 'png' ] } =
{ type="image" subtype="png" }
# validate record with Mails.mimeTypeAttributes ;;
- : { type = [ 'image' | 'text' | ... ] subtype = String } =
{ type="image" subtype="png" }
通常のprint_xml及びprint_xml_utf8ビルトイン関数を用いて、XMLスキーマ検証の結果として得られた値を印字することが可能である。
CDuceに組み込まれたXMLスキーマに対するサポートは、XMLスキーマの仕様書を完全にカバーしようとはしていない。特に、インポートされたスキーマは、妥当であると検査されない。スキーマの妥当性を検査するには、例えば、オンラインの検査器を使うことができる。
また、XMLスキーマ仕様書の機能の中には、サポートされていなかったり、部分的にしかサポートされていなかったりするものがある。ここに非網羅的な制限のリストを示す。
pattern、totalDigits、fractionDigits)<redefine> (修正付きのXMLスキーマのインクルード)xsi:type