2012-10-09 44 views
23

tengo el siguiente fragmento de JavaScript mínima:Chrome 22 salidas XML válido cuando atributos tienen un espacio de nombres 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); 

Cuando ejecuto el código en la mayoría de los navegadores (sólo pegarlo en la consola JavaScript del navegador), el XML analizado y luego serializado es equivalente al original. Por ejemplo en Chrome 8 consigo:

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

Sin embargo en Chrome 22 el mismo fragmento de código cambia el código XML a:

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

Tenga en cuenta que el prefijo de espacio de nombres xlink utilizado por los atributos de título y href no es definido en cualquier lugar, por lo que el XML ahora no es válido. Como probablemente pueda imaginar, esto causa todo tipo de problemas para el código que intenta utilizar posteriormente el XML.

Es esto un error en el XMLSerializer o me estoy perdiendo algunas complejidades de cómo el DOM se debe serializar?

¿Alguien encontró una solución alternativa que puedo poner en el código, en lugar de hacer que el XML coincida con la aparente preferencia de usar xlink como el prefijo para el espacio de nombre XLink?

actualización

Hice algunas pruebas adicionales y el problema parece ser causado por el hecho de que el XMLSerializer reconoce el espacio de nombres XLink e insiste en la salida de un prefijo xlink para ello, y sin registrarse adecuadamente ese prefijo.

Así que este trabajo fino fragmento:

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

Así que aquí me cambió la URL de espacio de nombres a algo menos conocido y la salida es ahora válido:

El siguiente fragmento también funciona bien :

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

Así que en este caso se utiliza el prefijo "espera" para el espacio de nombres XLink y a continuación, serializa sin problemas:

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

No estoy del todo seguro de cuál es la respuesta, pero este problema puede estar relacionado: http://stackoverflow.com/questions/8979267/xmlserializer-strips-xlink-from-xlinkhtml-svg-image-tag – Barbarrosa

+0

Gracias para el puntero Barbarrosa. Había visto informes sobre el manejo de SVG/XLink de Chrome. Pero realmente temo que la "solución" para eso puede haber sido lo que causó el problema que estoy experimentando. Con su enlace, puedo estar un paso más cerca del código ofensivo, ¡así que gracias! –

Respuesta

7

todavía estoy bastante seguro de que hay un error en Chrome de XMLSerializer, más probable es introducido mientras que frente a la SVG handling of XLink attributes that Barbarrosa pointed to. Sin embargo, dada la falta de respuesta a la bug report que hice para ella, hemos tenido que avanzar y solucionar el problema.

Nos evitar el problema llamando a esta función en el 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 función simplemente asegura que el atributo xmlns:xlink se declara en cualquier elemento que se ha atribuido en el espacio de nombres XLink. Dado que la función recorre el árbol y por lo tanto puede ser bastante tiempo, lo único que invoco para las versiones de Chrome 22 y superiores.

Tenga en cuenta que en la mayoría de los casos también puede salirse con la suya simplemente agregando el espacio de nombre xmlns:xlink en el elemento de documento, ya que se heredará desde allí.Pero en nuestro caso había algún otro código que elimina el elemento del documento con una expresión regular, por lo que decidimos ir a lo seguro y simplemente agregar el atributo donde sea que se necesite.

Update (20130324):

El bug se fijó y se verificó en Chrome Canary 26. He podido comprobar por mí mismo en la versión 25.0.1364.172 m también.

Cuestiones relacionadas