Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I add an XML tag or not, depending on an Option in Scala?

Tags:

xml

scala

Related to Adding an XML attribute depending on an Option, I would like to add a XML tag in Scala depending on an option.

scala> def toXml(value1: String, value2: Option[String]) =
     | <body>
     |   <tag1>{value1}</tag1>
     |   {value2 map (x => <tag2>{x}</tag2>) flatten}
     | </body>
toXml: (value1: String,value2: Option[String])scala.xml.Elem

If the Option exists:

scala> toXml("value1", Some("value2"))
res1: scala.xml.Elem =
<body>
  <tag1>value1</tag1>
  <tag2>value2</tag2>
</body>

If the Option does not exist:

scala> toXml("value1", None)
res2: scala.xml.Elem =
<body>
  <tag1>value1</tag1>

</body>

I want to generate a lot of tags depending on an Option, I was wondering whether a more concise solution could be found. For instance, pimping the Elem class with the ? operator and use it like this (it is a dirty solution since the Option value2 is converted to a String before the ? operator is called):

scala> def toXml2(value1: String, value2: Option[String]) =
     | <body>
     |   <tag1>{value1}</tag1>
     |   {<tag2>{value2}</tag2>?}
     | </body>

Any thoughts?

like image 414
Mark Jayxcela Avatar asked Mar 08 '11 22:03

Mark Jayxcela


2 Answers

Your desired ? function can be realised like this:

implicit def optionElem(e: Elem) = new {
  def ? : NodeSeq = {
    require(e.child.length == 1)
    e.child.head match {
      case atom: Atom[Option[_]] => atom.data match {
        case None    => NodeSeq.Empty
        case Some(x) => e.copy(child = x match {
          case n: NodeSeq => n
          case x => new Atom(x)
        })
      }
      case _ => e
    }      
  }
}

For simplicity this is only for single childed nodes to show you the concept (I guess you should be able to write a more general function from there in case you need it)

If the implicit function is in scope, the ? operator can be used just like you wanted:

<body>
{ <tag1>{ Some("Hello") }</tag1>?  }
{ <tag2>{ None }</tag2>? }
{ <tag3>{ Some(<innerTag/>) }</tag3>? }
{ <tag4><innerTag/></tag4>? }
{ <tag5>{ None }</tag5>? }
</body>

will result in:

<body>
  <tag1>Hello</tag1>

  <tag3><innerTag></innerTag></tag3>
  <tag4><innerTag></innerTag></tag4>

</body>
like image 105
Martin Ring Avatar answered Sep 22 '22 13:09

Martin Ring


Why not use an if statement like this:

def toXml(value1:String,value2:Option[String]) =
  <body>
    <tag1>{value1}</tag1>
    {if (value2 isDefined) <tag2>{value2.get}</tag2>}
  </body>

That should do the trick and is fairly understandable, right?

like image 33
Anne Avatar answered Sep 22 '22 13:09

Anne