<any>,再び

<any> のラウンド・トリップにおいて貨物を無くさないために,DataRecord中に scala.xml.Elem を保存してきましたが,DataRecord を利用する側に立つと,これは不便でもあります.問題は <any> はどの要素が来てもいいためパース不可能なことです.ただし,組み込み型はパース可能です.

混在内容のカタがある程度ついたので,XSD 組み込み型のパースに手をつけるいい機会だと思いました.使用例は以下のようになります:

def testAny {
  val subject = <foo xmlns="http://www.example.com/any"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <int xsi:type="xs:int">1</int>
        <byte xsi:type="xs:byte">1</byte>
        <dateTime xsi:type="xs:dateTime">2002-10-10T12:00:00Z</dateTime>

混在内容,再び

混在内容のサポートを前に始めましたが,おさらいをしておくと,<xs:complexType mixed="true"> の時,XHTML のように一つの要素内にテキストノードと子要素が並列して混在することができようになります.実装した後で,生成される case class が DRY じゃないのが結構気になっていました.

例えば,

<xs:element name="mixedTest">
  <xs:complexType mixed="true">
    <xs:choice maxOccurs="unbounded">
      <xs:element name="billTo" type="Address"/>
      <xs:any namespace="##other" processContents="lax" />
    </xs:choice>
  </xs:complexType>
</xs:element>

scalaxb 0.3.0

Tuple22 限界への対策

今年の初めに Scala の限界に関して書きました:

Scala は Tuple22 までしかサポートしません.

これは Scala が 22個のパラメータを超えた case class を定義できないことを意味します.22個を超えたパーティクルを持つシーケンスを含む複合型を定義するスキーマを扱えるよう回避策をいくつか用意しました.

まず,シーケンスが MaxParticleSize (20)個以上のパーティクルを持つとき,シーケンスを ChunkParticleSize (10)個ごとのチャンク(塊)に分けることにしました.例えば,30個の要素を持つシーケンスは 10個づつの要素を持った三つのチャンクに分かれます:

<xs:element name="foo">
  <xs:complexType>
   <xs:sequence>
     <xs:element name="string1" type="xs:string"/>
     <xs:element name="string2" type="xs:string"/>

代替グループ

XML Schema Part 0: Primer:

XML Schema には特定の要素を他の要素に差し替える代替グループという機構を持つ.具体的には,ヘッド要素と呼ばれる特定の要素に代替可能な特別な要素グループに他の要素を割り当てることができる.(ただし,ヘッド要素と代替可能な要素はグローバル要素に限る)

以下に代替グループの例を示します:

<complexType name="GH6Usage">
  <sequence>
    <element ref="ipo:gh6head"/>
    <element name="gh6head2" type="string" />
    <element name="city"   type="string"/>
  </sequence>
</complexType>

<element name="gh6head" type="string" abstract="true"/>

<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 ~ 
Syndicate content