/* SpryXML.js - Revision: Spry Preview Release 1.4 */



// 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:

//

//		<employees>

//			<employee id="1000">

//				<name>John Doe</name>

//			</employee>

//			<employee id="2000">

//				<name><![CDATA[Jane Smith]]></name>

//			</employee>

//		</employees>

//

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

};


