- scala> <document>
- | <child1/>
- | <child2/>
- | </document>
- res0: scala.xml.Elem =
- <document>
- <child1></child1>
- <child2></child2>
- </document>
- scala> res0 match {
- // match the document tag
- // the {_*} is critical
- | case <document>{_*}</document> => println("found document element")
- | case _ => println("Found another element")
- | }
- found document element
- scala> res0 match {
- // assign the document element to e
- | case e @ <document>{_*}</document> => println(e)
- | case _ => println("Found another element")
- | }
- <document>
- <child1></child1>
- <child2></child2>
- </document>
- scala> res0 match {
- // assign the children of document to children
- // notice that there are Text elements that are part of children
- | case <document>{children @ _*}</document> => println(children)
- | case _ => println("Found another element")
- | }
- ArrayBuffer(
- , <child1></child1>,
- , <child2></child2>,
- )
- // the '\' is xpath like but only returns elements and attributes
- // in this case the \ "_" returns all element children of res0. It
- // will not return the Text elements.
- scala> res0 \ "_" foreach {
- | case <child1>{_*}</child1> => println("child1 found")
- | case <child2>{_*}</child2> => println("child2 found")
- | case e => println("found another element")
- | }
- child1 found
- child2 found
- // another example of how \ does not return any text elements. This returns
- // no elements
- scala> <doc>Hello</doc> \ "_" foreach { case scala.xml.Text(t) => println("a text element found: "+t) }
- // the .child returns all children of an Elem
- scala> <doc>Hello</doc>.child foreach { case scala.xml.Text(t) => println("a text element found: "+t) }
- a text element found: Hello
- // This example throws a match error because there are whitespace text elements
- // that cause the match to fail.
- scala> res0 match {
- | case <document><child1/><child2/></document> => println("found the fragment")
- | }
- scala.MatchError: <document>
- <child1></child1>
- <child2></child2>
- </document>
- at .< init>(< console>:6)
- at .< clinit>(< console>)
- at RequestResult$.< init>(< console>:3)
- at RequestResult$.< clinit>(< console>)
- at RequestResult$result(< console>)
- at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
- at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMetho...
- // The trim method removes the whitespace nodes so now the
- // match will work
- scala> scala.xml.Utility.trim(res0) match {
- | case <document><child1/><child2/></document> => println("found the fragment")
- | }
- found the fragment
- // you can select part of the tree using matching
- // child2 is assigned to 3 in this example.
- scala> scala.xml.Utility.trim(res0) match {
- | case <document><child1/>{e @ _*}</document> => println("found the fragment:"+e)
- | }
- found the fragment:RandomAccessSeq(<child2></child2>)
Tuesday, November 17, 2009
XML matching
The Scala XML support includes the ability to match on XML elements. Here are several examples. One of the most important parts to remember is to not miss the '{' and '}'.
Be careful when matching with XML literals, as whitespace is significant. For this reason, Lift matches uses the XML case classes only.
ReplyDeleteThis is absolutely correct and a good warning. IF (and it is a big if) you use matching with literals I highly recommend using the scala.xml.Utility.trim() method to assist with it. But matching with case classes is safer (and uglier :) )
ReplyDelete