【问题标题】:Processing optional xml attributes in Scala在 Scala 中处理可选的 xml 属性
【发布时间】:2011-12-06 02:10:44
【问题描述】:

我有读取 XML 文件的代码。我需要处理的元素的一些属性是可选的。我正在尝试使用 Option[T] 来管理它们。我编写了以下内容来拉皮条由\ Node 运算符返回的 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]

【问题讨论】:

  • 您可能希望调用您的方法textOption,与SeqheadheadOption 方法的风格相同。
  • 听起来不错。我会更改我的代码。也在更新问题。

标签: scala xml-parsing option


【解决方案1】:

我会说你正在以一种非常惯用的方式这样做,是的。

您可以按如下方式“折叠定义”:

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.

【讨论】:

  • 这就是我想要的。我在第一次尝试时尝试使用匿名类 (new {...}),但它不起作用。我也喜欢textOrElse 方法。谢谢。
  • 请注意,“折叠定义”会导致每次调用额外方法时都使用 Java 反射。声明额外的类不会。
  • @Jean-PhilippePellet 好点!我怀疑 JVM JIT 编译器非常擅长处理反射调用,其中方法的名称以静态字符串的形式给出。
  • 忘记了。就我而言,XML 文件很小(配置文件),因此几乎不会对性能产生影响。
【解决方案2】:

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

}

请注意,该示例遵循案例类的一些限制:

  1. 它们必须在另一个特征/类/对象中定义。
  2. 它们只能在其构造函数中采用一个非隐式参数。

【讨论】:

    猜你喜欢
    • 2015-01-15
    • 2010-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-03
    • 1970-01-01
    相关资源
    最近更新 更多