5

我正在解析来自外部数据存储的一系列 XML 响应。在此期间,我必须测试子节点是否存在,如果存在,则测试它的值。为此,我有以下代码:

...
  val properties = for {
    val row <- root \\ "ResultDescription"
    val cond:Boolean = checkDetectionNode(row) match {
      case Some(nodeseq) => {
          val txt = nodeseq.text.toLowerCase
          if (txt contains "non-detect")
            false
          else
            true
      }
      case None => true
    }
    if (cond)
    val name = (row \ "CharacteristicName").text
    if (charNameList.exists(s => s == name) == false)
  } yield {
    getObservedProperty(name) match {
      case Some(property) => {
          charNameList = name :: charNameList
          property
      }
    }
  }
...

checkDetectionNode 定义如下:

private def checkDetectionNode(row: scala.xml.NodeSeq) : Option[scala.xml.NodeSeq] = {
  if ((row \ "ResultDetectionConditionText") != null)
    Some[scala.xml.NodeSeq]((row \ "ResultDetectionConditionText"))
  else
    None
}

上面的代码在行上导致“非法开始简单表达式”的未指定错误val name...。老实说,我不是 Scala 程序员,甚至不是函数式程序员(总是更偏向于 OO/命令式)。我只使用 Scala 几天,并且基于我从 Java 和 lambda 运算符中了解的大部分内容。不幸的是,我真的没有时间像我希望的那样坐下来真正学习 Scala。截止日期,愚弄我们所有人。

我希望有人可以看看并让我知道我是否做错了什么(因为我确信有)。我试图将显示的代码限制为我希望与问题相关的代码。但是,如果需要任何其他代码,请告诉我。

谢谢

4

3 回答 3

3

首先,请注意,如果不存在具有该名称的子项,(row \ "ResultDetectionConditionText")则不会出现null— 它只是一个空的NodeSeq(惯用的 Scala 代码倾向于避免返回null,正如您可能已经注意到的那样)。因此,您当前的代码将始终返回 a Some,这可能不是您想要的。更改!= null.nonEmpty将解决该问题。

接下来,这是编写条件逻辑的更简洁的方法:

val cond = (row \ "ResultDetectionConditionText").exists(
  _.text.toLowerCase contains "non-detect"
)

这表示:获取一个NodeSeq包含所有名为 的子节点"Result..."(如果存在),然后检查它NodeSeq是否有一个包含文本的节点"non-detect"。逻辑与您的不完全相同,因为我们单独检查节点的文本,但它实际上更符合我的猜测是您的意图 - 大概您不希望这样的东西通过测试:

val row = <row>
  <ResultDetectionConditionText>non-d</ResultDetectionConditionText>
  <ResultDetectionConditionText>etect</ResultDetectionConditionText>
</row>

但它会在您当前的版本中。

但是这些都不能解决你的"illegal start of simple expression"问题——它只是修复了逻辑并将 16 行代码减少到 3 行。这里的问题是,如果你刚刚完成的测试失败,你需要决定你name应该做什么。最明显的方法是使用Option

val name = if (cond) Some((row \ "CharacteristicName").text) else None

但根据您的使用name方式,其他一些方法可能更合适。

于 2012-09-06T21:17:47.323 回答
1

xml 在这里让人分心。问题是最后的 if (cond) 没有起到保护作用,它看起来应该是,编译器认为是新的 if 'then' 部分的开始。

在以下示例中:

val l = List(1,2,3,4,5)

val r = for {
    i <- l 
      if (i > 2)
    x <- Some(i * 2)
  } yield x

你会得到如你所料的 List(6,8,10) 。

使用

val r = for {
    val i <- l if (i > 2)
    val x <- Some(i * 2)
  } yield x

应该给你一个弃用警告,和

val r = for {
    val i <- l 
    if (i > 2)
    val x <- Some(i * 2)
  } yield x

得到

error: illegal start of simple expression
  val x <- Some(i * 2)

只需删除 Generator 前面的 val (Pattern1 '<-' Expr [Guard]),即可恢复正常服务。如果没有我发现的 for 循环中的 val,它也会更好地流动。

于 2012-09-07T22:23:34.300 回答
0

if (cond)后面应该跟一个表达式。在 Scala 中,if更像是 Java 中的三元运算符:它是表达式,而不是语句。变量声明不是一个表达式(如在 Java 中),因此您不能valthenif 部分使用 a。

老实说,我猜不出你想在那里实现什么,所以我不能提出一个有意义的语法正确的替代方案。但是,如果您有更多依赖于 的逻辑,cond则可以将其放在一个块中:

if (cond) {
  val name = ...
  // do more here
}
于 2012-09-06T21:05:32.173 回答