Analyse XML d'une chaîne de variables en JavaScript

204

J'ai une chaîne variable qui contient du XML bien formé et valide. J'ai besoin d'utiliser du code JavaScript pour analyser ce flux.

Comment puis-je accomplir cela en utilisant du code JavaScript (compatible avec le navigateur)?

David Bonnici
la source

Réponses:

90

Mise à jour: Pour une réponse plus correcte, voir la réponse de Tim Down .

Internet Explorer et, par exemple, les navigateurs basés sur Mozilla exposent différents objets pour l'analyse XML, il est donc sage d'utiliser un framework JavaScript comme jQuery pour gérer les différences entre les navigateurs.

Un exemple vraiment basique est:

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

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

Remarque: comme indiqué dans les commentaires; jQuery ne fait pas vraiment d'analyse XML, il s'appuie sur la méthode DOM innerHTML et l'analysera comme il le ferait avec du HTML, donc soyez prudent lorsque vous utilisez des noms d'éléments HTML dans votre XML. Mais je pense que cela fonctionne assez bien pour une `` analyse '' XML simple, mais ce n'est probablement pas suggéré pour une analyse XML intensive ou `` dynamique '' où vous ne savez pas d'avance quel XML va descendre et cela teste si tout analyse comme prévu.

Sander Versluys
la source
6
Le code pour résumer la différence d'analyse XML entre IE et les autres navigateurs est quelques lignes triviales, donc ne vaut pas la peine d'être ajouté à 50K de jQuery pour lui-même. La manipulation du DOM XML résultant est une autre affaire.
Tim Down le
7
Et quelque chose que je n'avais pas réalisé au moment de poster mon commentaire précédent est que jQuery n'analyse même pas le XML, il l'assigne simplement comme la innerHTMLpropriété d'un élément, ce qui n'est pas du tout fiable.
Tim Down
Notez que JQuery ne prend pas en charge les espaces de noms XML. Voir zachleat.com/web/2008/05/10/selecting-xml-with-javascript
mikemaccana
10
Cette réponse est fausse. Voir stackoverflow.com/questions/2124924/… , stackoverflow.com/questions/2908899/… , la réponse de @Tim Down et la documentation jQuery elle-même où il est indiqué: "Notez que [ jQuery()] analyse HTML, pas XML"
Crescent Fresh
2
@SanderVersluys: puisque l'auteur n'accepte pas une autre réponse, j'inclurais une note dans votre réponse reliant à la bonne réponse de @ TimDown . De cette façon, les gens n'ont pas à lire tous ces commentaires pour trouver la bonne réponse.
Senseful
321

Réponse mise à jour pour 2017

Ce qui suit analysera une chaîne XML dans un document XML dans tous les principaux navigateurs. Sauf si vous avez besoin de la prise en charge d'IE <= 8 ou d'un navigateur obscur, vous pouvez utiliser la fonction suivante:

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

Si vous devez prendre en charge IE <= 8, ce qui suit fera le travail:

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

Une fois que vous avez Documentobtenu un via parseXml, vous pouvez utiliser les méthodes / propriétés de traversée DOM habituelles telles que childNodeset getElementsByTagName()pour obtenir les nœuds souhaités.

Exemple d'utilisation:

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

Si vous utilisez jQuery, à partir de la version 1.5, vous pouvez utiliser sa parseXML()méthode intégrée , qui est fonctionnellement identique à la fonction ci-dessus.

var xml = $.parseXML("<foo>Stuff</foo>");
alert(xml.documentElement.nodeName);
Tim Down
la source
56
Je suis d'accord, cette réponse devrait être acceptée. Ma réponse est si ancienne depuis les premiers jours, j'ai toujours trouvé curieux qu'elle reçoive toujours des votes positifs. Quelqu'un est-il favorable à la suppression de ma réponse acceptée? Et le système de vote est-il défectueux? Votez pour ce peuple!
Sander Versluys
@SanderVersluys: Pouvez-vous supprimer votre réponse?
Witman
1
J'ai dû vous déprécier pour avoir dit qu'il n'y avait «pas d'autres réponses décentes». La réponse @SanderVersluys a bien fonctionné dans mon cas. Ce qui n'est pas décent à ce sujet, je ne sais pas.
Eric
2
@EricTurner: Je m'en tiens à cela et Sander lui-même a renié sa réponse. Les documents jQuery vous indiquent de ne pas utiliser $()pour l'analyse XML . Lisez les commentaires plus attentivement: cela ne fonctionne tout simplement pas dans de nombreuses situations.
Tim Down le
1
@DWoldrich: Je l'ai vu dans les deux sens sur le Web, et je soupçonne que cela fonctionne dans les deux sens. Le plus proche que je puisse trouver d'une réponse faisant autorité est msdn.microsoft.com/en-us/library/ms761398(v=vs.85).aspx , qui dit qu'un booléen devrait être utilisé. Cependant, et la valeur que vous y accordez dépend entièrement de vous, la parseXML()méthode de jQuery utilise une chaîne. Je suis légèrement réticent à changer la réponse car je n'ai pas de moyen facile de la tester pour le moment.
Tim Down
19

