Tuesday, December 1, 2009

Cross browser XML

One of the more annoying issues I came with is the cross browser issue. And a very important one is managing an XML driven website.

For this reason I created a unified XML handler class. Here it is:

//-------------------------------------------------------------------------------------------------
// browser enumeration helper –holding browser type and version
//-------------------------------------------------------------------------------------------------
var userAgent = navigator.userAgent.toLowerCase();
var browserType = {
    Version : (userAgent.match( /.+(?:rv|it|ra|ie|me)[\/: ]([\d.]+)/ ) || [])[1],
    CHROME : /chrome/.test( userAgent ),
    SAFARI : /webkit/.test( userAgent ) && !/chrome/.test( userAgent ),
    OPERA : /opera/.test( userAgent ),
    IE : /msie/.test( userAgent ) && !/opera/.test( userAgent ),
    MOZILLA : /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
};

//-------------------------------------------------------------------------------------------------
// XmlHandler class
//-------------------------------------------------------------------------------------------------
var XmlHandler = function() {
    //---------------------------------------------------------------------------------------------
    // LoadXML
    // - xmlString: xml string or xml file path
    // - isPath: true/false (true if xmlString is a file path)
    // return: xml document
    //---------------------------------------------------------------------------------------------

    this.LoadXML = function(xmlString, isPath) {
        if (xmlString && IsString(xmlString)) {
            var xDoc, xmlHttp;
            if (isPath) {
                if (window.XMLHttpRequest)
                    xmlHttp = new XMLHttpRequest();
                else
                    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");

                xmlHttp.open("GET", xmlString, false);
                xmlHttp.send();
                xDoc = xmlHttp.responseXML;
            } else {
                if (browserType.IE) {
                    xDoc = new ActiveXObject("MSXML2.DOMDocument")
                    xDoc.async = false;
                    xDoc.loadXML(xmlString);
                    xDoc.setProperty("SelectionLanguage", "XPath");
                } else {
                    var dp = new DOMParser();
                    xDoc = dp.parseFromString(xmlString, "text/xml");
                    xDoc.normalize();
                }
            }
            return xDoc;
        } else {
            return null;
        }
    }

    //---------------------------------------------------------------------------------------------
    // GetFirstItemValue
    // - doc: xml document
    // - nodeName: node name (tag name)
    // return: first node value
    //---------------------------------------------------------------------------------------------
    this.GetFirstItemValue = function(doc, nodeName) {
        var node = doc.getElementsByTagName(nodeName)[0].childNodes[0];
        if (node) {
            if (browserType.IE)
                return node.text;
            else
                return node.nodeValue;
        } else {
            return;
        }
    }

    //---------------------------------------------------------------------------------------------
    // GetNodeAttribute
    // - node: xml node
    // - attributeName: attribute name
    // return: attribute value
    //---------------------------------------------------------------------------------------------
    this.GetNodeAttribute = function(node, attributeName) {
        return node.getAttribute(attributeName);
    }

    //---------------------------------------------------------------------------------------------
    // SelectSingleNode
    // - xmlDoc: xml document
    // - elementPath: xPath
    // return: xml node
    //---------------------------------------------------------------------------------------------
    this.SelectSingleNode = function(xmlDoc, elementPath) {
        if(document.implementation && document.implementation.createDocument) {
            var nodes = xmlDoc.evaluate(elementPath, xmlDoc, null, XPathResult.ANY_TYPE, null);
            var results = nodes.iterateNext();
            return results;
        } else {
            return xmlDoc.selectSingleNode(elementPath);
        }
    }

    //---------------------------------------------------------------------------------------------
    // isString – private
    // - str: string
    // return: string
    //---------------------------------------------------------------------------------------------
    function IsString(str) {
        return str.toString();
    }

    //---------------------------------------------------------------------------------------------
    // ParseResponseText
    // - response: http response object
    // - nodeName: nodeName
    // return: first node value
    //---------------------------------------------------------------------------------------------
    this.ParseResponseText = function(response, nodeName) {
        var data = this.LoadXML(response.responseText);
        return this.GetFirstItemValue(data, nodeName || "string");
    }

};

This class is designed for a specific use, but, I believe that the methods written are useful for most purposes.

Enjoy,