2010-12-09 4 views
8

Ich habe mit Scala und XML experimentiert und ich fand einen seltsamen Unterschied im Verhalten zwischen einem XML-Tag erstellt mit XML.load (oder loadString) und schreiben es als Literal. Hier ist der Code:Scala XML.loadString vs Literal Ausdruck

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())) 

Und hier die Ausgabe:

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 

Die Typen sind die gleichen. Aber es gibt keine Gleichheit. Die Reihenfolge der Attribute ändert sich. Es ist nie dasselbe wie das Original. Die Attribute des Literals sind alphabetisch sortiert (nur Gefahr?).

Dies wäre kein Problem, wenn sich beide Lösungen nicht anders verhalten würden, wenn ich versuche, sie zu transformieren. Ich habe einen interessanten Code von Daniel C. Sobral unter How to change attribute on Scala XML Element gelesen und meine eigene Regel geschrieben, um den ersten Schrägstrich des Attributs "href" zu entfernen. Der RuleTransformer funktioniert gut mit dem in_xml, hat aber keinen Einfluss auf from_str!

Leider müssen die meisten meiner Programme dort XML über XML.load (...) lesen. Also, ich stecke fest. Weiß jemand von diesem Thema?

Mit freundlichen Grüßen,

Henri

+1

Dies ist definitiv ein Fehler. Nicht, dass das hilft ... –

+0

Scala XML-Literale haben bekannte Probleme mit der Reihenfolge der Attribute. Sie könnten http://lampsvn.epfl.ch/trac/scala/ticket/2735 abstimmen. (Ich weiß nicht, ob sie tatsächlich auf Stimmen achten, aber es kann nicht schaden.) – Steve

+0

Sie achten nicht auf Stimmen, obwohl sie auf Aktivität achten (Leute abonnieren, Kommentare machen, etc.). Trotzdem tut es nicht weh. Ich persönlich abonniere jeden Fehler, für den ich mich interessiere, und verbessere jeden, der meiner Meinung nach besonders wichtig ist. –

Antwort

0

Einige weitere Tests: Vielleicht, meine erste Gleichheitstest nicht geeignet ist:

in_xml == from_str 

und wenn ich testen:

in_xml.equals(in_xml) 

Ich werde auch falsch. Vielleicht sollte ich ein anderes Testverfahren verwenden (wie entspricht, aber ich habe nicht herausfinden, was ein Prädikat ich als zweiten Parameter verwenden sollte ...)

Das heißt, wenn ich folgendes in der REPL testen

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

ich wahr bekommen, auch ohne die Methode equals Aufruf ...

Zurück zu meinem ersten Beispiel: I definiert eine Rewrite-Regel

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

Es Klassen Helfer verwendet/Methoden definiert von Daniel C. Sobral um How to change attribute on Scala XML Element. Wenn ich mich bewerben:

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

ich das erwartete Ergebnis mit in_xml, aber keine Änderung mit from_str ...

1

Von dem, was ich sehen kann, in_xml und from_str sind nicht gleich, da die Reihenfolge der Attribute ist anders. Dies ist unglücklich und aufgrund der Art, wie das XML vom Compiler erstellt wird.Das bewirkt, dass die Attribute anders sein:

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

Sie sehen können, dass, wenn Sie die Attribute ersetzen der Vergleich funktioniert:

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

Mit dieser sagte, ich bin mir nicht klar, warum das würde dazu führen, ein anderes Verhalten in dem Code, der das href Attribut ersetzt. In der Tat vermute ich, dass etwas mit der Art und Weise, wie Attributzuordnungen funktionieren, nicht stimmt. Zum Beispiel ersetzen, wenn ich die in_str mit:

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

Es funktioniert gut. Könnte es sein, dass der Attributcode von Daniel nur funktioniert, wenn sich das Attribut in der Kopfposition MetaData befindet?


Randbemerkung: es sei denn, in_xmlnull ist, equals und == würde den gleichen Wert zurück. Die == Version überprüft, ob der erste Operand null ist, bevor equals aufgerufen wird.