From a54acf3d30f081dba5c12e7217556199952b7c2d Mon Sep 17 00:00:00 2001 From: Hosam Aly Date: Tue, 13 Mar 2018 12:22:59 +0000 Subject: [PATCH] Give elements default labels These default labels are to be used when a DataRecord doesn't have a label. This helps with generating XML from a memory model without having to know about the XML tags. --- cli/src/main/resources/scalaxb.scala.template | 3 +- .../scalaxb/compiler/xsd/GenSource.scala | 9 ++++-- .../resources/can_write_default_label.xsd | 25 +++++++++++++++++ .../test/scala/CanWriteDefaultLabelTest.scala | 28 +++++++++++++++++++ 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 integration/src/test/resources/can_write_default_label.xsd create mode 100644 integration/src/test/scala/CanWriteDefaultLabelTest.scala diff --git a/cli/src/main/resources/scalaxb.scala.template b/cli/src/main/resources/scalaxb.scala.template index 607093b11..e8e96db60 100644 --- a/cli/src/main/resources/scalaxb.scala.template +++ b/cli/src/main/resources/scalaxb.scala.template @@ -62,6 +62,7 @@ trait CanReadXML[A] { } trait CanWriteXML[A] { + def defaultElementLabel: Option[String] = None def writes(obj: A, namespace: Option[String], elementLabel: Option[String], scope: NamespaceBinding, typeAttribute: Boolean): NodeSeq } @@ -733,7 +734,7 @@ trait CanWriteChildNodes[A] extends CanWriteXML[A] { def writes(obj: A, namespace: Option[String], elementLabel: Option[String], scope: scala.xml.NamespaceBinding, typeAttribute: Boolean): scala.xml.NodeSeq = { val elem = scala.xml.Elem(Helper.getPrefix(namespace, scope).orNull, - elementLabel getOrElse { sys.error("missing element label.") }, + elementLabel orElse defaultElementLabel getOrElse { sys.error("missing element label.") }, writesAttribute(obj, scope), scope, true, writesChildNodes(obj, scope): _*) diff --git a/cli/src/main/scala/scalaxb/compiler/xsd/GenSource.scala b/cli/src/main/scala/scalaxb/compiler/xsd/GenSource.scala index 9b50572d9..add9f93f2 100644 --- a/cli/src/main/scala/scalaxb/compiler/xsd/GenSource.scala +++ b/cli/src/main/scala/scalaxb/compiler/xsd/GenSource.scala @@ -168,7 +168,8 @@ class GenSource(val schema: SchemaDecl, }} case _ => Left("reads failed: seq must be scala.xml.Node") }} - + + override val defaultElementLabel: Option[String] = { quote(decl.family.headOption) } def writes(__obj: {fqn}, __namespace: Option[String], __elementLabel: Option[String], __scope: scala.xml.NamespaceBinding, __typeAttribute: Boolean): scala.xml.NodeSeq = __obj match {{ { val cases = for (sub <- context.baseToSubs(decl)) @@ -388,6 +389,7 @@ class GenSource(val schema: SchemaDecl, def defaultFormats = if (simpleFromXml) trait Default{formatterName} extends scalaxb.XMLFormat[{fqn}] with scalaxb.CanWriteChildNodes[{fqn}] {{ val targetNamespace: Option[String] = { quote(schema.targetNamespace) } + override val defaultElementLabel: Option[String] = { quote(decl.family.headOption) } import scalaxb.ElemName._ def reads(seq: scala.xml.NodeSeq, stack: List[scalaxb.ElemName]): Either[String, {fqn}] = seq match {{ @@ -398,6 +400,7 @@ class GenSource(val schema: SchemaDecl, {makeWritesAttribute}{makeWritesChildNodes} }} else trait Default{formatterName} extends {defaultFormatSuperNames.mkString(" with ")} {{ + override val defaultElementLabel: Option[String] = { quote(decl.family.headOption) } val targetNamespace: Option[String] = { quote(schema.targetNamespace) } { if (decl.isNamed) "override def typeName: Option[String] = Some(" + quote(decl.name) + ")" + newline + newline + indent(2) @@ -492,6 +495,7 @@ class GenSource(val schema: SchemaDecl, Snippet({ buildComment(seq) }case class {localName}({paramsString}){superString}, , trait Default{formatterName} extends scalaxb.XMLFormat[{fqn}] {{ + final override def defaultElementLabel: Option[String] = None // sequences have no label def reads(seq: scala.xml.NodeSeq, stack: List[scalaxb.ElemName]): Either[String, {fqn}] = Left("don't call me.") {makeWritesXML} @@ -642,6 +646,7 @@ object {localName} {{ def build{formatterName} = new Default{formatterName} {{}} trait Default{formatterName} extends scalaxb.XMLFormat[{fqn}] {{ val targetNamespace: Option[String] = { quote(schema.targetNamespace) } + override val defaultElementLabel: Option[String] = { quote(decl.family.headOption) } def fromString(value: String, scope: scala.xml.NamespaceBinding): {fqn} = {valueCode} match {{ { enums.map(e => makeCaseEntry(e)) } @@ -655,7 +660,7 @@ object {localName} {{ def writes(__obj: {fqn}, __namespace: Option[String], __elementLabel: Option[String], __scope: scala.xml.NamespaceBinding, __typeAttribute: Boolean): scala.xml.NodeSeq = scala.xml.Elem(scalaxb.Helper.getPrefix(__namespace, __scope).orNull, - __elementLabel getOrElse {{ sys.error("missing element label.") }}, + __elementLabel orElse defaultElementLabel getOrElse {{ sys.error("missing element label.") }}, scala.xml.Null, __scope, true, scala.xml.Text(__obj.toString)) }}, makeImplicitValue(fqn, formatterName)) diff --git a/integration/src/test/resources/can_write_default_label.xsd b/integration/src/test/resources/can_write_default_label.xsd new file mode 100644 index 000000000..aba984063 --- /dev/null +++ b/integration/src/test/resources/can_write_default_label.xsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/integration/src/test/scala/CanWriteDefaultLabelTest.scala b/integration/src/test/scala/CanWriteDefaultLabelTest.scala new file mode 100644 index 000000000..de2cf5637 --- /dev/null +++ b/integration/src/test/scala/CanWriteDefaultLabelTest.scala @@ -0,0 +1,28 @@ +import scalaxb.compiler.Config +import scalaxb.compiler.ConfigEntry._ + +object CanWriteDefaultLabelTest extends TestBase { + private val schemaFile = resource("can_write_default_label.xsd") + + private def generate() = { + val config = Config.default.update(Outdir(tmp)).update(PackageNames(Map(None -> Some("defaultLabels")))) + module.process(schemaFile, config) + } + + "XML generation falls back to default labels if none are specified" >> { + repl(generate())( + s""" + import defaultLabels._ + import scalaxb.DataRecord + + val urgency = Urgency() + val docId = Docid() + val options = Seq(DataRecord(urgency), DataRecord(None, Some("customDocIdTag"), docId)) + scalaxb.toXML(Docdata(options), "docdata", scala.xml.TopScope).toString + """, expectedResult = scala.xml.Utility.trim( + + + + ).toString) + } +}