Analisi XML di una stringa variabile in JavaScript


204

Ho una stringa variabile che contiene un XML ben formato e valido. Devo usare il codice JavaScript per analizzare questo feed.

Come posso farlo utilizzando il codice JavaScript (compatibile con il browser)?

Risposte:


90

Aggiornamento: per una risposta più corretta vedi la risposta di Tim Down .

Internet Explorer e, ad esempio, i browser basati su Mozilla espongono oggetti diversi per l'analisi XML, quindi è consigliabile utilizzare un framework JavaScript come jQuery per gestire le differenze tra i browser.

Un esempio davvero di base è:

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

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

Nota: come sottolineato nei commenti; jQuery non esegue in alcun modo l'analisi XML, si basa sul metodo DOM innerHTML e lo analizzerà come qualsiasi HTML, quindi fai attenzione quando usi i nomi degli elementi HTML nel tuo XML. Ma penso che funzioni abbastanza bene per il semplice "analisi" XML, ma probabilmente non è suggerito per l'analisi XML intensa o "dinamica" in cui non si capisce quale XML verrà giù e questo verifica se tutto analizza come previsto.


6
Il codice per sottrarre la differenza nell'analisi XML tra IE e altri browser è alcune righe banali, quindi non vale la pena imbullonare da solo 50K di jQuery. La manipolazione del DOM dell'XML risultante è un'altra questione.
Tim Down,

7
E qualcosa che non ho realizzato al momento della pubblicazione del mio precedente commento è che jQuery non analizza nemmeno l'XML, ma semplicemente lo assegna come innerHTMLproprietà di un elemento, il che non è affatto affidabile.
Tim Down

Si noti che JQuery non supporta gli spazi dei nomi XML. Vedi zachleat.com/web/2008/05/10/selecting-xml-with-javascript
mikemaccana

10
Questa risposta è sbagliata Vedi stackoverflow.com/questions/2124924/… , stackoverflow.com/questions/2908899/… , la risposta di @Tim Down e la stessa documentazione di jQuery in cui si afferma: "Nota che [ jQuery()] analizza HTML, non XML"
Crescent Fresh

2
@SanderVersluys: poiché l'autore non accetta un'altra risposta, includerei una nota nella tua risposta che si collega alla risposta corretta di @ TimDown . In questo modo le persone non devono leggere tutti questi commenti per capire la risposta corretta.
Senso

321

Risposta aggiornata per il 2017

Di seguito verrà analizzata una stringa XML in un documento XML in tutti i principali browser. A meno che non sia necessario il supporto per IE <= 8 o alcuni browser oscuri, è possibile utilizzare la seguente funzione:

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

Se è necessario supportare IE <= 8, il seguente farà il lavoro:

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 volta Documentottenuto un via parseXml, puoi usare i soliti metodi / proprietà di attraversamento DOM come childNodesegetElementsByTagName() per ottenere i nodi desiderati.

Esempio di utilizzo:

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

Se stai usando jQuery, dalla versione 1.5 puoi usare il suo parseXML()metodo integrato , che è funzionalmente identico alla funzione sopra.

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

56
Sono d'accordo, questa dovrebbe essere una risposta accettata. La mia risposta è così antica sin dai primi tempi, l'ho sempre trovata curiosa che ottiene ancora voti. Qualcuno a favore della rimozione della mia risposta accettata? E il sistema di voto è difettoso? Valorizza questo popolo!
Sander Versluys l'

@SanderVersluys: riesci a rimuovere la tua risposta?
Witman,

1
Ho dovuto sottovalutarti per aver detto che non ci sono "altre risposte decenti". La risposta di @SanderVersluys ha funzionato bene nel mio caso. Cosa non è decente, non lo so.
eric,

2
@EricTurner: io lo sostengo e Sander stesso ha rinnegato la sua risposta. I documenti jQuery ti dicono di non utilizzare $()per l'analisi XML . Leggi i commenti con più attenzione: semplicemente non funziona in molte situazioni.
Tim Down,

