Scala XML.loadString vs文字表达式

时间:2010-12-09 18:23:02

标签: xml string scala comparison transformation

我一直在尝试使用Scala和XML,我发现使用XML.load(或loadString)创建的XML标记与将其写为文字的行为之间存在奇怪的差异。这是代码:

import scala.xml._
// creating a classical link HTML tag
val in_xml = <link type="text/css" href="/css/main.css" rel="stylesheet" xmlns="http://www.w3.org/1999/xhtml"></link>
// The same as a String
val in_str = """<link type="text/css" href="/css/main.css" rel="stylesheet" xmlns="http://www.w3.org/1999/xhtml"></link>"""
// Convert the String into XML
val from_str = XML.loadString(in_str)

println("in_xml  : " + in_xml)
println("from_str: "+ from_str)
println("val_xml == from_str: "+ (in_xml == from_str))
println("in_xml.getClass() == from_str.getClass(): " +
  (in_xml.getClass() == from_str.getClass()))

在这里,输出:

in_xml  : <link href="/css/main.css" rel="stylesheet" type="text/css" xmlns="http://www.w3.org/1999/xhtml"></link>
from_str: <link rel="stylesheet" href="/css/main.css" type="text/css" xmlns="http://www.w3.org/1999/xhtml"></link>
val_xml == from_str: false
in_xml.getClass() == from_str.getClass(): true

类型相同。但是没有平等。属性的顺序会发生变化。它永远不会与原来的相同。文字的属性按字母顺序排序(只有危险?)。

如果两种解决方案在尝试转换它们时行为不同,那么这不会成为问题。我在How to change attribute on Scala XML Element从Daniel C. Sobral那里获得了一些有趣的代码并编写了我自己的规则,以便删除“href”属性的第一个斜杠。 RuleTransformer适用于in_xml,但对from_str没有影响!

不幸的是,我的大部分程序都必须通过XML.load(...)读取XML。所以,我被困住了。有人知道这个话题吗?

致以最诚挚的问候,

亨利

2 个答案:

答案 0 :(得分:1)

从我所看到的情况来看,in_xmlfrom_str不相等,因为属性的顺序不同。这很不幸,并且由于编译器创建XML的方式。这导致属性不同:

scala> in_xml.attributes == from_str.attributes
res30: Boolean = false

您可以看到,如果替换属性,则比较将起作用:

scala> in_xml.copy(attributes=from_str.attributes) == from_str
res32: Boolean = true

话虽如此,我不清楚为什么会在替换href属性的代码中导致不同的行为。事实上,我怀疑属性映射的工作方式有问题。例如,如果我将in_str替换为:

val in_str = """<link type="text/css" rel="stylesheet" href="/css/main.css" 
xmlns="http://www.w3.org/1999/xhtml"></link>"""

工作正常。可能是Daniel的属性代码仅在属性位于MetaData的头部位置时才有效吗?


附注:除非in_xmlnull,否则equals==将返回相同的值。 ==版本将在调用equals之前检查第一个操作数是否为空。

答案 1 :(得分:0)

进一步测试: 也许,我最初的平等测试不合适:

in_xml == from_str

如果我测试:

in_xml.equals(in_xml)

我也变得虚假。也许,我应该使用另一种测试方法(比如对应,但我没有找到我应该使用的谓词作为第二个参数...)

那就是说,如果我在REPL中测试以下内容

<body id="1234"></body> == XML.loadString("<body id=\"1234\"></body>")

即使没有调用equals方法,我也是如此......

回到我的初始示例:我定义了重写规则

def unSlash(s: String) = if (s.head == '/') s.tail else s
val changeCSS = new RewriteRule {
    override def transform(n: Node): NodeSeq = n match {
        case e: Elem if (n \ "@rel").text == "stylesheet" =>
            e.copy(attributes = mapMetaData(e.attributes) {
                case g @ GenAttr(_, key, Text(v), _) if key == "href" =>
                    g.copy(value = Text(unSlash(v)))
                case other => other
            })
        case n => n
    }
}

它使用Daniel C. Sobral在How to change attribute on Scala XML Element定义的辅助类/方法。如果我申请:

new RuleTransformer(changeCSS).transform(in_xml)
new RuleTransformer(removeComments).transform(from_str)

我使用in_xml获得了预期的结果,但没有使用from_str修改...