在scala播放模板中使用scala.xml.Node

时间:2011-09-05 13:11:29

标签: xml scala playframework

我正在使用Scala play框架。对于我的大多数页面,我将HTML严格保留在视图模板中。特别是对于一个页面,我希望能够通过我在控制器中以编程方式生成的一些XML。我有以下简单的模板:

@(session:play.mvc.Scope.Session, flash:play.mvc.Scope.Flash, analysisTable : scala.xml.Node )

@main(title="Home", session=session, flash=flash) {
    <h1>Some title</h1>
    @{analysisTable}
}

当我通过一些预先生成的XML时,我希望嵌入并导航到相应的页面,我得到:

Execution exception
InvocationTargetException occured : null

在页面上,看起来像控制台上的堆栈溢出(摘录如下):

at play.templates.BaseScalaTemplate._display_(ScalaTemplate.scala:618)
at play.templates.BaseScalaTemplate$$anonfun$_display_$1.apply(ScalaTemplate.scala:618)
at play.templates.BaseScalaTemplate$$anonfun$_display_$1.apply(ScalaTemplate.scala:618)
at scala.xml.NodeSeq.foreach(NodeSeq.scala:43)
at scala.xml.NodeSeq.foldLeft(NodeSeq.scala:43)
at play.templates.BaseScalaTemplate._display_(ScalaTemplate.scala:618)
at play.templates.BaseScalaTemplate$$anonfun$_display_$1.apply(ScalaTemplate.scala:618)
at play.templates.BaseScalaTemplate$$anonfun$_display_$1.apply(ScalaTemplate.scala:618)
at scala.xml.NodeSeq.foreach(NodeSeq.scala:43)
at scala.xml.NodeSeq.foldLeft(NodeSeq.scala:43)
at play.templates.BaseScalaTemplate._display_(ScalaTemplate.scala:618)
at play.templates.BaseScalaTemplate$$anonfun$_display_$1.apply(ScalaTemplate.scala:618)
at play.templates.BaseScalaTemplate$$anonfun$_display_$1.apply(ScalaTemplate.scala:618)
at scala.xml.NodeSeq.foreach(NodeSeq.scala:43)
at scala.xml.NodeSeq.foldLeft(NodeSeq.scala:43)
at play.templates.BaseScalaTemplate._display_(ScalaTemplate.scala:618)
at play.templates.BaseScalaTemplate$$anonfun$_display_$1.apply(ScalaTemplate.scala:618)
at play.templates.BaseScalaTemplate$$anonfun$_display_$1.apply(ScalaTemplate.scala:618)
at scala.xml.NodeSeq.foreach(NodeSeq.scala:43)
at scala.xml.NodeSeq.foldLeft(NodeSeq.scala:43)

显然,我做的事情是愚蠢的或不允许的。有人会关心让我摆脱困境吗?

1 个答案:

答案 0 :(得分:2)

行。我阅读了这些消息来源并找到了解决办法。 scala play模板引擎似乎允许在模板中为内部呈现提供一组定义的不同类型(除了play-scala / src / play / templates / ScalaTemplate.scala),不包括scala.xml.Node:

 case class BaseScalaTemplate[T<:Appendable[T],F<:Format[T]](format: F) {

    def _display_(o:Any):T = {
        o match {
            case escaped:T => escaped
            case () => format.raw("")
            case None => format.raw("")
            case Some(v) => _display_(v)
            case escapeds:Seq[Any] => escapeds.foldLeft(format.raw(""))(_ + _display_(_))
            case string:String => format.escape(string)
            case v if v != null => _display_(v.toString)
            case _ => format.raw("")
        }
    }
}

大多数人会输入字符串,但还有一些其他类型被接受。查看上面匹配语句的第一行,允许任何属于Appendable的子类型。它恰好发生了更进一步的定义:

case class Html(text:String) extends Appendable[Html] {
    val buffer = new StringBuilder(text)

    def +(other:Html) = {
        buffer.append(other.buffer)
        this
    }
    override def toString = buffer.toString
}

我的解决方案是将原始xml子树转换为字符串,然后将其包装在Html类中,如下所示:

@(session:play.mvc.Scope.Session, flash:play.mvc.Scope.Flash, analysisTable : scala.xml.Node )

@main(title="Home", session=session, flash=flash) {
    <h1>Some title</h1>
    @{new play.templates.Html(analysisTable.toString)}
}