1
@DWoldrich: l'ho visto in entrambi i modi sul web e sospetto che funzioni in entrambi i modi. Il più vicino che posso trovare a una risposta autorevole è msdn.microsoft.com/en-us/library/ms761398(v=vs.85).aspx , che dice che dovrebbe essere usato un valore booleano. Tuttavia, e quanto valore attribuisci a questo dipende interamente da te, il parseXML()metodo di jQuery utilizza una stringa. Sono un po 'diffidente nel cambiare la risposta perché non ho un modo semplice per provarla in questo momento.
Tim Down

19

La maggior parte degli esempi sul Web (e alcuni presentati sopra) mostrano come caricare un XML da un file in modo compatibile con il browser. Ciò risulta semplice, tranne nel caso di Google Chrome che non supporta il document.implementation.createDocument()metodo. Quando si utilizza Chrome, per caricare un file XML in un oggetto XmlDocument, è necessario utilizzare l'oggetto XmlHttp incorporato e quindi caricare il file passando l'URI.

Nel tuo caso, lo scenario è diverso, perché desideri caricare l'XML da una variabile stringa , non da un URL. Tuttavia, per questo requisito, Chrome funziona esattamente come Mozilla (o almeno così ho sentito) e supporta il metodo parseFromString ().

Ecco una funzione che uso (fa parte della libreria di compatibilità del browser che sto attualmente creando):

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

16
Sono a conoscenza delle opinioni controverse sull'annusamento del browser e questa è la ragione per cui non ho incluso quella funzione qui. Tuttavia, non è stato stabilito che sia SBAGLIATO. In ogni caso, questo è un esempio suggestivo .
Cerebrus,

1
Credo sia sbagliato nel fatto che non puoi garantire che sia giusto. Chiunque può falsificare le stringhe UA ed è dubbio che OGNI browser non IE supporti DOMParser e che l'annusamento del browser sia PERFETTO. Inoltre, è molto più semplice farlo nel modo giusto:if(window.ActiveXObject){...}
1j01

Quindi ora IE9 + supporta DOMParser , come hai intenzione di supportarlo? -1 per quello che dice @ 1j01. Tutto quello che devi controllare è 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 è un parser XML JavaScript leggero e cross-browser. È orientato agli oggetti e ha molti esempi, inoltre l' API è documentata. È abbastanza nuovo, ma finora ha funzionato bene in uno dei miei progetti. Una cosa che mi piace è che leggerà XML direttamente da stringhe o URL e puoi anche usarlo per convertire l'XML in JSON.

Ecco un esempio di cosa puoi fare 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") + "'"
    );
}

Sembra marknote implementa un puro parser javascript. Significa che dovrebbe essere compatibile con qualsiasi motore javascript, ovunque sia utilizzato in un browser, in node.js o in un motore javascript autonomo ...
Coyote,

8

Ho sempre usato l'approccio di seguito che funziona in Internet Explorer e Firefox.

Esempio XML:

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

Come prenderesti un valore se avessi questa situazione <fruit> value </fruit>?
Siblja,

1
@Siblja devi usare innerTextinvece digetAttribute()
Manux22


2

Dai un'occhiata a XML DOM Parser ( W3Schools ). È un tutorial sull'analisi del DOM XML. Il parser DOM effettivo differisce da browser a browser ma l'API DOM è standardizzata e rimane la stessa (più o meno).

In alternativa, utilizzare E4X se si può limitare a voi stessi di Firefox. È relativamente più facile da usare ed è parte di JavaScript dalla versione 1.6. Ecco un piccolo esempio di utilizzo ...

//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.

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>

Per maggiori informazioni consultare questo http://www.easycodingclub.com/xml-parser-in-javascript/javascript-tutorials/


0

Disclaimer : ho creato fast-xml-parser

Ho creato fast-xml-parser per analizzare una stringa XML in oggetto JS / JSON o oggetto di attraversamento intermedio. Si prevede che sia compatibile in tutti i browser (comunque testato solo su 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 : non utilizza il parser DOM ma analizza la stringa utilizzando RE e la converte in oggetto JS / JSON.

Provalo online , CDN


-1

Puoi anche usare la funzione jquery ($. ParseXML) per manipolare la stringa xml

esempio 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'))
})
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.