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?
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.
I think the problem lies in xml.MetaData
or its subclass xml.Attribute
. When comparing two Elem
s, 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.Elem
s, they will be equal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With