Anti-XML Zipper

To this question , the asker wants to convert the documents as follows:

<text> The capitals of Bolivia are <blank/> and <blank/>. </text> 

In it:

 <text> The capitals of Bolivia are <input name="blank.1"> and <input name="blank.2">. </text> 

As I noted in my answer there , Anti-XML zippers provide a clean solution to this problem. For example, to rename empty elements, the following will work:

 import com.codecommit.antixml._ val q = <text>The capitals of Bolivia are <blank/> and <blank/>.</text>.convert (q \\ "blank").map(_.copy(name = "input")).unselect 

Unfortunately, the following does not work:

 (q \\ "blank").zipWithIndex.map { case (el, i) => el.copy( name = "input", attrs = Attributes("name" -> "blank.%d".format(i + 1)) )}.unselect 

Due to the fact that as soon as we get a zipWithIndex -life zipper, we no longer have a zipper, just IndexedSeq - we cannot have Zipper[(Node, Int)] , because the definition is trait Zipper[+A <: Node] ...

Is there a clean way to use zip or zipWithIndex on the Anti-XML splash screen, do some other map operations, etc., and end up with something else with a zipper?

+3
source share
1 answer

I can't think of a direct way to achieve what you need, but if you want to go for a lower level function, you can use fold , for example:

 val blanks = q \\ "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 

Please note that the zipper is a container with random access, so efficiency should not be a problem in this case.

+2
source

All Articles