anti-xml
The scala.xml library has some very annoying issues. Time for a clean-room replacement!
Anti-XML
Suppose I have an Anti-XML object, e.g.:
import com.codecommit.antixml._
val child = <child attr="val">...</child>.convert
I want to construct an XML object that contains child
as a child:
<parent foo="bar"><foo/><child attr="val">...</child><foo/></parent>
The obvious way would be
val parent : Elem = <parent foo="bar"><foo/>{ child }<foo/></parent>.convert
The problem is that Scala's XML literals don't recognize Anti-XML's objects, so child
gets converted to a string, and embedded in parent
as a text node:
<parent foo="bar"><foo/><child attr="val">...</child><foo/></parent>
How can I work around this issue?
Source: (StackOverflow)
Anti-xml will be the successor xml library in Scala. But I have found something that quirks.
Input
package com.twitter.sample
import com.codecommit.antixml._
object ReadingNamespaceXml extends Application{
val xml = <tra:route xmlns:tra="trace">
<spo:id xmlnls:spo="sport">23232322</spo:id>
<tra:service ref="go" xsi:type="ref:manualService" xmlns:ref="ServiceRef"/>
</tra:route>.convert
val route = xml \ "route"
Console println route.unselect
}
Output:
<tra:route>
<spo:id xmlnls:spo="sport">23232322</spo:id>
<tra:service xsi:type="ref:manualService" ref="go"/>
</tra:route>
So, the input xml and the output are not the same. Why?
Source: (StackOverflow)
In this question, the asker wants to transform documents like this:
<text>
The capitals of Bolivia are <blank/> and <blank/>.
</text>
Into this:
<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's zippers provide a clean solution to this problem. The following, for example, would work for renaming the blank elements:
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 doesn't work:
(q \\ "blank").zipWithIndex.map { case (el, i) => el.copy(
name = "input",
attrs = Attributes("name" -> "blank.%d".format(i + 1))
)}.unselect
Because of course once we've zipWithIndex
-ed the zipper we no longer have a zipper, just an IndexedSeq
—we can't have a Zipper[(Node, Int)]
because the definition is trait Zipper[+A <: Node] ...
.
Is there a clean way to use zip
or zipWithIndex
on an Anti-XML zipper, do some other operations with map
, etc., and end up with something that's still a zipper?
Source: (StackOverflow)
I've been surprised by how non-intuitive the standard Scala XML library is (beyond defining in-line XML and basic path tree traversal) as well as the lack of any apparent replacements. It looks like at one point anti-xml was gaining traction but it appears that development has been stale for some time.
Specifically I'm looking to manipulate the XML tree by adding and removing sub-trees, something along the lines of:
val tree1 = <root><foo>foo</foo></root>
val tree2 = <root><bar>bar</bar></root>
tree1 + tree2 == <root><foo>foo</foo><bar>bar</bar></root>
Pimping the existing Scala XML library is certainly an option but if there are existing libraries that afford this functionality I'd prefer to let them do the heavy lifting.
Do folks have recommendations on appropriate XML libraries for Scala in 2015 (i.e. >= 2.10) where this sort of manipulation is possible and straightforward?
Source: (StackOverflow)
I am cross-posting this from scala-user:
I have the following:
object XmlTest {
import com.codecommit.antixml._
implicit def toPicker(nodes: Group[Node]): Picker = new Picker(nodes)
class Picker(nodes: Group[Node]) {
def pick[A <: Node : ClassManifest]: Group[A] = nodes collect {
case a if implicitly[ClassManifest[A]].erasure.isInstance(a) => a.asInstanceOf[A]
}
}
def testCollect(elems: Group[Elem]) {
println("size before collect = " + elems.size)
val es = elems collect {
case e if e.name == "c" => println("element name is " + e.name); e
}
println("size after collect = " + es.size)
}
def main(args: Array[String]) {
val xml = XML.fromString("<a><b/><c/><d/></a>")
// this works because <a> has only elements as children
testCollect(xml.children.asInstanceOf[Group[Elem]])
// pick filters collection by type
testCollect(xml.children.pick[Elem])
}
}
When i ran it, it printed the following:
[info] size before collect = 3 // size is 3
[info] element name is c // element c matches
[info] size after collect = 1 // this is correct
[info] size before collect = 3 // size is the same as the previous case
[info] element name is c // element "c" is matched as well
[info] size after collect = 0 // this should be 1
I am at a lost here. What is going on?
Source: (StackOverflow)
Suppose I have an XML document stored as an Anti-XML Elem
:
val root : Elem =
<foo attr="val">
<bar/>
</foo>
. I want to append <baz>blahblahblah</baz>
to the root element as a child, giving
val modified_root : Elem =
<foo attr="val">
<bar/>
<baz>blahblahblah</baz>
</foo>
For comparison, in Python you can just root.append(foo)
.
I know I can append (as a sibling) to a Group[Node]
using :+
, but that's not what I want:
<foo attr="val">
<bar/>
</foo>
<baz>blahblahblah</baz>
How do I append it as the last child of <foo>
? Looking at the documentation I see no obvious way.
Similar to Scala XML Building: Adding children to existing Nodes, except this question is for Anti-XML rather than scala.xml
.
Source: (StackOverflow)
I am struggling to replace a XML element with another one using the library anti-xml. For instance, I have:
<root>
<sub>
<keep />
<replace />
<keeptoo />
</sub>
</root>
and the fragment:
<inserted key="value">
<foo>foo</foo>
<bar>bar</bar>
</inserted>
I would like to produce:
<root>
<sub>
<keep />
<inserted key="value">
<foo>foo</foo>
<bar>bar</bar>
</inserted>
<keeptoo />
</sub>
</root>
Note: The order of <sub>
children must be conserved.
Source: (StackOverflow)
What would be the best and/or simplest way to remove an element from a XML document using anti-xml?
Source: (StackOverflow)
there are a few examples for using Anti-Xml to extract information from XML documents, but none that I could find of using Anti-Xml to create XML documents. Does Anti-Xml support creating documents, or should I use another library for this (which one?). Does anyone have an example of creating an XML document with Anti-Xml?
Source: (StackOverflow)
I'd like to see a rewrite of bellow script using http://anti-xml.org instead of Scala XML.
This is an excerpt from Chapter 10. Herding XML in Scala - http://ofps.oreilly.com/titles/9780596155957/HerdingXMLInScalaDSLs.html
// code-examples/XML/reading/pattern-matching-script.scala
import scala.xml._
val someXML =
<sammich>
<bread>wheat</bread>
<meat>salami</meat>
<condiments>
<condiment expired="true">mayo</condiment>
<condiment expired="false">mustard</condiment>
</condiments>
</sammich>
someXML match {
case <sammich>{ingredients @ _*}</sammich> => {
for (cond @ <condiments>{_*}</condiments> <- ingredients)
println("condiments: " + cond.text)
}
}
Thanks
Source: (StackOverflow)
To test a method that would transform Text elements in an XML document I wrote two very simple Selectors and applied map/toUpperCase on the resulting Zipper. The result should be that all text elements except those excluded via the first Selector are transformed to upper case. But it only works for furthest-down Text elements. Here's the code:
scala> import com.codecommit.antixml._
import com.codecommit.antixml._
scala> val elemSelector = Selector({case x:Elem if x.name != "note" => x})
elemSelector: com.codecommit.antixml.Selector[com.codecommit.antixml.Elem] = <function1>
scala> val textSelector = Selector({case x:Text => x})
textSelector: com.codecommit.antixml.Selector[com.codecommit.antixml.Text] = <function1>
scala> val xml = XML.fromString("<tei><div><p>this<note>not<foreign lang=\"greek\">that</foreign>not</note></p><p>those<hi>these</hi></p></div></tei>")
xml: com.codecommit.antixml.Elem = <tei><div><p>this<note>not<foreign lang="greek">that</foreign>not</note></p><p>those<hi>these</hi></p></div></tei>
scala> val zipper = xml \\ elemSelector \ textSelector
zipper: com.codecommit.antixml.Zipper[com.codecommit.antixml.Text] = thisthatthosethese
scala> val modified = zipper.map(t => new Text(t.text.toUpperCase))
modified: com.codecommit.antixml.Zipper[com.codecommit.antixml.Text] = THISTHATTHOSETHESE
scala> val result = modified.unselect.unselect
result: com.codecommit.antixml.Zipper[com.codecommit.antixml.Node] = <tei><div><p>this<note>not<foreign lang="greek">THAT</foreign>not</note></p><p>those<hi>THESE</hi></p></div></tei>
So, in the second to last command, the upper case is applied to all targeted Text elements, but after stepping out of the zipper, only two of the four elements are transformed. I've tried it with <hi/>
instead of <hi>these</hi>
and then those
gets capitalized. Any idea what's the problem here?
I am using the arktekk.no fork for Scala 2.10.3.
Source: (StackOverflow)