2

Consider the following XML node:

 <Interval>
   <P v="1"/>
   <Q v="0.0"/>
  </Interval>

What is the correct way to pattern match the top level element in Scala? I would expect the following to work but it does not:

def visit(node:Node):String = {
    node match {
        case p @ <P/> => (p \ "@v") text
        case q @ <Q/> => (q \ "@v") text
        case <Interval> @ children:_* </Interval> => "parent"
    }
}

2 Answers 2

2

When you create an XML literal in Scala, the variable you assign to it is the top level element.

val node: scala.xml.Elem =
  <Interval>
   <P v="1"/>
   <Q v="0.0"/>
  </Interval> 

To match the top-level element, here Interval, or any element of Interval that has child elements like your example, you can use curly braces to match the children.

node match {
  case <Interval>{ children @_* }</Interval> => children.collect {
    case p @ <P/> => p \@ "v"
    case q @ <Q/> => q \@ "v"
  }
}

The result is:

Seq("1", "0.0")

If you're not familiar with collect, it allows you to provide a partial function (read as "pattern match") and ignore cases that would otherwise fail as a match error.

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

1 Comment

I think that this answer mostly gave a more legible and intuitive in regard to original question than mine (on pattern matching syntax, obviously). It should be considered as the correct answer. (As for me, I'll use more often this syntax for simple use cases)
0

This expression in scala:

<Interval>
 <P v="1"/>
 <Q v="0.0"/>
</Interval>

would definitely return a scala.xml.Node in scala but firstly a scala.xml.Elem. You can pattern match on it like this:

import scala.xml.Elem

def visit(elem: Elem) = {
    elem match {
        case e@Elem(_, "Interval",_, _, _*) => "identified!"
    }
}

Or you can pattern match on the child as well, because you pattern match on object n of type Elem is like Elem(n.prefix, n.label, n.attributes, n.scope, n.child) and here child elements (it's a Seq) are matched against each remaining elements of the pattern:

def visit(elem: Elem) = {
    elem match {
        case Elem(_, "Interval",_, _, emptyElem, nodeIWant@(<P/>), _*) =>
        (nodeIWant \ "@v").text
    }
}

which return 1 here for instance.

Hope it helps.

1 Comment

When I say "which return 1 here for instance" I may have to clarify that it is a String whom representation is 1. Anyway, don't hesitate to ask for a more specific case if that's not sufficient here.

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.