XML parsing of a variable string in JavaScript
Asked Answered
B

10

213

I have a variable string that contains well-formed and valid XML. I need to use JavaScript code to parse this feed.

How can I accomplish this using (browser-compatible) JavaScript code?

Bruno answered 16/3, 2009 at 8:17 Comment(0)
O
93

Update: For a more correct answer see Tim Down's answer.

Internet Explorer and, for example, Mozilla-based browsers expose different objects for XML parsing, so it's wise to use a JavaScript framework like jQuery to handle the cross-browsers differences.

A really basic example is:

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

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

Note: As pointed out in comments; jQuery does not really do any XML parsing whatsoever, it relies on the DOM innerHTML method and will parse it like it would any HTML so be careful when using HTML element names in your XML. But I think it works fairly good for simple XML 'parsing', but it's probably not suggested for intensive or 'dynamic' XML parsing where you do not upfront what XML will come down and this tests if everything parses as expected.

Oberammergau answered 16/3, 2009 at 8:43 Comment(8)
The code for abstracting out the difference in XML parsing between IE and other browsers is a few trivial lines, so not worth bolting on 50K of jQuery for on its own. Manipulating the resulting XML's DOM is another matter.Datha
And something I didn't realise at the time of posting my previous comment is that jQuery doesn't even parse the XML, it simply assigns it as the innerHTML property of an element, which is not at all reliable.Datha
Note that JQuery does not support XML namespaces. See zachleat.com/web/2008/05/10/selecting-xml-with-javascriptFelicitasfelicitate
jQuery DOES support XML namespaces, but it's not cross-browser. Parsing namespaced XML with different browsers is real PITA.Henton
This answer is wrong. See #2125424, #2909399, @Tim Down's answer and the jQuery documentation itself where it states: "Note that [jQuery()] parses HTML, not XML"Mechelle
@CrescentFresh You're correct, I've updated my answer, it's up to 'owner' of this question to mark another (better) answer as accepted. But i've used this method before and it works for simple structures... txn for pointing that out...Oberammergau
@SanderVersluys: since the author is not accepting another answer, I would include a note in your answer linking to @TimDown's correct answer. That way people don't have to read all these comments to figure out the correct answer.Bareheaded
@EricTurner: Seriously, do not use this. It may work in some cases in some browsers but it is not reliable. Use $.parseXML() instead.Datha
D
330

Updated answer for 2017

The following will parse an XML string into an XML document in all major browsers. Unless you need support for IE <= 8 or some obscure browser, you could use the following function:

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

If you need to support IE <= 8, the following will do the job:

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

Once you have a Document obtained via parseXml, you can use the usual DOM traversal methods/properties such as childNodes and getElementsByTagName() to get the nodes you want.

Example usage:

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

If you're using jQuery, from version 1.5 you can use its built-in parseXML() method, which is functionally identical to the function above.

var xml = $.parseXML("<foo>Stuff</foo>");
alert(xml.documentElement.nodeName);
Datha answered 7/12, 2011 at 9:27 Comment(14)
I agree, this should be accepted answer. My answer is so old from the early days, I've always find it curious it still gets upvotes. Anyone in favor of removing my accepted answer? And is the voting system flawed? Upvote this people!Oberammergau
@SanderVersluys: Are you able to remove your answer?Hasin
@Hasin as a matter of fact, i can't because it's the accepted answer... i've updated my answer to reflect that...Oberammergau
Had to downvote you for saying that there are 'no other decent answers'. @SanderVersluys answer worked fine in my case. What's not decent about that, I do not know.Hedwig
@EricTurner: I stand by it and Sander himself has disowned his answer. jQuery docs tell you not to use $() for XML parsing. Read the comments more carefully: it simply does not work in many situations.Datha
jsLint is telling me that I should be using !== "undefined" instead of != "undefined". Is that right?Mafia
@NateGlenn: It makes precisely no practical difference in this case: == and === behave identically when the operands are of the same type, which is the case here. It's up to you whether you want to appease JSLint.Datha
Is that xmlDoc.async really supposed to take a string "false"? Shouldn't that be a boolean false?Unwise
@DWoldrich: I've seen it both ways on the web, and I suspect it works both ways. The closest I can find to an authoritative answer is msdn.microsoft.com/en-us/library/ms761398(v=vs.85).aspx, which says a Boolean should be used. However, and how much value you place in this is entirely up to you, jQuery's parseXML() method uses a string. I'm slightly wary of changing the answer because I have no easy way to test it right now.Datha
@TimDown hmmm, makes me want to spelunke into the jQuery commit history to see what the secret to a string there is. Some ActiveX arcana or IE 5.5 tchotchke? Fun fun fun.Unwise
@DWoldrich: The code in my answer here is what I've used for ages predates the existence of jQuery's parseXML() so I'm sure I didn't get it from there. Where I did get it from is lost in the mists of time.Datha
I tried the jQuery parseXML() function on Firefox, Chrome and IE, and it only seems to work on Firefox; on the others, I get an error that says $.parseXML() is not a function (Chrome) or is not supported (IE). Then again, it could be just the context that I was using it in (a unit test environment using Qunit 2.3.3 as the testing framework and Sinon 2.3.5 as the mocking framework) that was causing the issue.Flowerpot
@TimDown you may want to update JQuery remark as of 2.x it no longer falls back to ActiveX (IE9+ only and hence will not support browsers no one supports any longer). Since your code is identical to JQuery.parseXML you may consider making parseXML more "recommended if you already use JQuery". Also see if you'd want to recommend dropping IE8 and use just DOMParser option. (then #7950252 can be re-closed as duplicate)Comic
@AlexeiLevenkov: Good points all round, thanks. I've updated my answer.Datha
O
93

