1

次のような内容のxmlファイルがあるとします。

<example name={name}/>

このファイルをScalaからロードして、{name}をスコープ内のnameの値に置き換えることは可能ですか?

つまり、XML.loadFileのようなものですが、ScalaのXMLリテラルと同じ方法でデータバインディングを実行します。

より複雑な例も同様に機能することに注意してください。

<example name={name}>
   {for (hobby <- hobbies) yield <hobby>{hobby}</hobby>}
</example>
4

2 に答える 2

3

これで十分でしょうか?

import scala.collection.mutable
import scala.util.matching.Regex.Groups
import scala.xml.XML

type Data = mutable.Map[Symbol, Any]

object Data {
  def empty = mutable.Map.empty[Symbol, Any]
}

class Assignment(identifier: Symbol, data: Data) {
  def :=(value: Any) {
    data(identifier) = value
  }
}

implicit def symbol2assignment(id: Symbol)(implicit data: Data) =
  new Assignment(id, data)

def bind(template: String)(implicit data: Data) = {
  val attributes = """=\{([^{}]+)}""".r
    .replaceAllIn((_: String), _ match {
      case Groups(identifier) =>
        "=\"%s\"".format(data(Symbol(identifier)))
    })
  val rest = """\{([^{}]+)}""".r
    .replaceAllIn((_: String), _ match {
      case Groups(identifier) =>
        data(Symbol(identifier)).toString
    })
  (attributes andThen rest andThen XML.loadString)(template)
}

implicit val data = Data.empty

'name := "bob"
'text := "hi there"

val bound = bind("<ex name={name}>{text}</ex>")
assert(bound == <ex name="bob">hi there</ex>)
于 2012-04-17T22:44:50.293 に答える
1
object XmlBinder {

  // "twitter" at "http://maven.twttr.com"
  // "com.twitter" %% "util-eval" % "3.0.0"
  import com.twitter.util.Eval
  import scala.xml.Elem

  private val template =
    """|<example name={name}>
       |  {for (hobby <- hobbies) yield <hobby>{hobby}</hobby>}
       |</example>""".stripMargin

  val name = "name"
  val hobbies = List("hobby 1", "hobby 2")

  def bind(): Elem = new Eval()("import XmlBinder._\n" + template)
}
于 2012-04-18T21:42:18.807 に答える