Обработка необязательных атрибутов 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 ответа:
Я бы сказал, что вы делаете это очень идиоматическим способом, да.
Вы можете "сложить определения" следующим образом:
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:
- они должны быть определены внутри другого признака / класса / объекта.
- они могут принимать только один неявный аргумент в их конструкторе.