sorting XML into an Object OOP and finding reference loops

Post Reply
darknkreepy3#
Site Admin
Posts: 247
Joined: Tue Oct 27, 2009 9:33 pm

sorting XML into an Object OOP and finding reference loops

Post by darknkreepy3# »

So, XML is a great way to store simple data, and get it into a program. That being said, it is also really hard to read, parse, unless you are up on your regular expressions, looping with endless loop bugs, etc. Letting AS2 and the much better AS3 is a great idea. But, if you ever wanted to understand how to parse something in XML with AS2 and the lost, missing, warped, incomplete tutorials have you hanging, here is my simple import engine I wrote. A SIMPLE version not meant for heavy use, just a few branches on a few hundred nodes is about what it can handle.

Scripting in AS2 is a hassle for sorting and node ordering because of it's limit of 256 loop branches or jumps per 'frame' of 'video' (fps). So, to get around that I just wrote a callback that freezes after counting how many branchings happened. I modulated the number until it always worked and it isn't perfect or incredibly fast like a compiled code module would be in C++ but it works, and you can see the inner workings of XML to an Object Model Node.

http://www.supercala.net/tuts/xml_oop/gallery.zip

Here is the code for now:

loadXML2.as
XML Loader function

Code: Select all

//loadXML2.as by kristoffe brodeur
//v2.0 01-11-2007
//----------
function loadXML(lX_targetObj)
	{
	trace("[loadXML]("+lX_targetObj.filename+")");
	lX_targetObj.onLoad=function(success)
		{
		//success is a binary function; positive on a good load
		if(success)
			{
			tF_debug.text+="XML loaded.";
			//this refers to the onLoad parent, dataXML, which is the actual XML data
			//therefore, onLoad is just an attribute and fucntion of the main object dataXML
			//tF_debug.text+=newline+"data:"+lX_targetObj;		
			lX_targetObj.loadAction();
			}//if
		}//f()
	lX_targetObj.ignoreWhite=true;
	lX_targetObj.load(lX_targetObj.filename);
	}//f()
the actual module sitting simply in a MC [and the needed *.as files]

Code: Select all

#include "../../../createMovieClip2.as"
#include "../../../loadXML2.as"
#include "../../../deepClone3.as"
#include "../../../DispTree.as"
//#include "../arrayFunctions.as" removed to get rid of unnecessary array functions
//-----
//09-15-2008	parse xml v2 by Kristoffe Brodeur. ©2008 All Rights Reserved.
//10-27-2008	adding object->xml for output back to normal xml parsing and php output
//10-30-2008	added T1.AP['cn'] to list the child node XML nodes that a parent object would have, saves wasted looping later in conversion
//03-01-2009	making the output very clear, clean, and a Class
//03-04-2009	rewrote entire Back2XMl for proper branch searching and optimal speed
//-----
Back2XML.prototype.stackChk=function()
	{
	//trace("stackChk>");
	len=this.nodeStack.length;
	tgt=this.nodeStack[len-1];
	tgt.pos++;
	//loop
	if(tgt.pos<tgt.cnt)
		{
		//trace("cnt "+tgt.cnt+" | "+tgt.pos);
		//array of node names
		if(tgt.bNode.cn!=undefined)
			{
			//trace("cn=true");
			nN=tgt.bNode.cn[tgt.pos];
			this.AP=tgt.bNode[nN];
			//
			if(tgt.pos>0)
				{
				nN_prev=tgt.bNode.cn[tgt.pos-1];
				this.xmlStr+="</"+nN_prev+">";
				}
			this.stackAdd();
			}
		//array of object nodes
		else
			{
			tgt2=this.nodeStack[len-2];
			this.AP=tgt.bNode[tgt.pos];
			nN=tgt2.bNode.cn[tgt2.pos];
			//
			if(tgt.pos>0)
				{
				this.xmlStr+="</"+nN+">";
				}
			//trace("cn=false");
			this.xmlStr+="<"+nN+">";
			//trace("**"+this.xmlStr);
			this.stackAdd();
			}
		}
	//pop stack or add text string
	else
		{
		//trace("end of loop.");
		//
		if(tgt.cnt!=undefined)
			{
			//
			if(tgt.bNode.cn!=undefined)
				{
				nN=tgt.bNode.cn[tgt.pos-1];
				//trace("CN!");
				this.xmlStr+="</"+nN+">";
				//trace(this.xmlStr);
				}
			//
			else
				{
				//this.xmlStr+="</#>";
				}
			this.nodeStack.pop();
			}
		//
		else
			{
			//trace("textual node.");
			this.xmlStr+=this.AP.DATA
			//this.xmlStr+="</"+this.AP.ID+">";
			//trace(this.xmlStr+newline);
			this.nodeStack.pop();
			}
		//
		if(this.nodeStack.length>0)
			{
			this.stackChk();
			}
		//
		else
			{
			//trace("END.");
			trace(this.xmlStr);
			this._caller.outputAction(this.xmlStr);
			}
		}
	}
