2012-09-06 23 views
5

我正在解析來自外部數據存儲的一系列XML響應。在此期間,我必須測試一個子節點的存在,並且 - 如果它存在 - 測試它的值。爲了實現這一點,我有以下代碼:Scala 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

我想我應該說清楚以上是語句理解的一部分。 'if(cond)'假定是用於確定yield塊的執行。我編輯了我的答案,詳細說明了代碼。 – Cowan

回答

1

xml在這裏是一個分心。問題是最後的if(cond)不是作爲守衛,它看起來應該是這樣,編譯器認爲這是一個新的'then'部分的開始。

在下面的例子:

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

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

你會得到清單(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在發電機的主(樣式1 '< - ' Expr [Guard]),您可以恢復正常服務。它也流暢了一點,沒有我找到的for循環中的vals。

+0

這是直接與問題相關的最佳答案。不幸的是,這使我重新思考問題並做了重大的改寫。 – Cowan

0

if (cond)應後跟一個表達式。在Scala中,if更像Java中的三元運算符:它是表達式,而不是語句。變量聲明不是一個表達式(如在Java中),所以在if的then部分中不能有val

老實說,我不能猜測你想在那裏達到什麼,所以我不能建議一個語法正確的選擇是有道理的。但如果你有依賴於cond更多的邏輯,你可以把它放在一個塊:

if (cond) { 
    val name = ... 
    // do more here 
} 
+0

感謝您的簡潔迴應。我忘記了if語句可以作爲條件操作符。然而,在這種情況下,我使用if語句作爲綜合操作的一部分,我認爲(我很可能會誤會)將它從三元操作符更改爲yield語句的條件需求。我已經修改了上面的問題以包含更多的代碼。 – Cowan

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"問題 - 它只是修復邏輯並將十六行代碼縮減爲三。這裏的問題是,如果你剛剛完成的測試失敗,你需要決定你的name應該是什麼。最明顯的方法是使用一個Option

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

但取決於你如何使用name,一些其他的方法可能更合適。

+0

感謝您的迴應並指出這些問題,我會將這些更改應用到代碼中。我編輯了我的問題,指出這是全面的 - 我認爲(可能是錯誤的)會改變if語句的三元性質。 – Cowan

相關問題