5

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

1
  • I guess I should make it clear that the the above is part of a comprehension for statement. The if(cond) is suppose to be for determining the execution of the yield block. I've edited my answer to elaborate more on the code. Commented Sep 7, 2012 at 12:22

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the response and pointing out those issues, I will apply those changes to the code. I've edited my question to point out that this is all in a comprehensive-for which I think (could be wrong) changes the ternary nature of the if statement.
1

The xml is a distraction here. The problem is the if (cond) at the end is not acting as a guard, it just looks like it should, the compiler thinks is the start of a new if 'then' part.

In the following example:

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

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

you'll get List(6,8,10) as you might expect.

Using

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

should get you a deprecation warning, and

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

gets

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

Simply remove the val in front of your Generator (Pattern1 ‘<-’ Expr [Guard]), and you can resume normal service. It also flows a bit more nicely without the vals in the for loop I find.

1 Comment

This is the best answer related directly to the question. Unfortunately, this caused me to re-think the problem and do a significant re-write.
0

if (cond) should be followed by an expression. In Scala, if is more like the ternary operator in Java: it is an expression, not a statement. A variable declaration is not an expression (as in Java), so you can't have a val in the then part of an if.

Honestly, I can't guess what you want to achieve there, so I can't suggest a syntactically correct alternative that makes sense. But if you have more logic that depends on cond, you could put it in a block:

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

1 Comment

Thanks for the concise response. I forgot that the if statement can act as the conditional operator. However, in this case I am using the if statement as a part of a comprehensive for operation, which I believe (I could very well be mistaken) changes it from a ternary operator to a conditional requirement for the yield statement. I've revised my question above to include more of the code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.