Core_Dumped
Core_Dumped

Reputation: 4699

Find all nodes of a particular label in Scala and replace them

I have an XML node:

<a>
    <b>
        <c>
            foo
        </c>
    </b>
    <b2>
           bar
   </b2>
</a>

I need to recursively go through every child and find a label, say in this case b and replace it with another label with some other text say <b3>baz</b3>, so that the final result looks like:

<a>
    <b3>
           baz
    </b3>
    <b2>
           bar
   </b2>
</a>

How can I make this happen?

Upvotes: 1

Views: 406

Answers (2)

pyanzin
pyanzin

Reputation: 120

Naive recursive implementation:

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>)

Upvotes: 0

Travis Brown
Travis Brown

Reputation: 139038

There's not really any nice way to do this with the standard library, but something like the following approach will work:

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
  }
)

I.e., we descend through the tree checking whether each element is a b, replacing it if it is, and moving on to its children if it's not.

This is a really nice use case for zippers, which are designed to make updating immutable data structures more elegant. For example, using Anti-XML (which is unfortunately no longer maintained), you could write the following:

(elem \\ "b").map(_ => <b3>baz</b3>.convert).unselect.head

You make a selection into the tree, make some changes, and then move back to the top with unselect. If you're interested in this approach, Scales XML is actively maintained and provides another Scala XML zipper implementation (although it's syntactically a little more bulky than Anti-XML's).

Upvotes: 2

Related Questions