2012-10-09 12 views
23

Ich habe folgendes minimal JavaScript-Fragment:Chrome 22 gibt ungültige XML, wenn Attribute haben einen XLink-Namensraum

var xml = '<El a:title="T" a:href="H" xmlns:a="http://www.w3.org/1999/xlink" />'; 
var dom = new DOMParser().parseFromString(xml, 'text/xml'); 
xml = new XMLSerializer().serializeToString(dom); 

Wenn ich den Code in den meisten Browsern ausgeführt werden (so fügen Sie ihn in Ihrem Browser JavaScript-Konsole), Das geparste-serialisierte XML entspricht dem Original. Zum Beispiel auf Chrome 8 I erhalten:

<El xmlns:a="http://www.w3.org/1999/xlink" a:title="T" a:href="H"/> 

jedoch auf Chrome 22 die gleiche Codefragment ändert sich die XML:

<El xmlns:a="http://www.w3.org/1999/xlink" xlink:title="T" xlink:href="H"/> 

Beachten Sie, dass die Namespacepräfix xlink durch den Titel und href-Attribute verwendet wird, nicht irgendwo definiert, so dass das XML jetzt ungültig ist. Wie Sie sich vorstellen können, verursacht dies alle Arten von Problemen für Code, der versucht, das XML anschließend zu verwenden.

Ist dies ein Fehler im XMLSerializer oder fehlen mir einige Feinheiten, wie das DOM serialisiert werden soll?

Hat auch jemand eine Problemumgehung gefunden, die ich in Code einfügen kann, im Gegensatz zu der XML-Übereinstimmung die scheinbare Präferenz, xlink als das Präfix für den XLink-Namespace zu verwenden?

aktualisiert

Ich habe einige zusätzlichen Tests und das Problem scheint durch die Tatsache verursacht wird, dass der XMLSerializer den Namespace XLink erkennt und besteht darauf, für sie einen xlink Präfix auf ausgeben, ohne richtig, dass die Vorsilbe Registrierung.

Also dieses Fragment funktionieren:

var xml = '<El a:title="T" a:href="H" xmlns:a="any-other-namespace-uri" />'; 
var dom = new DOMParser().parseFromString(xml, 'text/xml'); 
xml = new XMLSerializer().serializeToString(dom); 

Also hier änderte ich die Namespace-URL zu etwas weniger bekannt und der Ausgang ist jetzt gültig:

Das folgende Fragment funktioniert auch :

Also in diesem Fall verwenden wir das "erwartete" Präfix für den XLink-Namespace und es dann ohne Probleme serialisiert:

<El xmlns:a="http://www.w3.org/2000/xlink" a:title="T" a:href="H"/> 
+4

Ich bin mir nicht ganz sicher, was die Antwort ist, aber dieses Problem kann verwandt sein: http://stackoverflow.com/questions/8979267/xmlserializer-strips-xlink-from-xlinkhtml-svg-image-tag – Barbarrosa

+0

Danke für den Zeiger Barbarrosa. Ich hatte Berichte über das SVG/XLink-Handling von Chrome gesehen. Aber ich fürchte wirklich, dass die "Lösung" dafür verantwortlich sein könnte, was das Problem verursacht hat. Mit Ihrem Link kann ich vielleicht sogar einen Schritt näher an den fehlerhaften Code kommen, also danke! –

Antwort

7

Ich bin immer noch ziemlich sicher, dass es ein Fehler in Chrome ist XMLSerializer, höchstwahrscheinlich eingeführt, während die SVG handling of XLink attributes that Barbarrosa pointed to Adressierung. Aber angesichts der fehlenden Reaktion auf die bug report, die ich dafür gemacht habe, mussten wir weitermachen und das Problem lösen.

Wir arbeiten, um das Problem durch Aufruf dieser Funktion auf dem documentElement:

function EnsureXLinkNamespaceOnElement(element) 
{ 
    if (element.nodeType == 1) 
    { 
    var usesXLinkNamespaceUri = false; 
    var hasXLinkNamespacePrefixDefined = false; 
    for (var i = 0; i < element.attributes.length; i++) 
    { 
     var attribute = element.attributes[i]; 
     if (attribute.specified) 
     { 
     if (attribute.name.indexOf("xmlns:xlink") == 0) 
     { 
      hasXLinkNamespacePrefixDefined = true; 
     } 
     else if (attribute.namespaceURI == "http://www.w3.org/1999/xlink") 
     { 
      usesXLinkNamespaceUri = true; 
     } 
     } 
    } 
    if (usesXLinkNamespaceUri && !hasXLinkNamespacePrefixDefined) 
    { 
     element.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); 
    } 

    for (i = 0; i < element.childNodes.length; i++) 
    { 
     EnsureXLinkNamespaceOnElement(element.childNodes[i]); 
    } 
    } 
} 

Die Funktion stellt sicher, einfach, dass das xmlns:xlink Attribut auf ein beliebiges Element deklariert wird, die in dem XLink-Namensraum zugeschrieben hat. Da die Funktion die Baumstruktur durchläuft und daher ziemlich zeitaufwendig sein kann, rufe ich sie nur für die Chrome-Versionen 22 und höher auf.

Beachten Sie, dass Sie in den meisten Fällen auch einfach den Namespace xmlns:xlink auf dem Dokumentelement hinzufügen können, da er von dort geerbt wird.Aber in unserem Fall gab es einen anderen Code, der das Dokumentelement mit einem regulären Ausdruck löscht. Daher haben wir uns entschieden, auf Nummer sicher zu gehen und das Attribut einfach überall dort hinzuzufügen, wo es benötigt wird.

Update (20130324):

Die bug fixiert wurde und überprüft in Chrome Canary 26. Ich habe in der Lage, es selbst 25.0.1364.172 m auch auf Version zu überprüfen.