开发者

How to construct a NodeSeq programmatically?

I have a NodeSeq like this

val article_template =
 <div>
      <div class="title"></div>
      <div class="content"></div>
      <!-- some other markups don't know -->
 </div>

I want to create this structure for each article in a List (defined as val articleList), resulting in this:

 <div>
      <div class="title">title a</div>
      <div class="content">content a</div>
      <!-- some other markups don't know -->
 </div>
 <div>
      <div class="title">title b</div>
      <div class="content">content b</div>
      <!-- some other markups don't know -->
 </div>
...

Updated:

Please note the <!-- some other markups don't know --> part, so I cannot use XML literal syntax t开发者_JAVA百科o construct it. I need a list of modified article_template with corresponding article info.


See scala.xml.transform._ and the corresponding Stack Overflow questions.

It will probably look somewhat like this:

import scala.xml._
import transform._

case class Article( title: String, content: String )

val articleList = List(
    Article("title 1","content 1"),
    Article("title 2","content 2")
)

class TransformArticle(title: String, content: String) extends RewriteRule {
  override def transform(n: Node): Seq[Node] = n match {
    case div @ <div/> => div match {
        case elem: Elem if elem \ "@class" contains Text("title") =>
            elem copy (child = Text(title))
        case elem: Elem if elem \ "@class" contains Text("content") =>
            elem copy (child = Text(content))
        case other => other
    }
    case other => other
  }
}

val article_template =
 <div>
      <div class="title"></div>
      <div class="content"></div>
      <!-- some other markups don't know -->
 </div>

Group(
    articleList.flatMap( article => {
        new RuleTransformer(new TransformArticle(article.title, article.content)) transform article_template
    })
)


This is something lift is really good for

import net.liftweb.util.Helpers._ 

case class Article( title: String, content: String )

val articles = List(
    Article("title a","content a"),
    Article("title b","content b")
)  

val snipet =
"article *" #> articles.map { article =>
    "header h1 *" #> article.title &
    ".content *" #> article.content
}

val article_template =
<article>
    <header>
        <h1>Title</h1>
    </header>
    <section class="content">
        Content
    </section>
</article>

snipet( article_template )


Assuming that Article is defined something like:

case class Article(title: String, content: String)

and articleList as:

val articleList = List(
  Article("title a","content a"),
  Article("title b", "content b"))

You could produce the XML fragment with:

val xml: scala.xml.NodeSeq = articleList map { article => 
  <div>
    <div class="title">{article.title}</div>
    <div class="content">{article.content}</div>
  </div>
}


You can use Group to group XML elements. In XML literal it will look like this:

val xml =
  <xml:group>
    <div>
      <div class="title">title a</div>
      <div class="content">content a</div>
    </div>
    <div>
      <div class="title">title b</div>
      <div class="content">content b</div>
    </div>
  </xml:group> 

Update

You can create XML dynamically like this:

case class Article(title: String, content: String)
val articles = List(Article("A1", "A1 content"), Article("A2", "A2 content"))

val xml =
  <xml:group>{articles map { a =>
    <div>
      <div class="title">{a title}</div>
      <div class="content">{a content}</div>
    </div>
  }}</xml:group>

Update 1

Here is another variation using template. Template is just a function that returns XML. In this case I using currying in order to produce list of templates for each article (that still needs some stuff to be provided):

case class Article(title: String, content: String)
val articles = List(Article("A1", "A1 content"), Article("A2", "A2 content"))

def articleTemplate[T](article: Article)(stuff: T) =
  <div>
    <div class="title">{article title}</div>
    <div class="content">{article content}</div>

    <div class="stuff">{stuff}</div>
  </div>

val allArticles = articles map articleTemplate

val allArticlesWithStuff: NodeSeq =
  allArticles.zipWithIndex map {case (f, i) => f(i)} 


Use flatmap to add them together like this:

val xml: NodeSeq = List("Test", "Something", "Yo").flatMap(s => <a>{s}</a>)
  • With articles instead of just strings of course

Update: Works well with matching as well

val xml: NodeSeq = List("Test", "Something", "Yo", 1).flatMap{
  case s: String => <string>{s}</string>
  case i: Int => <int>{i}</int>
}
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