Обработка необязательных атрибутов xml в Scala


У меня есть код, который читает XML-файл. Некоторые атрибуты элементов, которые мне нужно обработать, необязательны. Я пытаюсь использовать опцию [T], чтобы управлять ими. Я написал следующее Для pimp типа NodeSeq, возвращаемого оператором узла :

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)

А потом назовем это так:

(node  "@attr").textOption.getOrElse("Some default value")

Если узел имеет атрибут "attr", этот код получает его значение. Если это не так, возвращается значение "некоторое значение по умолчанию".

Как я могу это улучшить? Есть ли какой-то способ сложить определение класса в неявный метод? Есть ли лучший способ получить "необязательные" значения атрибутов? Правильно ли я использую Option[T]?

2 7

2 ответа:

Я бы сказал, что вы делаете это очень идиоматическим способом, да.

Вы можете "сложить определения" следующим образом:

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)
  }
}

Если вы всегда применяете .getOrElse(...) к результату, вы также можете определить вторую версию 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)
}

Это сделает вещи немного более краткими.

scala> (<b>Hello</b> : NodeSeq).textOrElse("No text found.")
resN: String = Hello
scala> (<br /> : NodeSeq).textOrElse("No text found.")
resM: String = No text found.

Ответ может быть улучшен начиная со Scala 2.10 с введением неявных классов.

Http://docs.scala-lang.org/overviews/core/implicit-classes.html

Пример, приведенный op, может быть переписан с использованием неявного класса, например:

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)
    }
  }

}

Обратите внимание, что пример следует за парой ограничений для классов case:

  1. они должны быть определены внутри другого признака / класса / объекта.
  2. они могут принимать только один неявный аргумент в их конструкторе.