我有一个XML节点:
<a>
<b>
<c>
foo
</c>
</b>
<b2>
bar
</b2>
</a>
我需要以递归方式遍历每个孩子并找到一个标签,比如说b
,并将其替换为另一个带有其他文字的标签<b3>baz</b3>
,以便最终结果如下:
<a>
<b3>
baz
</b3>
<b2>
bar
</b2>
</a>
我怎样才能实现这一目标?
答案 0 :(得分:2)
使用标准库没有任何好的方法可以做到这一点,但是类似下面的方法会起作用:
def replaceAllBs(elem: Elem): Elem = elem.copy(
child = elem.child.map {
case elem: Elem if elem.label == "b" => <b3>baz</b3>
case elem: Elem => replaceAllBs(elem)
case other => other
}
)
即,我们通过树来检查每个元素是否为b
,如果是,则替换它,如果不是则继续使用它。
这是zippers的一个非常好的用例,旨在使更新不可变数据结构更加优雅。例如,使用Anti-XML(遗憾的是不再维护),您可以编写以下内容:
(elem \\ "b").map(_ => <b3>baz</b3>.convert).unselect.head
您在树中进行选择,进行一些更改,然后使用unselect
移回到顶部。如果您对这种方法感兴趣,Scales XML会得到积极维护并提供另一个Scala XML拉链实现(尽管它在语法上比Anti-XML更笨重)。
答案 1 :(得分:0)
天真的递归实现:
import scala.xml.{Elem, Node}
def replace(xml: Node)(p: Node => Boolean)(elem: Node): Node = xml match {
case x: Node if p(x) => elem
case Elem(prefix, label, attribs, scope, child @ _*) =>
Elem(prefix, label, attribs, scope, child.map(replace(_)(p)(elem)): _*)
case x: Node => x
}
val xml = <a><k/><b><c>text</c></b></a>
replace(xml)(_.label == "c")(<z>TEXT</z>)