//xml 轻量xml解析
namespace string;

var push = ..table.push;
var pop = ..table.pop;
var sub = sub;
var trim = trim;
var find = find;
var match = match;
var sub = sub;

var function parseProperties (ele, str) { 
	replace(
		str, 
		"(\w+)\s*=\s*([""'])(.*?)\2", 
		function (w, a, b){
    		ele[w] = b
		} 
	) 
}

var function pushEle(parent,ele){
	parent[ele.tag] = type(parent[ele.tag])==type.table?parent[ele.tag]:{};
	push( parent[ele.tag],ele );
	push( parent,ele );
} 

class xml{
	ctor( xmlstr ){
		var nodeStack = {};
		var topNode = this;
		push(nodeStack, topNode);  
 	
		var strfrom = 1;  
		var tagfrom,tagto //find pos
				,slash_front ,tag ,properties, slash_back = find(xmlstr, "\<([\/\?]?)(<[\w_:]+>|<:+>)(.*?)([\/\?]?)\>", strfrom);
				
		while(tagfrom) { 
		
			var innerText = sub(xmlstr, strfrom, tagfrom-1)
			var innerText = trim(innerText);
			if( #innerText ){ 
				push(topNode, innerText) 
				topNode.innerText = innerText
			}
			
			if #slash_back   {  
				//empty ele e.g. <tag />
				var tab = {  tag=tag; empty_ele=1}
				parseProperties( tab,properties);
				pushEle(topNode,tab)
			}
			elseif slash_front  != "/"  {  
			 	// open tag e.g. <tag prop="value" >
				topNode = { tag=tag }
				parseProperties( topNode,properties);
				push(nodeStack, topNode)   // new level
			}
			else {
				// close tag  e.g. </tag>
				var ele = ..table.pop(nodeStack)  // pop top
				topNode = nodeStack[#nodeStack]
			 	
				if #nodeStack < 1 {
					error("nothing to close with "+ tag)
				}
				if ele.tag != tag {
					error("trying to close <" + ele.tag + "> with </" + tag + ">")
				}
				pushEle(topNode, ele)
			}
			
			strfrom = tagto+1 
			tagfrom,tagto,slash_front ,tag,properties, slash_back = find(xmlstr, "\<([\/\?]?)(<[!\w_:]+>|<:+>)(.*?)([\/\?]?)\>" , strfrom);
				 
			if( tagfrom && xmlstr[tagfrom+1]=='!'#  ) { 
				//e.g <![CDATA[ ..... ]]>
				if( sub(xmlstr,tagfrom,tagfrom+8 ) == "<![CDATA[" ){ 
					var cdata = match(xmlstr,"(.+?)<@]]>@>", tagfrom+9)
					if(cdata){ 
						topNode.cdata = cdata;
						strfrom = tagfrom + 12 + #cdata
						tagfrom,tagto,slash_front ,tag,properties, slash_back =  find(xmlstr, "\<([\/\?]?)(<[!\w_:]+>|<:+>)(.*?)([\/\?]?)\>" , strfrom);
					}
				} 
			}
		}
		
		var innerText = sub(xmlstr, strfrom)
		var innerText = trim(innerText);
		if( #innerText ){  
			push(nodeStack[#nodeStack], text)
		}
	  	
		if #nodeStack> 1 {
			error("unclosed " + nodeStack[#nodeStack].tag)
		} 
	}; 
}

 

/**intellisense()
string.xml = xml解析
string.xml(__/*xml字符串*/) = 创建xml对象.
?string.xml = !xml.
end intellisense**/
 