La plupart des exemples sur le Web (et certains présentés ci-dessus) montrent comment charger un XML à partir d'un fichier de manière compatible avec un navigateur. Cela s'avère facile, sauf dans le cas de Google Chrome qui ne prend pas en charge la document.implementation.createDocument()méthode. Lorsque vous utilisez Chrome, pour charger un fichier XML dans un objet XmlDocument, vous devez utiliser l'objet XmlHttp intégré, puis charger le fichier en transmettant son URI.

Dans votre cas, le scénario est différent, car vous souhaitez charger le XML à partir d'une variable de chaîne , pas d'une URL. Pour cette exigence cependant, Chrome fonctionne censément comme Mozilla (ou du moins j'ai entendu parler) et prend en charge la méthode parseFromString ().

Voici une fonction que j'utilise (elle fait partie de la bibliothèque de compatibilité du navigateur que je suis en train de construire):

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;
}
Cerebrus
la source
16
Je suis au courant des opinions controversées concernant le reniflement du navigateur et c'est la raison pour laquelle je n'ai pas inclus cette fonction ici. Cependant, il n'a pas été établi qu'il est ERRONÉ. En tout cas, ceci est un exemple suggestif .
Cerebrus
1
Je crois que c'est faux en ce que vous ne pouvez pas garantir que c'est juste. Tout le monde peut usurper les chaînes UA, et il est douteux que CHAQUE navigateur non-IE prenne en charge DOMParser et que votre navigateur sniffing soit PARFAIT. Et en plus, c'est beaucoup plus facile de le faire de la bonne façon:if(window.ActiveXObject){...}
1j01
Alors maintenant, IE9 + prend en charge DOMParser , comment allez-vous prendre en charge cela? -1 pour ce que @ 1j01 dit. Tout ce que vous devez vérifier est 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 est un joli analyseur XML JavaScript multi-navigateur léger. Il est orienté objet et contient de nombreux exemples, et l' API est documentée. C'est assez nouveau, mais cela a bien fonctionné jusqu'à présent dans l'un de mes projets. Une chose que j'aime à ce sujet, c'est qu'il lira XML directement à partir de chaînes ou d'URL et vous pouvez également l'utiliser pour convertir le XML en JSON.

Voici un exemple de ce que vous pouvez faire avec 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
la source
Il semble que marknote implémente un analyseur javascript pur. Cela signifie qu'il doit être compatible avec n'importe quel moteur javascript, où qu'il soit utilisé dans un navigateur, dans node.js ou dans un moteur javascript autonome ...
Coyote
8

J'ai toujours utilisé l'approche ci-dessous qui fonctionne dans IE et Firefox.

Exemple 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);
      }
    }
  }
}
John Topley
la source
Comment prendriez-vous une valeur si vous aviez cette situation <fruit> valeur </fruit>?
Siblja
1
@Siblja vous devez utiliser innerTextau lieu degetAttribute()
Manux22
2

Veuillez jeter un œil à XML DOM Parser ( W3Schools ). Il s'agit d'un tutoriel sur l'analyse DOM XML. L'analyseur DOM réel diffère d'un navigateur à l'autre, mais l'API DOM est normalisée et reste la même (plus ou moins).

Vous pouvez également utiliser E4X si vous pouvez vous limiter à Firefox. Il est relativement plus facile à utiliser et fait partie de JavaScript depuis la version 1.6. Voici un petit exemple d'utilisation ...

//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.
Autocrate
la source
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>

Pour plus d'informations, consultez ce http://www.easycodingclub.com/xml-parser-in-javascript/javascript-tutorials/

easycodingclub
la source
0

Avertissement : j'ai créé un analyseur rapide de xml

J'ai créé fast-xml-parser pour analyser une chaîne XML en objet JS / JSON ou objet de traversée intermédiaire. Il devrait être compatible avec tous les navigateurs (cependant testé sur Chrome, Firefox et IE uniquement).

Usage

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

Remarque : Il n'utilise pas l'analyseur DOM mais analyse la chaîne à l'aide de RE et la convertit en objet JS / JSON.

Essayez-le en ligne , CDN

Amit Kumar Gupta
la source
-1

Vous pouvez également utiliser la fonction jquery ($. ParseXML) pour manipuler la chaîne xml

exemple 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'))
})
user6016338
la source