我试图取代XML块,需要沿途的蓄电池。 说我有一个填充式的空白存储为XML,像这样的问题:
val q = <text>The capitals of Bolivia are <blank/> and <blank/>.</text>
在某些时候,我会想将这些空白转换成HTML输入元素,我需要能够区分第一和第二,所以我可以检查它们。 (忽略的是,在这种情况下,两国首都可以以任何顺序出现的事实 - 这是一个头痛的,我会处理后)
由于在计算器上一些可爱的回答,我产生了以下解决方案:
import scala.xml._
import scala.xml.transform._
class BlankReplacer extends BasicTransformer {
var i = 0
override def transform(n: Node): NodeSeq = n match {
case <blank/> => {
i += 1
<input name={ "blank.%d".format(i) }/>
}
case elem: Elem => elem.copy(child=elem.child.flatMap(transform _))
case _ => n
}
}
而这个效果相当好。 我要创建一个new BlankReplacer()
我要开始重新编号每一次,但它几乎作品:
scala> new BlankReplacer()(q)
res6: scala.xml.Node = <text>The capitals of Bolivia are <input name="blank.1"></input> and <input name="blank.2"></input>.</text>
这里的问题。 有一个简单的方法,以避免我每次都做突变我更换<blank/>
我有什么不罢工我可怕,但我认为这可能是清洁的,如果我没有创建的新实例BlankReplacer
每次我有一个问题转换为HTML时类。 我敢肯定有某种方式把它变成一个蓄电池,但我不知道该怎么做。
谢谢! 托德
秤的Xml提供折叠路径,让你“修改”一棵树,积累...
import scales.utils._
import ScalesUtils._
import scales.xml._
import ScalesXml._
// the xml example
val q = <("text") /( "The capitals of Bolivia are ", <("blank")," and ",<("blank"),".")
// which elems to fold on?
val p = top(q) \\* "blank"
val f = foldPositions(p, p.size){ // size is used as the starting point for the fold
case (question, path) =>
(question - 1, Replace( <("input") /@ ("name" -> ("blank."+question) )) )
}
// f is an either, so we assuming its working here, and ._1 is the accumalator, _.2 the Path
val newTree = f.left.get._2.tree
唯一的怪癖是,它积聚在反向文档顺序,也有不可累积版本。 这允许变换的组合时,有些是破坏性的(例如改变subchild,然后删除它在另一个转型都只是工作)。
输入的褶皱本身就是路径的可迭代的,只要他们在同一棵树,让您查询,您认为合适的结合。
看到这里,了解如何能够折叠秤XML的更多细节
这恰恰是那种这个问题反XML的拉链设计来解决 :
换句话说,我们开始与XML树,我们下钻成树使用选择,我们得出这一结果与一些修改设定的新版本(在我们的情况下,一个新的属性),现在我们想回去树我们原本,除非我们取得了肠子一路下滑的修改。 这是一个拉链是什么?
你的情况,你可以这样做:
import com.codecommit.antixml._
def replaceBlanks(el: Elem) = {
var i = 0
(el \\ "blank").map { _ =>
i += 1
<input name={"blank.%d".format(i)}/>.convert
}.unselect
}
或者你可以避开var
使用的伎俩在这个答案 :
def replaceBlanks(el: Elem) = {
val blanks = el \\ "blank"
(0 until blanks.size).foldLeft(blanks) {
case (z, i) => z.updated(i, z(i).copy(
name = "input",
attrs = Attributes("name" -> "blank.%d".format(i + 1)))
)
}.unselect
}
现在,我们可以应用方法的元素(将其转换为后com.codecommit.antixml.Elem
):
scala> println(replaceBlanks(q.convert))
<text>The capitals of Bolivia are <input name="blank.1"/> and <input name="blank.2"/>.</text>
诀窍是,我们可以使用\\
向下挖掘到树,就像scala.xml
,但不像scala.xml
我们可以进行修改,由此产生的“节点集”(实际上是一个拉链),然后把它们放回其原来的环境中使用unselect
。