Domanda

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?

È stato utile?

Soluzione

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:

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top