Scala XML.loadString против буквального выражения - PullRequest
8 голосов
/ 09 декабря 2010

Я экспериментировал со Scala и XML и обнаружил странную разницу в поведении между тегом XML, созданным с помощью XML.load (или loadString), и записью его как литерал.Вот код:

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

Типы одинаковы.Но нет равенства.Порядок атрибутов меняется.Это никогда не совпадает с оригиналом.Атрибуты литерала отсортированы по алфавиту (только опасность?).

Это не будет проблемой, если оба решения не будут вести себя по-разному, когда я пытаюсь их преобразовать.Я взял интересный код от Дэниела С. Собрала на Как изменить атрибут в XML-элементе Scala и написал свое собственное правило, чтобы убрать первую косую черту атрибута "href".RuleTransformer хорошо работает с in_xml, но не влияет на from_str!

К сожалению, большинству моих программ приходится читать там XML через XML.load (...).Итак, я застрял.Кто-нибудь знает об этой теме?

С уважением,

Анри

Ответы [ 2 ]

1 голос
/ 11 декабря 2010

Из того, что я вижу, in_xml и from_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>"""

Работает нормально. Может ли быть так, что код атрибута от Даниэля работает, только если атрибут находится в позиции головы MetaData?


Примечание: если in_xml не равно null, equals и == не вернут одинаковое значение. Версия == проверит, является ли первый операнд нулевым, перед вызовом equals.

0 голосов
/ 10 декабря 2010

Некоторые дальнейшие испытания: Возможно, мой первоначальный тест на равенство не подходит:

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
    }
}

Он использует вспомогательные классы / методы, определенные Даниэлем С. Собралом на Как изменить атрибут в XML-элементе Scala . Если я подам заявление:

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

Я получаю ожидаемый результат с in_xml, но без изменения с from_str ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...