Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala XML: test for node existence and value

Tags:

xml

scala

I am parsing a series of XML responses from a external data store. During which I must test for the existence of a child node and - if it exists - test its value. To achieve that I have the following code:

...
  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 is defined as such:

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

The above code results in an unspecified error of "illegal start of simple expression" on the val name... line. To be honest I am not a Scala programmer or even a functional programmer (always was more partial to OO/imperative). I've only been using Scala for a few days and been basing most of what I know from Java and lambda operators. Unfortunately, I don't really have the time to sit down and really learn Scala like I wish I could. Deadlines, make fools of us all.

I am hoping that someone could take a look and let me know if there is something I am doing wrong (as I am sure there is). I tried to limit the code shown to, what I hope, is relevant to the question. However, please let me know if any additional code is needed.

Thanks

like image 742
Cowan Avatar asked Oct 07 '22 17:10

Cowan


1 Answers

First of all, note that (row \ "ResultDetectionConditionText") won't be null if no children with that name exist—it will just be an empty NodeSeq (idiomatic Scala code tends to avoid returning null, as you've probably noticed). So your current code will always return a Some, which probably isn't what you want. Changing your != null to .nonEmpty will fix that problem.

Next, here's a more concise way of writing your conditional logic:

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

This says: get a NodeSeq that contains all the children named "Result...", if they exist, and then check that NodeSeq for a node that contains the text "non-detect". The logic's not exactly the same as yours, since we check the text of the nodes individually, but it actually fits what I'd guess is your intent even better—presumably you don't want something like this to pass the test:

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

But it will in your current version.

But none of this solves your "illegal start of simple expression" issue—it just fixes the logic and cuts sixteen lines of code down to three. The problem here is that you need to decide what your name should be if the test you've just done fails. The most obvious approach is to use an Option:

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

But depending on how you're using name, some other approach may be more appropriate.

like image 146
Travis Brown Avatar answered Oct 10 '22 15:10

Travis Brown