<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 は以下のコードを生成します:

case class Choice1(any: org.scalaxb.rt.DataRecord[scala.xml.Node]*) extends org.scalaxb.rt.DataModel {
 
  def toXML(namespace: String, elementLabel: String, scope: scala.xml.NamespaceBinding): scala.xml.Node = {
    val prefix = scope.getPrefix(namespace)
    var attribute: scala.xml.MetaData  = scala.xml.Null
 
    scala.xml.Elem(prefix, elementLabel,
      attribute, scope,
      Seq(any.map(x => x.toXML(x.namespace, x.key, scope))).flatten: _*)
  }
}
 
object Choice1 {
  def fromXML(node: scala.xml.Node): Choice1 =
    Choice1((node.child.partialMap {
      case x: scala.xml.Elem =>
        org.scalaxb.rt.DataRecord(x.scope.getURI(x.prefix), x.label, x) }).toList: _*) 
}

次にchoice の選択肢として使われる場合.

<element name="Element1">
  <complexType>
    <sequence>
      <choice maxOccurs="unbounded">
        <element ref="ipo:Choice1"/>
        <any namespace="##other" processContents="lax" />
      </choice>
    </sequence>
  </complexType>
</element>

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

case class Element1(arg1: org.scalaxb.rt.DataRecord[Any]*) extends org.scalaxb.rt.DataModel {
 
  def toXML(namespace: String, elementLabel: String, scope: scala.xml.NamespaceBinding): scala.xml.Node = {
    val prefix = scope.getPrefix(namespace)
    var attribute: scala.xml.MetaData  = scala.xml.Null
 
    scala.xml.Elem(prefix, elementLabel,
      attribute, scope,
      Seq(arg1.map(x => x.toXML(x.namespace, x.key, scope))).flatten: _*)
  }
}
 
object Element1 {
  def fromXML(node: scala.xml.Node): Element1 =
    Element1(node.child.filter(Element1Option.fromXML.isDefinedAt(_)).map(x =>
      Element1Option.fromXML(x)).toList: _*) 
}
 
trait Element1Option extends org.scalaxb.rt.DataModel
object Element1Option {  
  def fromXML: PartialFunction[scala.xml.NodeSeq, org.scalaxb.rt.DataRecord[Any]] = {
    case x: scala.xml.Elem if (x.label == "Choice1" && 
        x.scope.getURI(x.prefix) == "http://www.example.com/IPO") =>
      org.scalaxb.rt.DataRecord(x.scope.getURI(x.prefix), x.label, Choice1.fromXML(x))
    case x: scala.xml.Elem =>
      org.scalaxb.rt.DataRecord(x.scope.getURI(x.prefix), x.label, x)
  }
}

さらに,scalaxb は<anyAttribute>のサポートも始めました.

<element name="Element2">
  <complexType>
    <anyAttribute namespace="##any"/>
  </complexType>
</element>

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

case class Element2(anyAttribute: Seq[org.scalaxb.rt.DataRecord[String]]) extends org.scalaxb.rt.DataModel {
 
  def toXML(namespace: String, elementLabel: String, scope: scala.xml.NamespaceBinding): scala.xml.Node = {
    val prefix = scope.getPrefix(namespace)
    var attribute: scala.xml.MetaData  = scala.xml.Null
    anyAttribute.foreach(x =>
      if (x.namespace == null)
        attribute = scala.xml.Attribute(null, x.key, x.value, attribute)
      else
        attribute = scala.xml.Attribute(scope.getPrefix(x.namespace), x.key, x.value, attribute))
 
    scala.xml.Elem(prefix, elementLabel,
      attribute, scope,
      Seq().flatten: _*)
  }
}
 
object Element2 {
  def fromXML(node: scala.xml.Node): Element2 =
    Element2(node match {
        case elem: scala.xml.Elem =>
          (elem.attributes.toList) flatMap {
 
            case scala.xml.UnprefixedAttribute(key, value, _) =>
              List(org.scalaxb.rt.DataRecord(null, key, value.text))
            case scala.xml.PrefixedAttribute(pre, key, value, _) =>
              List(org.scalaxb.rt.DataRecord(elem.scope.getURI(pre), key, value.text))
            case _ => Nil
          }
        case _ => Nil
      }) 
}

ちょっとゴチャゴチャしてきていますが,ラウンド・トリップ時にxmlドキュメントにデータを書き出せるようにDataRecord内にデータを保存しているというだけですね.