<any> and <anyAttribute>

Last time I wrote:

Next goal is to handle <any> without ignoring it completely using this generic container. I can probably store the scala.xml.Elem object "as is" in a collection. The user of round trip probably would expect that I don't lose luggage during the flight.

That's pretty much what I did for two usages of <any> handled by scalaxb. First pattern is that it could appear as part of the sequence.

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

scalaxb generates the following:

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: _*) 
}

The second is that it could appear as part of choice particle.

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

scalaxb generates the following:

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)
  }
}

Finally, scalaxb now supports <anyAttribute>:

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

scalaxb generates the following:

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
      }) 
}

It's getting a little messy, but the idea is to keep the data around as DataRecord so it can persist it back into xml document when the time comes to round trip.