Search code examples
xmlscalaclasscase-class

How to represent an XML entity in a Scala Class beautifully?


While this question may be answered in other programming languages, I feel like it was missing from Scala.

I'd like to use a clear DSL that represents the following example XML in a Scala class so that I can easily use it in my XML over REST (play) framework.

<?xml version="1.0" encoding="UTF-8">
<requests>
  <request type="foo" id="1234">
    <recipient>bar<recipient>
    <recipient>baz<recipient>
    <body>This is an example string body</body>
    <ext>Optional tag here like attachments</ext>
    <ext>Optional too</ext>
  </request>
</requests>

Here's my attempt to represent the above model in a scala class:

class Attribute[G](
  value:G
)

class Request(
  type: Attribute[String],
  id: Attribute[Integer],
  recipient[List[String]],
  body: String,
  ext: Option[List[String]] // Some or None
)

// how it's used
val requests = List[Request]

This is not homework, I'm trying to write an app in play to translate from one company internal REST to an industry standard one. (If anyone is curious, it's the OpenCable ESNI vI02 XML format)

My question: Did I represent the "foo" and "id" attributes correctly? if so, how would i easily output the XML without much massaging or crude string interpolation. I want foo and id to be interpreted as attributes and NOT as nested tags like so:

...<request><type>foo</type><id>1234</id>...DO NOT WANT

Thanks!


Solution

  • XML tags are first class citizens in Scala, giving you the possibility to use the tags in a cleaner way than other languages.

    As of Scala 2.11, XML Library has been extracted to its own package.

    Having that, you can easily use some idiomatic Scala to achieve your goal:

    case class Request(requestType: String, id: Int, recipients: List[String], body: String, ext: Option[List[String]]){
    
          def toXML =
            <requests>
              <request type={requestType} id={id}>
                  {recipientsXML}
                  <body>{body}</body>
                  {extXML}
              </request>
            </requests>
    
          private def recipientsXML = 
            recipients.map(rec => <recipient>{rec}</recipient>)
          private def extXML = for {
            exts <- ext
            elem <- exts
          } yield <ext>{elem}</ext>
    }