// SpryXML.js - version 0.4 - Spry Pre-Release 1.6 // // Copyright (c) 2006. Adobe Systems Incorporated. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of Adobe Systems Incorporated nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. var Spry; if (!Spry) Spry = {}; if (!Spry.XML) Spry.XML = {}; if (!Spry.XML.Schema) Spry.XML.Schema = {}; Spry.XML.Schema.Node = function(nodeName) { this.nodeName = nodeName; this.isAttribute = false; this.appearsMoreThanOnce = false; this.children = new Array; }; Spry.XML.Schema.Node.prototype.toString = function (indentStr) { if (!indentStr) indentStr = ""; var str = indentStr + this.nodeName; if (this.appearsMoreThanOnce) str += " (+)"; str += "\n"; var newIndentStr = indentStr + " "; for (var $childName in this.children) { var child = this.children[$childName]; if (child.isAttribute) str += newIndentStr + child.nodeName + "\n"; else str += child.toString(newIndentStr); } return str; }; Spry.XML.Schema.mapElementIntoSchemaNode = function(ele, schemaNode) { if (!ele || !schemaNode) return; // Add all attributes as children to schemaNode! var i = 0; for (i = 0; i < ele.attributes.length; i++) { var attr = ele.attributes.item(i); if (attr && attr.nodeType == 2 /* Node.ATTRIBUTE_NODE */) { var attrName = "@" + attr.name; // We don't track the number of times an attribute appears // in a given element so we only handle the case where the // attribute doesn't already exist in the schemaNode.children array. if (!schemaNode.children[attrName]) { var attrObj = new Spry.XML.Schema.Node(attrName); attrObj.isAttribute = true; schemaNode.children[attrName] = attrObj; } } } // Now add all of element's element children as children of schemaNode! var child = ele.firstChild; var namesSeenSoFar = new Array; while (child) { if (child.nodeType == 1 /* Node.ELEMENT_NODE */) { var childSchemaNode = schemaNode.children[child.nodeName]; if (!childSchemaNode) { childSchemaNode = new Spry.XML.Schema.Node(child.nodeName); if (childSchemaNode) schemaNode.children[child.nodeName] = childSchemaNode; } if (childSchemaNode) { if (namesSeenSoFar[childSchemaNode.nodeName]) childSchemaNode.appearsMoreThanOnce = true; else namesSeenSoFar[childSchemaNode.nodeName] = true; } Spry.XML.Schema.mapElementIntoSchemaNode(child, childSchemaNode); } child = child.nextSibling; } }; Spry.XML.getSchemaForElement = function(ele) { if (!ele) return null; schemaNode = new Spry.XML.Schema.Node(ele.nodeName); Spry.XML.Schema.mapElementIntoSchemaNode(ele, schemaNode); return schemaNode; }; Spry.XML.getSchema = function(xmlDoc) { if (!xmlDoc) return null; // Find the first element in the document that doesn't start with "xml". // According to the XML spec tags with names that start with "xml" are reserved // for future use. var node = xmlDoc.firstChild; while (node) { if (node.nodeType == 1 /* Node.ELEMENT_NODE */) break; node = node.nextSibling; } return Spry.XML.getSchemaForElement(node); }; Spry.XML.nodeHasValue = function(node) { if (node) { var child = node.firstChild; if (child && child.nextSibling == null && (child.nodeType == 3 /* Node.TEXT_NODE */ || child.nodeType == 4 /* CDATA_SECTION_NODE */)) return true; } return false; }; Spry.XML.XObject = function() { }; Spry.XML.XObject.prototype._value = function() { var val = this["#text"]; if (val != undefined) return val; return this["#cdata-section"]; }; Spry.XML.XObject.prototype._hasValue = function() { return this._value() != undefined; }; Spry.XML.XObject.prototype._valueIsText = function() { return this["#text"] != undefined; }; Spry.XML.XObject.prototype._valueIsCData = function() { return this["#cdata-section"] != undefined; }; Spry.XML.XObject.prototype._propertyIsArray = function(prop) { var val = this[prop]; if (val == undefined) return false; return (typeof val == "object" && val.constructor == Array); }; Spry.XML.XObject.prototype._getPropertyAsArray = function(prop) { var arr = []; var val = this[prop]; if (val != undefined) { if (typeof val == "object" && val.constructor == Array) return val; arr.push(val); } return arr; }; Spry.XML.XObject.prototype._getProperties = function() { var props = []; for (var p in this) { if (!/^_/.test(p)) props.push(p); } return props; }; Spry.XML.nodeToObject = function(node) { if (!node) return null; var obj = new Spry.XML.XObject(); // Add all attributes as properties of the object. for (var i = 0; i < node.attributes.length; i++) { var attr = node.attributes[i]; var attrName = "@" + attr.name; obj[attrName] = attr.value; } var child; if (Spry.XML.nodeHasValue(node)) { try { child = node.firstChild; if (child.nodeType == 3 /* TEXT_NODE */) obj[child.nodeName] = Spry.Utils.encodeEntities(child.data); else if (child.nodeType == 4 /* CDATA_SECTION_NODE */) obj[child.nodeName] = child.data; } catch (e) { Spry.Debug.reportError("Spry.XML.nodeToObject() exception caught: " + e + "\n"); } } else { // The node has no value, so run through any element children // it may have and add them as properties. child = node.firstChild; while (child) { if (child.nodeType == 1 /* Node.ELEMENT_NODE */) { var isArray = false; var tagName = child.nodeName; if (obj[tagName]) { if (obj[tagName].constructor != Array) { var curValue = obj[tagName]; obj[tagName] = new Array; obj[tagName].push(curValue); } isArray = true; } var childObj = Spry.XML.nodeToObject(child); if (isArray) obj[tagName].push(childObj); else obj[tagName] = childObj; } child = child.nextSibling; } } return obj; }; // Spry.XML.documentToObject - Utility method for creating a // JavaScript object with properties and nested objects that // mirror an XML document tree structure. // // Sample XML: // // // // John Doe // // // // // // // Object returned by documentToObject(): // // { // employees: // { // employee: // [ // { // @id: "1000", // name: { "#text": "John Doe" } // }, // { // @id: "2000", // name: { "#cdata-section": "Jane Smith" } // } // ] // } // } Spry.XML.documentToObject = function(xmlDoc) { var obj = null; if (xmlDoc && xmlDoc.firstChild) { var child = xmlDoc.firstChild; while (child) { if (child.nodeType == 1 /* Node.ELEMENT_NODE */) { obj = new Spry.XML.XObject(); obj[child.nodeName] = Spry.XML.nodeToObject(child); break; } child = child.nextSibling; } } return obj; };