Update: For a more correct answer see Tim Down's answer.

Internet Explorer and, for example, Mozilla-based browsers expose different objects for XML parsing, so it's wise to use a JavaScript framework like jQuery to handle the cross-browsers differences.

A really basic example is:

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

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

Note: As pointed out in comments; jQuery does not really do any XML parsing whatsoever, it relies on the DOM innerHTML method and will parse it like it would any HTML so be careful when using HTML element names in your XML. But I think it works fairly good for simple XML 'parsing', but it's probably not suggested for intensive or 'dynamic' XML parsing where you do not upfront what XML will come down and this tests if everything parses as expected.

Oberammergau answered 16/3, 2009 at 8:43 Comment(8)
The code for abstracting out the difference in XML parsing between IE and other browsers is a few trivial lines, so not worth bolting on 50K of jQuery for on its own. Manipulating the resulting XML's DOM is another matter.Datha
And something I didn't realise at the time of posting my previous comment is that jQuery doesn't even parse the XML, it simply assigns it as the innerHTML property of an element, which is not at all reliable.Datha
Note that JQuery does not support XML namespaces. See zachleat.com/web/2008/05/10/selecting-xml-with-javascriptFelicitasfelicitate
jQuery DOES support XML namespaces, but it's not cross-browser. Parsing namespaced XML with different browsers is real PITA.Henton
This answer is wrong. See #2125424, #2909399, @Tim Down's answer and the jQuery documentation itself where it states: "Note that [jQuery()] parses HTML, not XML"Mechelle
@CrescentFresh You're correct, I've updated my answer, it's up to 'owner' of this question to mark another (better) answer as accepted. But i've used this method before and it works for simple structures... txn for pointing that out...Oberammergau
@SanderVersluys: since the author is not accepting another answer, I would include a note in your answer linking to @TimDown's correct answer. That way people don't have to read all these comments to figure out the correct answer.Bareheaded
@EricTurner: Seriously, do not use this. It may work in some cases in some browsers but it is not reliable. Use $.parseXML() instead.Datha
E
19

Most examples on the web (and some presented above) show how to load an XML from a file in a browser compatible manner. This proves easy, except in the case of Google Chrome which does not support the document.implementation.createDocument() method. When using Chrome, in order to load an XML file into a XmlDocument object, you need to use the inbuilt XmlHttp object and then load the file by passing it's URI.

In your case, the scenario is different, because you want to load the XML from a string variable, not a URL. For this requirement however, Chrome supposedly works just like Mozilla (or so I've heard) and supports the parseFromString() method.

Here is a function I use (it's part of the Browser compatibility library I'm currently building):

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;
}
Elga answered 16/3, 2009 at 9:46 Comment(3)
I am aware of the controversial opinions regarding Browser sniffing and that's the reason I did not include that function here. However, it has not been established that it is WRONG. In any case, this is a suggestive example.Elga
I believe it's wrong in that you can't guarantee that it's right. Anyone can spoof the UA strings, and it's doubtful that EVERY non-IE browser supports DOMParser, and that your browser-sniffing is PERFECT. And besides, it's much easier to do it the right way: if(window.ActiveXObject){...}Paulie
So now IE9+ supports DOMParser, how are you going to support that? -1 for what @Paulie is saying. All you need to check is 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)') }.Encomiast
U
13

Marknote is a nice lightweight cross-browser JavaScript XML parser. It's object-oriented and it's got plenty of examples, plus the API is documented. It's fairly new, but it has worked nicely in one of my projects so far. One thing I like about it is that it will read XML directly from strings or URLs and you can also use it to convert the XML into JSON.

Here's an example of what you can do with 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") + "'"
    );
}
Unmarked answered 29/1, 2012 at 21:16 Comment(2)
It seems marknote implements a pure javascript parser. It means it should be compatible with any javascript engine, wherever it is used in a browser, in node.js or in a standalone javascript engine...Turnheim
As of 6/2021, please note that Marknote is not maintained any more. fast-xml-parser is a maintained alternative.Danelaw
E
8

I've always used the approach below which works in IE and Firefox.

Example 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);
      }
    }
  }
}
Easeful answered 16/3, 2009 at 10:51 Comment(2)
How would you take a value if you had this situation <fruit>value</fruit> ?Baronial
@Baronial you need use innerText instead of getAttribute()Catchall
S
8

Apparently jQuery now provides jQuery.parseXML http://api.jquery.com/jQuery.parseXML/ as of version 1.5

jQuery.parseXML( data ) Returns: XMLDocument

Stercoraceous answered 5/12, 2011 at 22:3 Comment(0)
C
2

Please take a look at XML DOM Parser (W3Schools). It's a tutorial on XML DOM parsing. The actual DOM parser differs from browser to browser but the DOM API is standardised and remains the same (more or less).

Alternatively use E4X if you can restrict yourself to Firefox. It's relatively easier to use and it's part of JavaScript since version 1.6. Here is a small sample usage...

//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.
Caius answered 16/3, 2009 at 8:41 Comment(0)
I
2

Disclaimer : I've created fast-xml-parser

I have created fast-xml-parser to parse a XML string into JS/JSON object or intermediate traversal object. It is expected to be compatible in all the browsers (however tested on Chrome, Firefox, and IE only).

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

Note: It doesn't use DOM parser but parse the string using RE and convert it into JS/JSON object.

Try it online, CDN

Increate answered 23/1, 2018 at 3:36 Comment(0)
L
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>

For more info refer this http://www.easycodingclub.com/xml-parser-in-javascript/javascript-tutorials/

Legendary answered 26/12, 2015 at 5:24 Comment(0)
G
-1

You can also through the jquery function($.parseXML) to manipulate xml string

example 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'))
})
Germinate answered 4/3, 2016 at 3:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.