I ran into this behavior which surprised me. Essentially, if I create "the same" XML Elem
from two different XML literals, they fail to equal one another. The unique thing here is that I am using a Boolean
in one and a String
in the other.
scala> import scala.xml._
import scala.xml._
scala> val t: Boolean = true
t: Boolean = true
scala> val fromBoolean: Elem = <b>{t}</b>
fromBoolean: scala.xml.Elem = <b>true</b>
scala> val fromString = <b>true</b>
fromString: scala.xml.Elem = <b>true</b>
scala> fromString == fromBoolean
res0: Boolean = false
Is this the expected behavior?
It seems that Scala is storing the underlying type and a Boolean doesn't strictly equal a String.
Is this correct interpretation, and can anyone explain what exactly is going on here? I couldn't find a way to inspect the underlying type within the two nodes. If I look at the children they just appear to be Node
s.
scala> fromString.child(0)
res1: scala.xml.Node = true
scala> fromBoolean.child(0)
res2: scala.xml.Node = true
Your interpretation is correct. The child of fromString
is scala.xml.Text
, which extends scala.xml.Atom[String]
:
scala> fromString.child(0).getClass.getName
res1: String = scala.xml.Text
scala> fromString.child(0).asInstanceOf[xml.Atom[_]].data.getClass.getName
res2: String = java.lang.String
And the child of fromBoolean
is scala.xml.Atom[Boolean]
:
scala> fromBoolean.child(0).getClass.getName
res3: String = scala.xml.Atom
scala> fromBoolean.child(0).asInstanceOf[xml.Atom[_]].data.getClass.getName
res4: String = java.lang.Boolean
So the data
of fromString
's child Atom
has type String
, and the data
of fromBoolean
's Atom
has type Boolean
. The equality implementation of Atom
(scala.xml.Atom#strict_==
) just compares the data
directly, and so the String
and the Boolean
compare unequal.
I'm not sure what's the purpose of distinguishing the types of Atom
data. It seems to me that Atom
should compare toString
values of its data anyway. So this behaviour might be a bug.
As a workaround, I can advise to convert the atom values to String
explicitly. The equality works in that case:
scala> <b>{true.toString}</b> == <b>true</b>
res5: Boolean = true
Scala xml comparison does have more quirks though:
scala> <foo:b xmlns:foo="foo"/> == <foo:b xmlns:foo="bar"/>
res6: Boolean = true
scala> <b>{"<"}</b> == <b><</b>
res7: Boolean = false
scala> <b>></b> == <b>></b>
res8: Boolean = false
So it may be worth it to try implementing comparison manually.