function XMLDom(){
	//methods
	this.AddRoot=_addroot;
	this.AddElement=_addnode;
	this.AddCDataElement=_addcdatanode;
	this.toXML=_getXML;
	this.AddElementByObj=_addnodebyobj;
	this.GetSingleElement=_getnode;
	this.FromXML=_setXML;
	//
	
	//private vars
	var xmlfrag="";
	var root;
	var bIncludeNewLine=false; 
	//
	
	//private methods
	function _addroot(sRootName){
		if(!ValidateTagName(sRootName)){
			throw sRootName +" is an invalid tagname";
		}
		root=new XMLElement();
		root.TagName=sRootName;
	}
	function _addnode(sTagName,sValue){
		if(sValue==null){sValue='';}
		var el=new XMLElement();
		el.TagName=sTagName;
		el.Value=sValue;
		root.AddChild(el);
	}
	function _addcdatanode(sTagName,sValue){
		if(sValue==null){sValue='';}
		var el=new XMLElement();
		el.TagName=sTagName;
		el.Value=sValue;
		el.IsCData=true;
		root.AddChild(el);
	}
	function _addnodebyobj(el_child){
		root.AddChild(el_child);
	}
	var ret=""; //ref var for _getXML func
	function _getXML(){
		if(xmlfrag!=""){return xmlfrag;}
		ret+="<"+root.TagName+">"+getN();
		childloop(root);
		ret+="</"+root.TagName+">";
		return ret;
	}
	function _setXML(sXML){
		xmlfrag=sXML;
	}
	
	//function to get a single node. Code to get the child nodes of this node TBD
	function _getnode(XPath){
		if(XPath.indexOf("/")==0){ //trim off leading '/'
			XPath=XPath.substring(1,XPath.length);
		}
		
		var nodes=XPath.split("/");
		var indx=0;
		for(var n=0;n<nodes.length;n++){
			if(xmlfrag.indexOf(nodes[n],indx)==-1){
				return null;
			}
			indx=xmlfrag.indexOf(nodes[n],indx)+nodes[n].length+1;
		}
		var endindx=xmlfrag.indexOf("</"+nodes[nodes.length-1],indx);
		var newEl=new XMLElement();
		newEl.TagName=nodes[nodes.length-1];
		newEl.IsCData=false;
		var val=xmlfrag.substring(indx,endindx);
		if(val.indexOf('<![CDATA[')>-1){
			newEl.IsCData=true;
			val=val.replace('<![CDATA[','');
			val=val.replace(']]>','');
		}
		newEl.Value=val;
		return newEl;
	}
	
	//supporting private functions
	function ValidateTagName(sName){
		var regex= new RegExp('[^a-zA-Z0-9_]');
		return !regex.test(sName);
	}
	function getN(){
		if(bIncludeNewLine)
			return "\n";
		else
			return "";
	}
	function getT(){
		if(bIncludeNewLine)
			return "\t";
		else
			return "";
	}
	function childloop(e){
		if(e.ChildElements){
			var el;
			for(var r=0;r<e.ChildElements.length;r++){
				
				el=e.ChildElements[r]
				ret+=createBeginTag(el.TagName);
				if(el.ChildElements.length>0){
					ret+=getN()+getT();
					childloop(el);
					ret+=getN()+getT();
				}else{
					ret+=FormatValue(el.Value,el.IsCData);
				}
				ret+=createEndTag(el.TagName)+getN();
			}
		}
	}
	function createBeginTag(sTagName){
			if(!ValidateTagName(sTagName)){
				throw sTagName +" is an invalid tagname";
			}
			return getT()+"<"+sTagName+">";
	}
	function createEndTag(sTagName){
			return "</"+sTagName+">";
	}
	function FormatValue(sValue,bCDATA){
		if(!bCDATA){
			return sValue;
		}else{
			return "<![CDATA["+sValue+"]]>";
		}
	}
	function createElement(sTagName,sValue,bCDATA){
		if(!bCDATA){
			return "<"+sTagName+">"+sValue+"</"+sTagName+">"+getN();
		}else{
			return "<"+sTagName+"><![CDATA["+sValue+"]]></"+sTagName+">"+getN();
		}
	}
	//end supporting private methods
	

	
}

//XML element object
function XMLElement(){
	this.Value=_val;
	this.TagName=_name;
	this.IsCData=_bcdata;
	this.ChildElements=new Array();
	this.AddChild=_addelement;
	
	var _name="";
	var _val="";
	var _bcdata=false;
			
	function _addelement(child){
		this.ChildElements[this.ChildElements.length]=child;
	}
}

