2010-12-09 1 views
8

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

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 

типы одинаковы. Но не существует равенства. Изменяется порядок атрибутов. Это не то же самое, что и оригинальное. Атрибуты litteral сортируются по алфавиту (только опасность?).

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

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

С наилучшими пожеланиями,

Анри

+1

Это определенно ошибка. Не то, что помогает ... – 2010-12-09 23:42:02

ответ

0

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

in_xml == from_str 

и если я проверяю:

in_xml.equals(in_xml) 

Я тоже получаю ложь. Может быть, я должен использовать другой метод тестирования (например, соответствует, но я не нашел, что предикат следует использовать в качестве второго параметра ...)

Это сказало, если я проверить следующее в РЕПЛ

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

Он использует вспомогательные классы/методы определяемый Даниэлем С. Собралем по адресу How to change attribute on Scala XML Element. Если я применяю:

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

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

1

Из того, что я могу видеть, 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>""" 

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


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