//-----
Back2XML.prototype.stackAdd=function()
	{
	//trace("stackAdd>");
	len=this.nodeStack.length;
	//
	if(this.AP.cn!=undefined)
		{
		tgt=this.nodeStack[len]=new Object();
		tgt.cnt=this.AP.cn.length;
		tgt.pos=-1;
		tgt.bNode=this.AP;
		//trace("nN["+len+"]---->"+"cn[A]("+this.AP.cn+") cnt "+tgt.cnt+" | pos "+tgt.pos);		
		this.stackChk();
		}
	//
	else
		{
		tgt=this.nodeStack[len]=new Object();
		tgt.cnt=this.AP.length;
		tgt.pos=-1;
		tgt.bNode=this.AP;
		//trace("nN["+len+"]---->obj[A] cnt "+tgt.cnt+" | pos "+tgt.pos);
		this.stackChk();
		}
	}
//-----
Back2XML.prototype.init=function()
	{
	//trace("init>");
	this.AP=_XML;//array pointer
	this.recursion=0;
	clearArray(this.nodeStack);
	this.AP=_XML;//defined outside as an Object that the XML file is OOP parsed into
	this.xmlStr="";
	this.stackAdd();
	}
//-----
//same as arrayFunctions2.as clearArray
function clearArray(sArr)
	{
	lenSA=sArr.length;
	//
	for(clrA=0;clrA<lenSA;clrA++)
		{
		sArr.pop();
		}
	}
//-----
function Back2XML(sCaller)
	{
	this._caller=sCaller;		
	//trace("Back2XML>");
	this.nodeStack=new Array();
	this.init();
	}
//-----
function done_sort()
	{
	trace("done_sort>");
	trace("--------------------");
	this.parseAction();
	/*
	T1.tmp1=new DeepClone();
	//pushCopy(base array,node to copy,new node to copy to,should new text nodes be clear?)
	T1.tmp1.pushCopy(_XML.db[0].branch,0,null,null);
	T1.tmp1.cloneAction=function()
		{
		trace("cloning complete!");
		//E1=new DispTree(_XML);
		test1=new Back2XML();
		}
	T1.tmp1.go();
	//show_videos();
	//T1.test=new Back2XML();
	trace("--------------------");
	//Btest=new DispTree(_XML);
	*/
	}
//-----
function coolDown()
	{
	T1.recursion=-1;
	T1.recPause=new TimerA(T1.root,11);
	T1.recPause.timerAction=function()
		{
		//trace("DONE!");
		incr_stack1();
		}
	}
//-----
function check_recursion()
	{
	//trace("check_recursion>");
	T1.recursion++;
	//
	if(T1.recursion>25)
		{
		//trace("cooling down");
		coolDown();
		}
	else{incr_stack1();}
	}
//-----
function node_pop()
	{
	//remove selected node
	//trace("node_pop>");	
	}
//-----
function node_push(sBase,sNode)
	{
	//duplicate selected node
	//trace("node_push>");
	//trace(sBase);
	//trace(sNode);
	T1.cloned=new DeepClone(sBase,sNode,null,"push");
	T1.cloned._par=T1.root;
	T1.cloned.cloneAction=function()
		{
		//trace("finished node_push.");
		this._par.cloneAction();
		}
	T1.cloned.go();
	}
//-----
function Node(sName,sData)
	{
	this.ID=sName;
	this.DATA=sData;
	}
//-----
function addObjNode()
	{
	cnt=T1.nodeStack.length;
	nName=T1.nodeStack[cnt-1];//0 counts in an array, so cnt-1 is the position of the end node
	nExist=false;
	//
	if(T1.AP[nName]==undefined)
		{
		T1.AP[nName]=new Array();
		}
	//
	else
		{
		nExist=true;
		}
	if(T1.AP['cn']==undefined){T1.AP['cn']=new Array();}//holds xml node names in parent
	cnt=T1.AP[nName].length;
	T1.AP[nName][cnt]=new Node(nName,"");
	//T1.AP['cn'].push(nName);
	//
	if(nExist==false)
		{
		T1.AP['cn'].push(nName);
		}
	//
	//only the first node parent doesnt have an ID or DATA
	begN="<"+nName+">";
	//trace(begN);
	T1.stringXML+=begN;
	T1.AP.chi_pnt=T1.AP[nName][cnt];
	parPtr=T1.AP;
	T1.AP=T1.AP[nName][cnt];
	T1.AP.par_pnt=parPtr;
	}
