0

Is it possible to store a Scala XML Pattern in a variable? Or at least patterns which search for a particular subtree structure with wildcards? I'd like to load patterns at runtime, e.g.,

import scala.xml._

// Is there something like XMLPattern?
def matchMyPattern(xml: Elem, p: XMLPattern): Option[Seq[Node]] = {
  xml match {
    case p(save, throwAway) => Some(save)
    case _ => None
  }
}

val patternsFromFile = Array("<a><b>{ save @ _* }</b>{ throwAway @ _  *}</a>", 
                             "<a>{ throwAway @ _* }<c>{ save @ _* }</c></a>")

val xml = <a><b>x</b><c>y</c></a>

for(pString <- patternsFromFile) {
  val p = new XMLPattern(pString)
  val extractedSeqNode = matchMyPattern(xml, p)
  ...
}

I am looking for a way that takes advantage of Scala's great pattern matching abilities. In particular, I would like to avoid:

  1. Writing my own string parsing and subtree search algorithm.

  2. Using a runtime interpreter along the lines of an Eval(myCode: String).

If it's not possible to access the Scala compiler's internal XML Pattern logic, can the pattern matching be simulated using something like parser combinators for trees?

1 Answer 1

3

It would be best to avoid loading code in at runtime.

Here is an example solution using Scala's 2.11's JSR-223 support:

scala> import javax.script._
import javax.script._

scala> val e = new ScriptEngineManager().getEngineByName("scala");
e: javax.script.ScriptEngine = scala.tools.nsc.interpreter.IMain@26969ee5

scala> val pf = e.eval("""{case <red>{scala.xml.Text(txt)}</red> => txt }: PartialFunction[scala.xml.Elem, String]""").asInstanceOf[PartialFunction[scala.xml.Elem, String]]
pf: PartialFunction[scala.xml.Elem,String] = <function1>

scala> pf(<yellow/>)
scala.MatchError: <yellow/> (of class scala.xml.Elem)
  at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:248)
    at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:246)
    at $anonfun$1.applyOrElse(<console>:8)
    at $anonfun$1.applyOrElse(<console>:8)
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36)
    ... 32 elided

scala> pf(<red>RED</red>)
: String = RED

You can convert the pf into an extractor if you like. Relevant reading:

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

1 Comment

That's pretty cute. I'm sure using IMain directly would let you probe the type of the expr without casting.

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.