<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 thescala.xml.Elemobject “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.