2012-10-09 7 views
23

Ho il seguente minimo frammento di JavaScript:Chrome 22 uscite XML non valida quando gli attributi hanno un namespace XLink

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

Quando eseguo il codice nella maggior parte dei browser (basta incollarlo in console JavaScript del browser), l'XML parsed-then-serialized è equivalente all'originale. Per esempio su Chrome 8 ottengo:

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

Tuttavia su Chrome 22 lo stesso frammento di codice cambia il XML:

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

Nota che il prefisso namespace xlink utilizzato dal titolo e href attributi non è definito ovunque, quindi l'XML non è più valido. Come probabilmente puoi immaginare, questo causa tutti i tipi di problemi per il codice che tenta di utilizzare successivamente l'XML.

Si tratta di un bug in XMLSerializer o mi mancano alcune complessità su come il DOM deve essere serializzato?

Inoltre, qualcuno ha trovato una soluzione alternativa che è possibile inserire nel codice, al contrario di fare in modo che XML corrisponda alla preferenza apparente di utilizzare xlink come prefisso per lo spazio dei nomi XLink?

Aggiornamento

Ho fatto qualche test aggiuntivi e il problema sembra essere causato dal fatto che il XMLSerializer riconosce il namespace XLink e insiste su un output xlink prefisso per esso, senza registrarti correttamente quel prefisso.

Quindi questo lavoro frammento di bene:

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

Così qui ho cambiato l'URL Namespace a qualcosa di meno conosciuto e l'uscita è ora valida:

Il seguente frammento funziona anche bene :

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

Quindi, in questo caso si usa il prefisso "atteso" per lo spazio dei nomi e XLink quindi serializza senza problemi:

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

Non sono del tutto sicuro di quale sia la risposta, ma questo problema potrebbe essere correlato: http://stackoverflow.com/questions/8979267/xmlserializer-strips-xlink-from-xlinkhtml-svg-image-tag – Barbarrosa

+0

Grazie per il puntatore Barbarrosa. Ho visto rapporti sulla gestione SVG/XLink di Chrome. Ma temo davvero che la "correzione" di quello possa essere stato ciò che ha causato il problema che sto vivendo. Con il tuo link potrei effettivamente avvicinarmi di un passo al codice offensivo, quindi grazie! –

risposta

7

Sono ancora abbastanza sicuro che c'è un bug in Chrome di XMLSerializer, molto probabilmente introdotta affrontando il SVG handling of XLink attributes that Barbarrosa pointed to. Ma data la mancanza di risposta allo bug report che ho fatto per questo, abbiamo dovuto andare avanti e aggirare il problema.

Abbiamo aggirare il problema chiamando questa funzione sul 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]); 
    } 
    } 
} 

La funzione assicura semplicemente che l'attributo xmlns:xlink è dichiarato su ogni elemento che ha attribuito nel namespace XLink. Poiché la funzione attraversa l'albero e quindi può richiedere molto tempo, la invoco solo per le versioni di Chrome 22 e successive.

Si noti che nella maggior parte dei casi si può anche ottenere semplicemente aggiungendo lo spazio dei nomi xmlns:xlink sull'elemento del documento, poiché verrà ereditato da lì.Ma nel nostro caso c'era un altro codice che estrae l'elemento del documento usando un'espressione regolare, quindi abbiamo deciso di giocare sul sicuro e semplicemente aggiungere l'attributo ovunque sia necessario.

Update (20.130.324):

Il bug è stato fissato e verificato in Chrome Canary 26. Ho potuto verificare io stesso della versione 25.0.1364.172 m troppo.

Problemi correlati