开发者

Using scala.xml.Node in scala play templates

开发者 https://www.devze.com 2023-04-02 06:45 出处:网络
I am using the Scala play framework. For most of my pages I keep my HTML strictly within the view templates. For one page in particular though, I would like to be able pass through some XML I have gen

I am using the Scala play framework. For most of my pages I keep my HTML strictly within the view templates. For one page in particular though, I would like to be able pass through some XML I have generated programatically in my controller. I have the following trivial template:

@(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}
}

When I pass through some pre-generated XML that I am hoping to embed and navigate to the appropriate page, I get:

Execution exception
InvocationTargetException occured : null

On the page, and what looks like a stack overflow on the console (excerpt below):

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)

Clearly I am doing something either dumb or not allowed. Would anyone care to put me out of my misery?


OK. I read the sources and worked out a fix. The scala play templating engine seems to allow a defined set of different types within the template for internal rendering (exceprt from play-scala / src / play / templates / ScalaTemplate.scala), not including 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("")
        }
    }
}

Mostly one puts in strings, but there are a few other types accepted. Looking at the top line of the match statement above, anything that is a subtype of Appendable is allowed. And it just so happens that a little further up there is the following class defined:

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
}

My solution then, is to convert the original xml subtree to a string and then wrap that in the Html class as follows:

@(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)}
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号