/* License: GNU Lesser General Public License (http://www.gnu.org/licenses/lgpl.html) Copyright (C) 2005 tagnetic.org. Please do not remove this copyright/license comment. */ //************************************************************************* //Start cross-browser extras useBrowserExtras //************************************************************************* /** * Defines a DOMParser class that is usable in Mozilla, Safari, IE and Opera. * Taken directly from: http://erik.eae.net/archives/2005/07/03/20.19.18/ * * Example usage: * var parser = new DOMParser(); * var xmlDom = parser.parseFromString(xmlString); * * Then you can use the normal DOM methods to work with the XML. */ if (typeof DOMParser == "undefined") { DOMParser = function () {}; DOMParser.prototype.parseFromString = function (str, contentType) { if (typeof ActiveXObject != "undefined") { var d = new ActiveXObject("MSXML.DomDocument"); d.loadXML(str); return d; } else if (typeof XMLHttpRequest != "undefined") { var req = new XMLHttpRequest; req.open("GET", "data:" + (contentType || "application/xml") + ";charset=utf-8," + encodeURIComponent(str), false); if (req.overrideMimeType) req.overrideMimeType(contentType); req.send(null); return req.responseXML; } } } /** * Adds an Array.filter method if it doesn't already exist. * Taken directly from: * http://erik.eae.net/playground/arrayextras/ * Also see Erik's blog post: * http://erik.eae.net/archives/2005/06/05/17.53.19/ */ //http://developer-test.mozilla.org/docs/Core_JavaScript_1.5_Reference:Objects:Array:filter if (!Array.prototype.filter) { Array.prototype.filter = function (f, obj) { var l = this.length; // must be fixed during loop... see docs var res = []; for (var i = 0; i < l; i++) { if (f.call(obj, this[i], i, this)) res.push(this[i]); } return res; }; } //************************************************************************* //End cross-browser extras //************************************************************************* //************************************************************************* //Start SimpleDom useSimpleDom //************************************************************************* SDom = { //************************************************************************* /** * Factory for creating a simple dom object. * * @param {Object} domNode: A DOM Node. Can be a DOM Document. * * @param {String} rootElement: If domNode is a DOM Document, * specify a root element to use as the first SimpleDom object. * * For the following XML document: * * * A SimpleDom object will have * the following structure: * node._sdNode = true. Use to find out if this is a SimpleDom node. * node._n = String. The node name (typically element name). * node._v = String .If there was only one child for this node, and that node * was a text or cdata node. If there are more than one text/cdata nodes, * or text/cdata nodes mixed with element nodes, this property will not * be defined. * node._a = a hashmap object of attributes. For instance, use node._a['foo'] * or nod._a.foo to access the foo attribute of a node. * node._c = an array of the child elements, in the order that they appear in the * XML. If there were no children, or if the only child was a text/cdata * node, then this property will not be defined. * * In addition to child elements being stored in the _c array, child elements are * also stored off the node by their nodeName. So, if there was a * element under the node, it could be accessed by: * * node.phonenumber or node['phonenumber'] * * If there are more than one child element with the same name (for instance, * more than one element), then that name will be an array: * * node.phonenumber.length would give the length of the array. * * To find out if a named member of a node is just a SimpleDom object or an array * of SimpleDomObjects, the ._n and ._v properties will be undefined for an array. * Also, there will be no ._sdNode = true property. * So for the phonenumber case where it is an array, * * node.phonenumber._n or node.phonenumber._v or node._sdNode * * will be undefined. You could use a: * * typeof(node.phonenumber._sdNode) == 'undefined') * or * !node.phonenumber._sdNode * * check to see if it is an array. Testing for node.phonenumber.length is not * advised, since length could be used as the name of an element in the DOM. * * Notes: * - It may not work so well with XML elements that start with an underscore (_). * - It does not support names spaces officially. Whatever is returned * by the DOM property node.nodeName is used as the name of the node. * - It is mostly useful for creating a read-only JavaScript structure. * There is a SDom.serialize that will convert a SimpleDom structure to * an XML string, but that XML is not guaranteed to be equivalent to * the XML that was used to create the SimpleDom. * - Only Element, CDATA and Text nodes are processed. */ create: function(domNode, rootElementName) { var result = null; //If this is a document node, find root element and start with that. if (domNode.nodeType == 9) { if (rootElementName) { var roots = domNode.getElementsByTagName(rootElementName); if (roots && roots[0]) result = new SDom._construct(roots[0]); } } return result; }, //************************************************************************* /** * Class method to convert a SimpleDom to a string. Does not guarantee that * the string output will match the XML string that was used to create a * SimpleDom. */ serialize: function(simpleDom) { var result = ''; if (!simpleDom) return result; //If the simpleDom is an array, then call the serialize method for each //item in the array. if (simpleDom instanceof Array) { for (var index = 0; index < simpleDom.length; index++) result += SDom.serialize(simpleDom[index]); return result; } //If not an array, Make sure it is a simple dom node. //If not, it must be a string (or something that can convert //properly to a string). if (!simpleDom._sdNode) return simpleDom; //Get the attributes var attributes = ''; if (simpleDom._a) { for (var param in simpleDom._a) attributes += ' ' + param + '="' + simpleDom._a[param] + '"'; } //If no value or children, empty node. if (typeof(simpleDom._v) == 'undefined' && typeof(simpleDom._c) == 'undefined') return '<' + simpleDom._n + attributes + ' />'; //Make the start tag result = '<' + simpleDom._n + attributes + '>'; if (simpleDom._v) result += simpleDom._v; else if (simpleDom._c) { result += SDom.serialize(simpleDom._c); } result += ''; return result; }, //************************************************************************* //************************************************************************* //************************************************************************* /** * @private Constructor for creating a simple dom object. * Do not call this method directly. * Use the factory method SDom.create() instead. */ _construct: function(domNode, rootElementName) { //Set a property indicating this object is a simple dom node. //Some of things attached in a simple dom structure will just //be strings (for text and cdata nodes). this._sdNode = true; this._n = domNode.nodeName; //Get the attributes var attributes = domNode.attributes; var i, node; if (attributes && attributes.length > 0) { this._a = new Object(); for (i = 0; i < attributes.length; i++) { node = attributes.item(i); this._a[node.nodeName] = node.nodeValue; } } //Get the children var childIndex = 0; var namedChildList; var children = domNode.childNodes; if (children && children.length > 0) { //Find out if there is only one child and if it is a text node (3) or cdata node (4). if (children.length == 1 && (children[0].nodeType == 3 || children[0].nodeType == 4)) { this._v = children[0].nodeValue; } else { this._c = new Array(); //Iterate through children and add to the dom. for (i = 0; i < children.length; i++) { node = children[i]; //Only handling text, cdata and other elements right now. switch(node.nodeType) { case 1: //Element this._c[childIndex] = new SDom._construct(node); //Also add the child as a named property of the node. if (!this[node.nodeName]) this[node.nodeName] = this._c[childIndex]; else { if (this[node.nodeName]._sdNode) { //If the named property is a sdom node already, //convert the named property into an array. var temp = this[node.nodeName]; this[node.nodeName] = new Array(); this[node.nodeName].push(temp); } this[node.nodeName].push(this._c[childIndex]); } childIndex++; break; case 3: //Text Node case 4: //CData Node this._c[childIndex] = node.nodeValue; childIndex++; break; } } } } } } //************************************************************************* //End SimpleDom //*************************************************************************