Análisis XML de una cadena variable en JavaScript

204

Tengo una cadena variable que contiene XML bien formado y válido. Necesito usar el código JavaScript para analizar este feed.

¿Cómo puedo lograr esto usando el código JavaScript (compatible con el navegador)?

David Bonnici
fuente

Respuestas:

90

Actualización: para obtener una respuesta más correcta, consulte la respuesta de Tim Down .

Internet Explorer y, por ejemplo, los navegadores basados ​​en Mozilla exponen diferentes objetos para el análisis XML, por lo que es aconsejable utilizar un marco de JavaScript como jQuery para manejar las diferencias entre navegadores.

Un ejemplo realmente básico es:

var xml = "<music><album>Beethoven</album></music>";

var result = $(xml).find("album").text();

Nota: Como se señaló en los comentarios; jQuery realmente no realiza ningún análisis XML en absoluto, se basa en el método DOM innerHTML y lo analizará como lo haría con cualquier HTML, así que tenga cuidado al usar nombres de elementos HTML en su XML. Pero creo que funciona bastante bien para el 'análisis' XML simple, pero probablemente no se sugiera para el análisis XML intensivo o 'dinámico' en el que no se indique por adelantado qué XML se reducirá y esto prueba si todo se analiza como se esperaba.

Sander Versluys
fuente
66
El código para resumir la diferencia en el análisis XML entre IE y otros navegadores es unas pocas líneas triviales, por lo que no vale la pena atornillar en 50K de jQuery por sí solo. Manipular el DOM del XML resultante es otra cuestión.
Tim Down
77
Y algo de lo que no me di cuenta al momento de publicar mi comentario anterior es que jQuery ni siquiera analiza el XML, simplemente lo asigna como la innerHTMLpropiedad de un elemento, que no es del todo confiable.
Tim Down
Tenga en cuenta que JQuery no admite espacios de nombres XML. Ver zachleat.com/web/2008/05/10/selecting-xml-with-javascript
mikemaccana
10
Esta respuesta es incorrecta. Consulte stackoverflow.com/questions/2124924/… , stackoverflow.com/questions/2908899/… , la respuesta de @Tim Down y la documentación de jQuery en la que dice: "Tenga en cuenta que [ jQuery()] analiza HTML, no XML"
Crescent Fresh
2
@SanderVersluys: dado que el autor no acepta otra respuesta, incluiría una nota en su respuesta que vincule a la respuesta correcta de @ TimDown . De esa manera, las personas no tienen que leer todos estos comentarios para encontrar la respuesta correcta.
Sentido el
321

Respuesta actualizada para 2017

Lo siguiente analizará una cadena XML en un documento XML en todos los principales navegadores. A menos que necesite soporte para IE <= 8 o algún navegador oscuro, puede usar la siguiente función:

function parseXml(xmlStr) {
   return new window.DOMParser().parseFromString(xmlStr, "text/xml");
}

Si necesita admitir IE <= 8, lo siguiente hará el trabajo:

var parseXml;

if (typeof window.DOMParser != "undefined") {
    parseXml = function(xmlStr) {
        return new window.DOMParser().parseFromString(xmlStr, "text/xml");
    };
} else if (typeof window.ActiveXObject != "undefined" &&
       new window.ActiveXObject("Microsoft.XMLDOM")) {
    parseXml = function(xmlStr) {
        var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async = "false";
        xmlDoc.loadXML(xmlStr);
        return xmlDoc;
    };
} else {
    throw new Error("No XML parser found");
}

Una vez que tengas un Document obtenido vía parseXml, puede utilizar los métodos / propiedades transversales habituales de DOM, como childNodesy getElementsByTagName()para obtener los nodos que desee.

Ejemplo de uso:

var xml = parseXml("<foo>Stuff</foo>");
alert(xml.documentElement.nodeName);

Si está utilizando jQuery, a partir de la versión 1.5 puede utilizar su parseXML()método incorporado , que es funcionalmente idéntico a la función anterior.

var xml = $.parseXML("<foo>Stuff</foo>");
alert(xml.documentElement.nodeName);
Tim Down
fuente
56
Estoy de acuerdo, esta respuesta debe ser aceptada. Mi respuesta es tan antigua desde los primeros días, siempre me parece curioso que todavía reciba votos. ¿Alguien a favor de eliminar mi respuesta aceptada? ¿Y es defectuoso el sistema de votación? ¡Vota a esta gente!
Sander Versluys
@SanderVersluys: ¿Puedes eliminar tu respuesta?
Witman
1
Tuve que rechazarte por decir que "no hay otras respuestas decentes". La respuesta de @SanderVersluys funcionó bien en mi caso. Lo que no es decente sobre eso, no lo sé.
eric
2
@EricTurner: lo mantengo y el mismo Sander ha repudiado su respuesta. Los documentos de jQuery le dicen que no use $()para el análisis XML . Lea los comentarios con más cuidado: simplemente no funciona en muchas situaciones.
Tim Down
1
@DWoldrich: Lo he visto en ambos sentidos en la web, y sospecho que funciona en ambos sentidos. Lo más cercano que puedo encontrar a una respuesta autorizada es msdn.microsoft.com/en-us/library/ms761398(v=vs.85).aspx , que dice que se debe usar un booleano. Sin embargo, y la cantidad de valor que coloque en esto depende completamente de usted, el parseXML()método de jQuery usa una cadena. Estoy un poco preocupado de cambiar la respuesta porque no tengo una manera fácil de probarlo en este momento.
Tim Down
19

