<enumeration>

XML Schema Part 0: Primer より:

enumeration (列挙)ファセットは単純型を具体的な値の集合へと限定します.例えば,アメリカの州の略称を値とする USState という新しい単純型をstringから派生して定義するのに enumeration ファセットを利用することができます:

<xsd:simpleType name="USState">
  <xsd:restriction base="xsd:string">
    <xsd:enumeration value="AK"/>
    <xsd:enumeration value="AL"/>
    <xsd:enumeration value="AR"/>
    <!-- and so on ... -->
  </xsd:restriction>
</xsd:simpleType>

このような制限は case object を使って表現することができます.以下は scalaxb が生成するコードです:

trait USState
 
object USState {

scalaxb-appengine

scalaxb-appengine は scalaxb を web上で使うための RESTful API です.n8han/Unfiltered を使ってて,ソースは eed3si9n/scalaxb-appengine にあります.

compile

URL:
http://scalaxb.appspot.com/compile/{output}.{format}
フォーマット:
scala, zip
HTTP メソッド:
POST
HTTP エンコーディング:
multipart/form-data
パラメータ:
- arg: 省略可,複数化.スキーマファイルの URL.
- argf: 省略可,複数化.アップロードするスキーマファイル.
- defaultPackageName: 省略可.対象パッケージ.
- namespaceURI: 省略可,複数化.パッケージする名前空間 URI.
- packageName: 省略可,複数化.namespaceURI によって指定された名前空間の対象パッケージ.
- classPrefix: 省略可,生成されるクラス名のプレフィックスを指定します.
- paramPrefix: 省略可,生成される仮引数名のプレフィックスを指定します.
- wrapContents: 省略可,複数化.別の case class に追い出す複合型を指定します.
備考:
- argargf かのどちらか一つは指定して下さい.
- n番目の packageName が n番目の namespaceURI の対象パッケージを指定します.

scalaxb 0.2.0

  • <group>, <attributeGroup>, <all> のサポートを実装しました.
  • シーケンスを含んだ複合型のラウンドトリップを修正しました.
  • case class をすっきりさせるため,toXMLがコンパニオンオブジェクトに生成されるようになりました.

例えば,

<xs:complexType name="Address">
  <xs:sequence>
    <xs:element name="name"   type="xs:string"/>
    <xs:element name="street" type="xs:string"/>
    <xs:element name="city"   type="xs:string"/>
  </xs:sequence>
</xs:complexType>

から以下のようなコードが生成されます:

case class Address(name: String,
  street: String,
  city: String)

<group> と <attributeGroup>

XML Schema Part 1 より:

モデルグループ定義を行うスキーマコンポーネントの XML 表現は<group> 要素である.これはXMLで表現された複合型定義内においてモデルグループの参照するための名前付けを行うためのものである.

<group> という機構を使うことによってスキーマ設計者は内容モデルの一部を型派生に頼ることなく再利用することができます.これは込み入ったスキーマを扱うときに便利なものです.例えば,以下のような head.misc という名前のグループと head という名前の要素を考えます.

<group name="head.misc">
  <sequence>
    <choice minOccurs="0" maxOccurs="unbounded">
      <xs:element ref="ipo:script"/>
      <xs:element ref="ipo:style"/>
    </choice>
  </sequence>
</group>

scalaxb 0.1.0

生成されるパーサの一例です:

object Address extends rt.ElemNameParser[Address] {
  val targetNamespace = "http://www.example.com/IPO"

  def parser(node: scala.xml.Node): Parser[Address] =
    (rt.ElemName(targetNamespace, "name")) ~ 
      (rt.ElemName(targetNamespace, "street")) ~ 
      (rt.ElemName(targetNamespace, "city")) ^^
        { case p1 ~ 
      p2 ~ 

xsi:nillable

XML において値の欠如を表現するのに要素を省くか空要素を使うかの方法があります.

未配送の物品,不明な情報,不適切な情報などを要素の欠落ではなく明示的に表現することが望ましい場合があります.

空要素 <foo></foo> を使うことの問題は,空の値が指定されている xs:positiveInteger にマッチしなくなってしまうことです.確かに,正の整数と空文字の両方を許容するために,xs:positiveInteger と空文字のみを含んだ xs:enumeration(列挙型)の xs:union(ユニオン型) を形成することも可能ですが,厳密には空文字と純粋な無の値は別物です.コードでいうと,null"" の違い,特に Scala での NoneSome("") の違いがあります.

XML Schema ではこの問題を解決するために xsi:nil という特別な属性を使います.

<price xsi:nil="true" />

パーサ・コンビネータを使ったパーシング

ハンド・パーシング(手書き構文解析)の限界は前から分かっていました.トークンの位置に頼ったパーシングは,文法に繰り返し,オプション,シーケンスの選択などの複雑なものが出てきたとたんに手に負えなくなります.ある時点で scala のパーサ・コンビネータを使って内容モデルをパーシングをしようと決めましたが,結構長く時間がかかってしまいました.

まずは,実際に使われているスキーマから複雑な構造を紹介しましょう:

<complexType name="SubjectType">
    <choice>
        <sequence>
            <choice>
                <element ref="saml:BaseID"/>
                <element ref="saml:NameID"/>
                <element ref="saml:EncryptedID"/>
            </choice>
            <element ref="saml:SubjectConfirmation" minOccurs="0" maxOccurs="unbounded"/>

混在内容

一つの要素内にテキストノードと子要素が並列して混在している混在内容のサポートを実装しました.<any>と同様にテキストは他のDataRecordオブジェクトと一緒にDataRecord[String]オブジェクトの中に保存され,mixedという値で呼ばれます.

次のようなスキーマがあるとすると,,

<element name="Element3">
  <complexType mixed="true">
    <choice maxOccurs="unbounded">
      <element ref="ipo:Choice1"/>
      <element ref="ipo:Choice2"/>
      <any namespace="##other" processContents="lax" />
    </choice>
  </complexType>
</element>

使用例のコードは以下のようになります.

 

<any> と <anyAttribute>

前回

今後の予定としては,このジェネリックなコンテナを使って現在切り捨てている<any>をちゃんと変換することです.おそらくscala.xml.Elemをそのままの形でコレクションの中に残しておくような形になると思います.一旦ラウンド・トリップ機能を提供すると,ユーザは途中で荷物が無くならないことを期待すると思うので.

と書いたとおり, <any>の処理を変更しました.<any>の処理には2パターンあって,まずsequence の一部として使われる場合.

<element name="Choice1">
  <complexType>
    <sequence>
      <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
    </sequence>
  </complexType>
</element>

scalaxb は以下のコードを生成します:

 

ラウンド・トリップ

ラウンド・トリップ(往復券)の実装を始めています.つまり,xmlドキュメントからscalaオブジェクトに変換して,そこからまたxmlドキュメントに変換できるようにする機能です.以下のようなドキュメントがあるとして,

val subject = <shipTo xmlns="http://www.example.com/IPO"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ipo="http://www.example.com/IPO"
    xsi:type="ipo:USAddress">
  <name>Foo</name>
  <street>1537 Paper Street</street>
  <city>Wilmington</city>
  <state>DE</state>
  <zip>19808</zip>
</shipTo>

fromXML()を呼び出すことでオブジェクトに変換できます

val obj = Addressable.fromXML(subject)
Syndicate content