09 March 2011

XML Parsing and other XML Utilities - Cross Browser

Hello,

Are you searching for an alternative to new ActiveXObject("Microsoft.XMLDOM") which will work in all popular browsers? Then here it is a solution.

This Javascript library will give you the possibility to do almost everything what you could do with ActiveXObject("Microsoft.XMLDOM") but in different browsers.



Note: jQuery Core and jQuery UI is used in this Javascript library.

Code:
MSXML = [
 "Msxml2.DOMDocument.6.0",
 "Msxml2.DOMDocument.5.0",
 "Msxml2.DOMDocument.4.0",
 "Msxml2.DOMDocument.3.0",
 "MSXML2.DOMDocument",
 "Microsoft.XMLDOM"
];

function createDocument() {
    var doc;
    if (document.implementation && document.implementation.createDocument) {
        doc = document.implementation.createDocument("", "", null);
    } else if (window.ActiveXObject) {
        for (var i = 0; i < MSXML.length; i++) {
            try {
                doc = new ActiveXObject(MSXML[i]);
            } catch (e) { }
        }
        if (!doc) {
            alert("Cannot create XMLDocument object");
            return false;
        }
    }
    return doc;
}

function parseXML(str) {
    if (str == null) return null;
    if ($.trim(str) == "") return createDocument();
  
    var dom = str;
    if ($.browser.msie) {
        dom = new ActiveXObject("Microsoft.XMLDOM");
        dom.async = "false";
        dom.loadXML(str);
    }
    else if (typeof (DOMParser) != "undefined") {
        var parser = new DOMParser();
        try {

            dom = parser.parseFromString(str, "text/xml");
        } catch (e) { };

    }

    var errorMsg = null;
    if (dom.parseError && dom.parseError.errorCode != 0) {
        errorMsg = "XML Parsing Error: " + dom.parseError.reason
                          + " at line " + dom.parseError.line
                          + " at position " + dom.parseError.linepos;
    }
    else {
        if (dom.documentElement) {
            if (dom.documentElement.nodeName == "parsererror") {
                errorMsg = xmlDoc.documentElement.childNodes[0].nodeValue;
            }
        }
        else {
            errorMsg = "XML Parsing Error!";
        }
    }

    if (errorMsg) {
        //alert(errorMsg);
        return false;
    }
  
    return dom;
}

function parseXMLUrl(xmlURL) {
    var doc = createDocument();

    if (doc && typeof doc.load != 'undefined') {
        doc.async = false;
        doc.load(xmlURL);
        return doc;
    } else {
        var request = new XMLHttpRequest();
        request.open("GET", xmlURL, false);
        request.send("");
        return request.responseXML;
    }
}

function getXMLAsString(xmlDoc) {
    if (xmlDoc == null) return null;
    return ($.browser.msie) ? xmlDoc.xml : (new XMLSerializer()).serializeToString(xmlDoc);
}

function selectNodes(xmlDoc, xPath) {
    if (xmlDoc == null) return null;
    var condition = xPath;
    condition = condition.substring(0, 1) == "/" ? condition.substring(1, condition.length) : condition;
    condition = condition.replace(new RegExp("/","g"), ">").replace(new RegExp("@","g"), "");

    return $(xmlDoc).find(condition);
}

function selectSingleNode(xmlDoc, xPath) {
    if (xmlDoc == null) return null;
    var nodes = selectNodes(xmlDoc, xPath);
    if (nodes.length > 0) {
        return nodes[0];
    }
    return null;
}


This library provides a set of functions which you will use instead of standard ones.
For example
1) When you want to create an instance of XMLDOM then use CreateDocument() function. i.e.
              var xmlObj = CreateDocument();
              // Instead of:
              var xmlObj = new ActiveXObject("Microsoft.XMLDOM") ;

2) When you want to load a xml into an xmlObject then instead of a set of operations you will have to write only one line of code. i.e.
              var xmlObj = parseXML('');
              // Instead of:

              var xmlObj = new ActiveXObject("Microsoft.XMLDOM");
              xmlObj .async = "false";
              xmlObj .loadXML('');



Freelance Jobs

3) When you want to load a xml from an URL then instead of a set of operations you will have to write only one line of code(again :) ). i.e.
              var xmlObj = parseXMLUrl('XMLParsing.com/CrossBrowser');
              // Instead of:
              var xmlObj = new ActiveXObject("Microsoft.XMLDOM");
              doc.async = false;
              doc.load(xmlURL);

4) Use getXMLAsString(xmlObj) instead of xmlObj.xml

5) To select some nodes which corresponds to a xPath condition use selectNodes(xmlObj, xPath), as like you were using it with xmlObj.selectNodes(xPath);

6) And the last one: selectSingleNode, its alternative is selectSingleNode(xmlObj, xPath).