//-----
function addTextNode()
	{
	tgt=T1.xPtr.childNodes[T1.xPtr.pos];
	text1=tgt.nodeValue;
	//trace(text1);	
	text1fix="";
	tl=text1.length;
	for(i=0;i<tl;i++)
		{
		c1=text1.substr(i,1);
		//
		if(c1=="&")
			{
			text1fix+="&";
			}
		else
			{
			text1fix+=c1;
			}
		}
	cnt=T1.nodeStack.length;
	nName=T1.nodeStack[cnt-1];
	//T1.AP already points to the new node in the dynamic array one step previous when called and made in addObjNode
	cnt=T1.AP[nName].length;
	T1.AP.DATA=text1fix;
	T1.stringXML+=text1fix;
	}
//-----
function decr_stack1()
	{
	//trace("decr_stack1>");
	//
	if(T1.nodeStack.length>0)
		{
		endX="</"+T1.nodeStack[T1.nodeStack.length-1]+">";
		//trace(endX);
		T1.stringXML+=endX;
		}
	T1.nodeStack.pop();
	T1.xPtr=T1.xPtr.par_pnt;
	T1.AP=T1.AP.par_pnt;
	incr_stack1();
	}
//-----
function change_pointer()
	{
	//trace("change_pointer>");
	//
	if(T1.xPtr.pos<T1.xPtr.cnt)
		{
		//trace("changing...");
		par1=T1.xPtr;
		T1.xPtr=T1.xPtr.childNodes[T1.xPtr.pos];
		T1.xPtr.par_pnt=par1;
		check_recursion();
		}
	}
//-----
function incr_stack2()
	{
	//trace("incr_stack2>");
	cnt=T1.xPtr.childNodes.length;
	//trace(cnt);
	//
	if(T1.xPtr.pos==undefined)
		{
		T1.xPtr.pos=-1;//start at -1 so it will roll to 0 with ++
		T1.xPtr.cnt=cnt;//how many children are there?
		}
	T1.xPtr.pos++;
	//
	if(T1.xPtr.pos<T1.xPtr.cnt)
		{
		//trace(T1.xPtr.pos);
		pos=T1.xPtr.pos;
		nName=T1.xPtr.childNodes[pos].nodeName;
		//
		if(nName!=null)
			{
			//trace("?"+nName);
			T1.nodeStack.push(nName);
			addObjNode();
			//trace("added");
			change_pointer();
			}
		else
			{
			addTextNode();
			decr_stack1();
			}
		}
	else{decr_stack1();}
	}
//-----
function incr_stack1()
	{
	//trace("incr_stack1>");
	len=T1.xPtr.childNodes.length;
	//
	if(len>0){incr_stack2();}
	//
	else{
		stackPos=T1.nodeStack.length;
		//
		if(stackPos>0){decr_stack1();}
		//
		else{done_sort();}
		}
	}
//-----
function parse_XML()
	{
	trace("f(parse_XML)");
	T1.stringXML="";
	T1.recursion=0;
	T1.nodeStack=new Array();
	T1.xPtr=T1.e_XML;
	incr_stack1(T1.xPtr);
	}
//-----
function l_XML()
	{
	trace("f(l_XML)");	
	T1.e_XML=new XML();
	T1.e_XML.filename=T1.filename;
	T1.e_XML.loadAction=function(){parse_XML();}
	loadXML(T1.e_XML);
	}
//-----
function main(sFilename)
	{
	T1.filename=sFilename;
	tF_debug.text="main>"+sFilename;
	//trace("main>"+sFilename);
	T1.XML_ok=false;
	delete T1.AP;
	delete T1.root._XML;
	T1.root._XML=new Object();
	T1.AP=_XML;
	l_XML();
	}
//-----
var T1=new Object();
T1.root=this;
//trace("parser ready. send the *.xml filename to main(*); to begin.");
//main("ev1.xml");
//main("branchtest.xml");
All as a zip
Post Reply