Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a bug in scala.xml.Elem?

Tags:

xml

scala

Mapping a Set[String] to attributes of a Set[Elem] works fine with one attribute, but seems to fail with multiple attributes when one of them is shared:

scala> val s1=Set("A","B","C")
s1: scala.collection.immutable.Set[java.lang.String] = Set(A, B, C)

scala> s1.map((a:String)=>{<X w={a}></X>})
res3: scala.collection.immutable.Set[scala.xml.Elem] = Set(<X w="A"></X>, <X w="B"></X>, <X w="C"></X>)

scala> s1.map((a:String)=>{<X w={a} k="SSS"></X>})
res4: scala.collection.immutable.Set[scala.xml.Elem] = Set(<X k="SSS" w="A"></X>)

What happened to B & C?

Or is my understanding of equals on Elems wrong?

like image 679
Jim Avatar asked Oct 24 '22 23:10

Jim


2 Answers

This does appear to be a bug, albeit a very strange one. I would guess it's a bug in Set and not Elem, but I can't speak with any authority on that point.

like image 170
Daniel Spiewak Avatar answered Nov 27 '22 04:11

Daniel Spiewak


I think the problem lies in xml.MetaData or its subclass xml.Attribute. When comparing two Elems, it is checked for equality of the xml prefix, the label, the attributes and the Node’s children.

Now, xml.MetaData has kind of a strange implementation underneath, it contains itself and at the same time a linked list of attributes. That means that, for example:

scala >val elem = <e x="a" y="b"></e>
elem: scala.xml.Elem = <e y="b" x="a"></e>

scala> elem.attributes
res50: scala.xml.MetaData =  y="b" x="a"

scala> elem.attributes.toSet
res51: Set[scala.xml.MetaData] = Set( y="b" x="a",  x="a")

E.g. it generates a list of itself with the head attribute removed.

The equality check in MetaData looks like this

this.toSet == other.toSet

which works okay but is overridden in the Attribute class. (We can’t see it in the REPL, but our elem.attributes really is an Attribute.) There, the code only does this

(this.pre == other.pre) && (this.key == other.key) && (this.value sameElements other.value)

Which would be fine, if the attributes list were converted to a Set before but it isn’t and so only the first element in the attributes list is checked for equality. And thus, if the head element in the internal linked list of attributes happens to be the same element for two xml.Elems, they will be equal.

like image 25
Debilski Avatar answered Nov 27 '22 02:11

Debilski