I have code that reads an XML file. Some of the attributes of elements that I need to process are optional. I am trying to use Option[T] to manage them. I have written the following to pimp the NodeSeq type returned by the \
Node operator:
class NodeSeqWrapper(nodeSeq: NodeSeq) {
def textOption: Option[String] = {
val text = nodeSeq.text
if (text == null || text.length == 0) None else Some(text)
}
}
implicit def nodeSeqWrapper(nodeSeq: NodeSeq): NodeSeqWrapper =
new NodeSeqWrapper(nodeSeq)
and then call it like this:
(node \ "@attr").textOption.getOrElse("Some default value")
If the node has the "attr" attribute, this code gets it value. If it does not, the value "Some default value" is returned.
How can I improve this? Is there some way to fold the class definition into the implicit method? Is there a better way of getting "optional" attribute values? Am I using Option[T]
"correctly"?
I would say you are doing it in a very idiomatic way, yes.
You can "fold the definitions" as follows:
implicit def enrichNodeSeq(nodeSeq: NodeSeq) = new AnyRef {
def textOption : Option[String] = {
val text = nodeSeq.text
if (text == null || text.length == 0) None else Some(text)
}
}
If you are always applying .getOrElse(...)
on the result, you may also want to define a second version textOrElse(elze : String) : String
:
implicit def enrichNodeSeq(nodeSeq: NodeSeq) = new AnyRef {
def textOption : Option[String] = {
val text = nodeSeq.text
if (text == null || text.length == 0) None else Some(text)
}
def textOrElse(elze : String) : String = textOption.getOrElse(elze)
}
That will make things slightly more concise.
scala> (<b>Hello</b> : NodeSeq).textOrElse("No text found.")
resN: String = Hello
scala> (<br /> : NodeSeq).textOrElse("No text found.")
resM: String = No text found.
The answer can be improved on since Scala 2.10 with the introduction of implicit classes.
http://docs.scala-lang.org/overviews/core/implicit-classes.html
The example the op gave can be re-written using an implicit class like so:
object SomeExtensions {
implicit class ExtendedNodeSeq(nodeSeq: NodeSeq) {
def textOption: Option[String] = {
val text = nodeSeq.text
if (text == null || text.length == 0) None else Some(text)
}
}
}
Note that the example follows a couple of the restrictions for case classes:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With