我正在从外部数据存储中解析一系列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。截止日期,愚弄我们所有人。
我希望有人可以看看并告诉我是否有我做错的事(我确信有)。我试图限制显示的代码,我希望,与问题相关。但是,如果需要任何其他代码,请告诉我。
由于
答案 0 :(得分:3)
首先,请注意(row \ "ResultDetectionConditionText")
如果不存在具有该名称的子项,则不会是null
- 它只是一个空的NodeSeq
(惯用的Scala代码往往会避免返回null
,你可能已经注意到了)。因此,您当前的代码将始终返回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
的方式,其他一些方法可能更合适。
答案 1 :(得分: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)
只需移除发电机前面的val(Pattern1'&lt; - 'Expr [Guard]),即可恢复正常服务。如果没有我找到的for循环中的val,它也会更好地流动。
答案 2 :(得分:0)
if (cond)
后面应该跟一个表达式。在Scala中,if
更像是Java中的三元运算符:它是表达式,而不是语句。变量声明不是表达式(如在Java中),因此在if的val
部分中不能有then
。
老实说,我猜不出你想要达到什么目标,所以我不能建议一个语法正确的替代方案。但是如果你有更多依赖于cond
的逻辑,你可以把它放在一个块中:
if (cond) {
val name = ...
// do more here
}