La mayoría de los ejemplos en la web (y algunos presentados anteriormente) muestran cómo cargar un XML desde un archivo de manera compatible con el navegador. Esto resulta fácil, excepto en el caso de Google Chrome que no admite el document.implementation.createDocument()método. Al usar Chrome, para cargar un archivo XML en un objeto XmlDocument, debe usar el objeto XmlHttp incorporado y luego cargar el archivo pasando su URI.

En su caso, el escenario es diferente, porque desea cargar el XML desde una variable de cadena , no desde una URL. Sin embargo, para este requisito, Chrome supuestamente funciona igual que Mozilla (o eso he oído) y es compatible con el método parseFromString ().

Aquí hay una función que uso (es parte de la biblioteca de compatibilidad del navegador que estoy construyendo actualmente):

function LoadXMLString(xmlString)
{
  // ObjectExists checks if the passed parameter is not null.
  // isString (as the name suggests) checks if the type is a valid string.
  if (ObjectExists(xmlString) && isString(xmlString))
  {
    var xDoc;
    // The GetBrowserType function returns a 2-letter code representing
    // ...the type of browser.
    var bType = GetBrowserType();

    switch(bType)
    {
      case "ie":
        // This actually calls into a function that returns a DOMDocument 
        // on the basis of the MSXML version installed.
        // Simplified here for illustration.
        xDoc = new ActiveXObject("MSXML2.DOMDocument")
        xDoc.async = false;
        xDoc.loadXML(xmlString);
        break;
      default:
        var dp = new DOMParser();
        xDoc = dp.parseFromString(xmlString, "text/xml");
        break;
    }
    return xDoc;
  }
  else
    return null;
}
Cerebro
fuente
16
Soy consciente de las opiniones controvertidas sobre el rastreo del navegador y esa es la razón por la que no incluí esa función aquí. Sin embargo, no se ha establecido que sea INCORRECTO. En cualquier caso, este es un ejemplo sugerente .
Cerebrus
1
Creo que está mal que no puedas garantizar que esté bien. Cualquiera puede falsificar las cadenas de UA, y es dudoso que CADA navegador que no sea IE sea compatible con DOMParser, y que el rastreo de su navegador sea PERFECTO. Y además, es mucho más fácil hacerlo de la manera correcta:if(window.ActiveXObject){...}
1j01
Entonces, ahora IE9 + es compatible con DOMParser , ¿cómo vas a soportar eso? -1 por lo que dice @ 1j01. Todo lo que necesitas verificar es var dp; try{ dp = new DOMParser() } catch(e) { }; if(dp) { // DOMParser supported } else { // alert('you need to consider upgrading your browser\nOr pay extra money so developer can support the old versions using browser sniffing (eww)') }.
Annie
13

Marknote es un agradable analizador XML JavaScript de navegador cruzado. Está orientado a objetos y tiene muchos ejemplos, además de que la API está documentada. Es bastante nuevo, pero hasta ahora ha funcionado bien en uno de mis proyectos. Una cosa que me gusta es que leerá XML directamente de cadenas o URL y también puede usarlo para convertir el XML en JSON.

Aquí hay un ejemplo de lo que puede hacer con Marknote:

var str = '<books>' +
          '  <book title="A Tale of Two Cities"/>' +
          '  <book title="1984"/>' +
          '</books>';

var parser = new marknote.Parser();
var doc = parser.parse(str);

var bookEls = doc.getRootElement().getChildElements();

for (var i=0; i<bookEls.length; i++) {
    var bookEl = bookEls[i];
    // alerts "Element name is 'book' and book title is '...'"
    alert("Element name is '" + bookEl.getName() + 
        "' and book title is '" + 
        bookEl.getAttributeValue("title") + "'"
    );
}
Mike McMillien
fuente
Parece que marknote implementa un analizador javascript puro. Significa que debe ser compatible con cualquier motor javascript, donde sea que se use en un navegador, en node.js o en un motor javascript independiente ...
Coyote
8

Siempre he usado el siguiente enfoque que funciona en IE y Firefox.

XML de ejemplo:

<fruits>
  <fruit name="Apple" colour="Green" />
  <fruit name="Banana" colour="Yellow" />
</fruits>

JavaScript:

function getFruits(xml) {
  var fruits = xml.getElementsByTagName("fruits")[0];
  if (fruits) {
    var fruitsNodes = fruits.childNodes;
    if (fruitsNodes) {
      for (var i = 0; i < fruitsNodes.length; i++) {
        var name = fruitsNodes[i].getAttribute("name");
        var colour = fruitsNodes[i].getAttribute("colour");
        alert("Fruit " + name + " is coloured " + colour);
      }
    }
  }
}
John Topley
fuente
¿Cómo tomaría un valor si tuviera esta situación <fruit> value </fruit>?
Siblja
1
@Siblja necesita usar en innerTextlugar degetAttribute()
Manux22
2

Por favor, eche un vistazo a XML DOM Parser ( W3Schools ). Es un tutorial sobre el análisis XML DOM. El analizador DOM real difiere de un navegador a otro, pero la API DOM está estandarizada y sigue siendo la misma (más o menos).

Alternativamente, use E4X si puede restringirse a Firefox. Es relativamente más fácil de usar y es parte de JavaScript desde la versión 1.6. Aquí hay una pequeña muestra de uso ...

//Using E4X
var xmlDoc=new XML();
xmlDoc.load("note.xml");
document.write(xmlDoc.body); //Note: 'body' is actually a tag in note.xml,
//but it can be accessed as if it were a regular property of xmlDoc.
Autodidacta
fuente
0
<script language="JavaScript">
function importXML()
{
    if (document.implementation && document.implementation.createDocument)
    {
            xmlDoc = document.implementation.createDocument("", "", null);
            xmlDoc.onload = createTable;
    }
    else if (window.ActiveXObject)
    {
            xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.onreadystatechange = function () {
                    if (xmlDoc.readyState == 4) createTable()
            };
    }
    else
    {
            alert('Your browser can\'t handle this script');
            return;
    }
    xmlDoc.load("emperors.xml");
}

function createTable()
{
    var theData="";
    var x = xmlDoc.getElementsByTagName('emperor');
    var newEl = document.createElement('TABLE');
    newEl.setAttribute('cellPadding',3);
    newEl.setAttribute('cellSpacing',0);
    newEl.setAttribute('border',1);
    var tmp = document.createElement('TBODY');
    newEl.appendChild(tmp);
    var row = document.createElement('TR');
    for (j=0;j<x[0].childNodes.length;j++)
    {
            if (x[0].childNodes[j].nodeType != 1) continue;
            var container = document.createElement('TH');
            theData = document.createTextNode(x[0].childNodes[j].nodeName);
            container.appendChild(theData);
            row.appendChild(container);
    }
    tmp.appendChild(row);
    for (i=0;i<x.length;i++)
    {
            var row = document.createElement('TR');
            for (j=0;j<x[i].childNodes.length;j++)
            {
                    if (x[i].childNodes[j].nodeType != 1) continue;
                    var container = document.createElement('TD');
                    var theData = document.createTextNode(x[i].childNodes[j].firstChild.nodeValue);
                    container.appendChild(theData);
                    row.appendChild(container);
            }
            tmp.appendChild(row);
    }
    document.getElementById('writeroot').appendChild(newEl);
}
</script>
</HEAD>

<BODY onLoad="javascript:importXML();">
<p id=writeroot> </p>
</BODY>

Para obtener más información, consulte http://www.easycodingclub.com/xml-parser-in-javascript/javascript-tutorials/

easycodingclub
fuente
0

Descargo de responsabilidad : he creado fast-xml-parser

He creado fast-xml-parser para analizar una cadena XML en un objeto JS / JSON u objeto transversal intermedio. Se espera que sea compatible en todos los navegadores (aunque probado solo en Chrome, Firefox e IE).

Uso

var options = { //default
    attrPrefix : "@_",
    attrNodeName: false,
    textNodeName : "#text",
    ignoreNonTextNodeAttr : true,
    ignoreTextNodeAttr : true,
    ignoreNameSpace : true,
    ignoreRootElement : false,
    textNodeConversion : true,
    textAttrConversion : false,
    arrayMode : false
};

if(parser.validate(xmlData)){//optional
    var jsonObj = parser.parse(xmlData, options);
}

//Intermediate obj
var tObj = parser.getTraversalObj(xmlData,options);
:
var jsonObj = parser.convertToJson(tObj);

Nota : No usa el analizador DOM, sino que analiza la cadena usando RE y la convierte en objeto JS / JSON.

Pruébelo en línea , CDN

Amit Kumar Gupta
fuente
-1

También puede usar la función jquery ($. ParseXML) para manipular la cadena xml

ejemplo javascript:

var xmlString = '<languages><language name="c"></language><language name="php"></language></languages>';
var xmlDoc = $.parseXML(xmlString);
$(xmlDoc).find('name').each(function(){
    console.log('name:'+$(this).attr('name'))
})
usuario6016338
fuente