Scala对XML文字的支持非常适合生成类型安全的XHTML标记;然而,当给定块中包含非xml-literal代码时,必须将文字与++
运算符一起附加,这是一个烦人的问题。
例如,这会爆发:
import scala.xml._
def getNode() = <div>foo</div>
val node: NodeSeq =
<div>bar</div>
<div>baz</div>{
getNode()
}
error: type mismatch;
found : scala.xml.Elem
required: Int
getNode()
虽然以下内容进行了编译,但请注意非getNode()
,否则只有尾部Elem
为生成。
import scala.xml._
def getNode() = <div>foo</div>
val node: NodeSeq =
<div>bar</div>
<div>baz</div> ++ {
getNode()
}
<div>lonely node</div>
node: scala.xml.NodeSeq = NodeSeq(<div>bar</div>, <div>baz</div>, <div>foo</div>)
res6: scala.xml.Elem = <div>lonely node</div>
那么,有没有办法隐式链接XML文字,其中散布着XML,默认返回Scala代码?由于上面的示例编译但实际上已被破坏,因此在处理XML文字时会出现虚假的安全感。
明确强制附加文字的一种方法是执行以下操作:
import scala.xml._
def getNode() = <div>foo</div>
def nodify(elems: Elem*): NodeSeq = elems
nodify(
<div>bar</div>,
<div>baz</div>,
getNode(),
<div>not lonely node</div>
)
res8: scala.xml.NodeSeq = NodeSeq(<div>bar</div>, <div>baz</div>, <div>foo</div>, <div>not lonely node</div>)
但这并不是很好,因为你必须在方法调用中包装XML文字块。至少它强制附加,不会没有编译。
很想拥有一个干净的XHTML标记DSL,如果你有它,请提供秘密酱! (或者如果我遗漏了一些令人目眩的明显事物,请提醒我。)
由于
答案 0 :(得分:1)
我知道处理这种情况的最好方法是将表达式包装在no-op <xml:group/>
元素中:
import scala.xml._
def getNode() = <div>foo</div>
val node: NodeSeq = <xml:group>
<div>bar</div>
<div>baz</div>{
getNode()
}
</xml:group>
的产率:
scala> node
res0: scala.xml.NodeSeq =
<div>bar</div>
<div>baz</div><div>foo</div>
答案 1 :(得分:1)
作为复习(对我而言),您的大括号不是嵌入式Scala表达式,它必须是标记内容。
您的错误消息显示您正在调用NodeBuffer.apply{f}
,以便进行以下增强。
如果连续有两个元素,则会得到NodeBuffer
,编译器会使用&+
构建它们。
scala> import xml._
import xml._
scala> def f = <div>foo</div>
f: scala.xml.Elem
scala> implicit class `autoappend Elem`(b: NodeBuffer) { def apply(e: Elem) = b &+ e }
defined class autoappend$u0020Elem
scala> :pa
// Entering paste mode (ctrl-D to finish)
val n =
<div>bar</div>
<div>baz</div>{
f
}
// Exiting paste mode, now interpreting.
n: scala.xml.NodeBuffer = ArrayBuffer(<div>bar</div>, <div>baz</div>, <div>foo</div>)
scala> val nn: NodeSeq = n
nn: scala.xml.NodeSeq = NodeSeq(<div>bar</div>, <div>baz</div>, <div>foo</div>)
你仍然可以:
scala> n(1)
res0: scala.xml.Node = <div>baz</div>
scala> n(2)
res1: scala.xml.Node = <div>foo</div>
这些天不是每个人都使用插补器吗?这是一种时尚还是潮流?
答案 2 :(得分:0)
所以,经过一段时间的黑客攻击后,我发现使用varargs的显式方法是可行的方法。
检查出来,为了生成html标记,你通常会在布局或部分内容中执行此操作,例如:
object Crud extends Layout{
def apply[T <: Seq[Node]](title: String, args: (Symbol,String)*)(body: T*) {
header(...)
<body>
{body}
</body>
footer(...)
}
}
然后你想隐式链接包含上面布局主体的标记。根据上面的答案,没有优雅的方法来实现隐式链接。但是,使用var args,你可以吃蛋糕,也可以吃。在实现varargs方法之前,创建Foos的表单看起来像:
Crud(title, ...)(
<h1>{title}</h1>
<div> </div> ++
withForm(routes.Foo.save)(
fields(form) ++
crud.submit("Create")
) ++
css("foo") ++
css("bar")
)
零编译时保证不会遗忘一个++,完全容易出错。使用上面的varargs Crud应用签名foo表单创建看起来像这样:
Crud(title, ...)(
<h1>{title}</h1>
<div> </div>,
withForm(routes.Foo.save)(
fields(form),
crud.submit("Create")
),
css("foo"),
css("bar")
)
如果省略逗号,则会出现编译时错误,正是我们想要的。在“加号”方面,如果需要,您仍然可以使用++,因为Seq [Node]位于Scala XML类型层次结构的顶部,因此Elem,NodeSeq等无关紧要,无论它是什么,它必须从中派生出来Seq [Node]你很高兴,哇喔; - )