And again, if you have any suggestion for improvement please tell me. Let me know your impressions about this post.

UPDATE on 20 Feb 2011:
I have noted that the team from jQuery has achieved the same parseXML as me. :) in jQuery core 1.5.

4 comments:

Ning Yong said...

I have a problem opening a xml document (see one sample below) in Chrome, Firefox and so on. it can be load into Microsoft IE (9.0). I think the problem lies in the different browsers.

Let me tell you what utility I am using right now and then ask you to help figure out how to change my code.

First, the utility I am using is a standard downloadxml.js. It looks like:

___________________
/**
* Returns an XMLHttp instance to use for asynchronous
* downloading. This method will never throw an exception, but will
* return NULL if the browser does not support XmlHttp for any reason.
* @return {XMLHttpRequest|Null}
*/
function createXmlHttpRequest() {
try {
if (typeof ActiveXObject != 'undefined') {
return new ActiveXObject('Microsoft.XMLHTTP');
} else if (window["XMLHttpRequest"]) {
return new XMLHttpRequest();
}
} catch (e) {
changeStatus(e);
}
return null;
};

/**
* This functions wraps XMLHttpRequest open/send function.
* It lets you specify a URL and will call the callback if
* it gets a status code of 200.
* @param {String} url The URL to retrieve
* @param {Function} callback The function to call once retrieved.
*/
function downloadUrl(url, callback) {
var status = -1;
var request = createXmlHttpRequest();
if (!request) {
return false;
}

request.onreadystatechange = function() {
if (request.readyState == 4) {
try {
status = request.status;
} catch (e) {
// Usually indicates request timed out in FF.
}
if (status == 200) {
callback(request.responseXML, request.status);
request.onreadystatechange = function() {};
}
}
}
request.open('GET', url, true);
try {
request.send(null);
} catch (e) {
changeStatus(e);
}
};

/**
* Parses the given XML string and returns the parsed document in a
* DOM data structure. This function will return an empty DOM node if
* XML parsing is not supported in this browser.
* @param {string} str XML string.
* @return {Element|Document} DOM.
*/
function xmlParse(str) {
if (typeof ActiveXObject != 'undefined' && typeof GetObject != 'undefined') {
var doc = new ActiveXObject('Microsoft.XMLDOM');
doc.loadXML(str);
return doc;
}

if (typeof DOMParser != 'undefined') {
return (new DOMParser()).parseFromString(str, 'text/xml');
}

return createElement('div', null);
}

/**
* Appends a JavaScript file to the page.
* @param {string} url
*/
function downloadScript(url) {
var script = document.createElement('script');
script.src = url;
document.body.appendChild(script);
}

____________________

I used downloadurl to open the xml document, which looks like:

_______________
downloadUrl("gardenpt1.xml", function(data) {
var xmlDoc = xmlParse(data);
var records = xmlDoc.getElementsByTagName("pt");
_______________

Below is a smaple xml document:

_______________





_____________

Can you help me? Your help will be greatly appreciated.

Roman Gherman said...

Hi Ning Yong,

It looks that you are not using that correctly, but any way here is what I suggest you, and it is simple javascript and it works on all major browsers:

------------------------------------
MSXML = [
"Msxml2.DOMDocument.6.0",
"Msxml2.DOMDocument.5.0",
"Msxml2.DOMDocument.4.0",
"Msxml2.DOMDocument.3.0",
"MSXML2.DOMDocument",
"Microsoft.XMLDOM"
];

function createDocument() {
var doc;
if (document.implementation && document.implementation.createDocument) {
doc = document.implementation.createDocument("", "", null);
} else if (window.ActiveXObject) {
for (var i = 0; i < MSXML.length; i++) {
try {
doc = new ActiveXObject(MSXML[i]);
} catch (e) { }
}
if (!doc) {
alert("Cannot create XMLDocument object");
return false;
}
}
return doc;
}

function parseXMLUrl(xmlURL) {
var doc = createDocument();

if (doc && typeof doc.load != 'undefined') {
doc.async = false;
doc.load(xmlURL);
return doc;
} else {
var request = new XMLHttpRequest();
request.open("GET", xmlURL, false);
request.send("");
return request.responseXML;
}
}

var xmlDoc = parseXMLUrl('gardenpt1.xml');
var records = xmlDoc.getElementsByTagName("pt");
alert(records.length);
------------------------------------

Thanks for visiting my blog. You can subscribe to it to get more useful Javascript Libraries.

Regards,
Roman

andry said...

xml is a very interesting language to be used and contain the data object model or abbreviated DOM.tutorial very good and hopefully can help me in building a web application thanks

Construction Cleaning Honolulu said...

Great post much appreciate the time you took to write this

Post a Comment

your thoughts are welcome:

Need more? Leave comments and subscribe to my blog.

.