dojo.provide("dojox.xml.DomParser"); dojox.xml.DomParser=new (function(){ /********************************************************** * The DomParser is a close-to (but not entirely) * conforming XML parser based on regular * expressions. It will take any XML fragment * and return a lightweight JS structure that is * similar to (but not exactly) the DOM specification. * * Getter and setter methods are NOT available; the goal * was to keep the resulting object model entirely JS-like. * * All node types but document fragments are supported; * all nodes support getElementsByTagName and * getElementsByTagNameNS (with short names byName and * byNameNS). The document node supports getElementById * (byId), and all nodes support a supplimental * childrenByName/childrenByNameNS method as well. * * The object model is intended to be a READONLY format; * mutation events are NOT supported, and though you * can change properties on a node-by-node basis, certain * operations are not supported (such as changing the ID * of an element). **********************************************************/ // internal use only. var nodeTypes={ ELEMENT:1, ATTRIBUTE:2, TEXT:3, CDATA_SECTION:4, PROCESSING_INSTRUCTION:7, COMMENT:8, DOCUMENT:9 }; // compile the regular expressions once. var reTags=/<([^>\/\s+]*)([^>]*)>([^<]*)/g; var reAttr=/([^=]*)=(("([^"]*)")|('([^']*)'))/g; // patch from tdedischew AT gmail, with additional grouping var reEntity=//g; var reCData=//g; var reComments=//g; var trim=/^\s+|\s+$/g; var normalize=/\s+/g; var egt=/\>/g; var elt=/\</g; var equot=/\"/g; var eapos=/\'/g; var eamp=/\&/g; var dNs="_def_"; // create a root node. function _doc(){ return new (function(){ var all={}; this.nodeType=nodeTypes.DOCUMENT; this.nodeName="#document"; this.namespaces={}; this._nsPaths={}; this.childNodes=[]; this.documentElement=null; // any element with an ID attribute will be added to the internal hashtable. this._add=function(obj){ if(typeof(obj.id)!="undefined"){ all[obj.id]=obj; } }; this._remove=function(id){ if(all[id]){ delete all[id]; } }; this.byId=this.getElementById=function(id){ return all[id]; }; this.byName=this.getElementsByTagName=byName; this.byNameNS=this.getElementsByTagNameNS=byNameNS; this.childrenByName=childrenByName; this.childrenByNameNS=childrenByNameNS; })(); } // functions attached to element nodes function byName(name){ // return all descendants with name. Fully qualified (i.e. svg:svg) function __(node, name, arr){ dojo.forEach(node.childNodes, function(c){ if(c.nodeType==nodeTypes.ELEMENT){ if(name=="*"){ arr.push(c); } else if(c.nodeName==name){ arr.push(c); } __(c, name, arr); } }); } var a=[]; __(this, name, a); return a; } function byNameNS(name, ns){ // return all descendants with name by namespace. If no namespace passed, the default is used. function __(node, name, ns, arr){ dojo.forEach(node.childNodes, function(c){ if(c.nodeType==nodeTypes.ELEMENT){ if(name=="*"&&c.ownerDocument._nsPaths[ns]==c.namespace){ arr.push(c); } else if(c.localName==name&&c.ownerDocument._nsPaths[ns]==c.namespace){ arr.push(c); } __(c, name, ns, arr); } }); } if(!ns){ ns=dNs; } var a=[]; __(this, name, ns, a); return a; } // Only child nodes with name. function childrenByName(name){ var a=[]; dojo.forEach(this.childNodes, function(c){ if(c.nodeType==nodeTypes.ELEMENT){ if(name=="*"){ a.push(c); } else if(c.nodeName==name){ a.push(c); } } }); return a; } function childrenByNameNS(name, ns){ var a=[]; dojo.forEach(this.childNodes, function(c){ if(c.nodeType==nodeTypes.ELEMENT){ if(name=="*"&&c.ownerDocument._nsPaths[ns]==c.namespace){ a.push(c); } else if(c.localName==name&&c.ownerDocument._nsPaths[ns]==c.namespace){ a.push(c); } } }); return a; } function _createTextNode(v){ return { nodeType:nodeTypes.TEXT, nodeName:"#text", nodeValue:v.replace(normalize," ").replace(egt,">").replace(elt,"<").replace(eapos,"'").replace(equot,'"').replace(eamp,"&") }; } // attribute functions function getAttr(name){ for(var i=0; i0){ return p.childNodes[i-1]; } } } return null; } function next(){ var p=this.parentNode; if(p){ for(var i=0;i0){ var entity, eRe=[]; if(reEntity.test(str)){ reEntity.lastIndex=0; // match entities while((entity=reEntity.exec(str))!=null){ eRe.push({ entity:"&"+entity[1].replace(trim,"")+";", expression:entity[2] }); } // replace instances in the document. for(var i=0; i1){ if(obj.parentNode){ obj=obj.parentNode; } var text=(res[3]||"").replace(trim, ""); if(text.length>0) { obj.childNodes.push(_createTextNode(text)); } } // open tags. else if(res[1].length>0){ // figure out the type of node. if(res[1].charAt(0)=="?"){ // processing instruction var name=res[1].substr(1); var target=res[2].substr(0,res[2].length-2); obj.childNodes.push({ nodeType:nodeTypes.PROCESSING_INSTRUCTION, nodeName:name, nodeValue:target }); } else if(res[1].charAt(0)=="!"){ // CDATA; skip over any declaration elements. if(res[1].indexOf("![CDATA[")==0){ var val=parseInt(res[1].replace("![CDATA[","").replace("]]","")); obj.childNodes.push({ nodeType:nodeTypes.CDATA_SECTION, nodeName:"#cdata-section", nodeValue:cdSections[val] }); } // Comments. else if(res[1].substr(0,3)=="!--"){ var val=parseInt(res[1].replace("!--","").replace("--","")); obj.childNodes.push({ nodeType:nodeTypes.COMMENT, nodeName:"#comment", nodeValue:comments[val] }); } } else { // Elements (with attribute and text) var name=res[1].replace(trim,""); var o={ nodeType:nodeTypes.ELEMENT, nodeName:name, localName:name, namespace:dNs, ownerDocument:root, attributes:[], parentNode:null, childNodes:[] }; // check to see if it's namespaced. if(name.indexOf(":")>-1){ var t=name.split(":"); o.namespace=t[0]; o.localName=t[1]; } // set the function references. o.byName=o.getElementsByTagName=byName; o.byNameNS=o.getElementsByTagNameNS=byNameNS; o.childrenByName=childrenByName; o.childrenByNameNS=childrenByNameNS; o.getAttribute=getAttr; o.getAttributeNS=getAttrNS; o.setAttribute=setAttr; o.setAttributeNS=setAttrNS; o.previous=o.previousSibling=prev; o.next=o.nextSibling=next; // parse the attribute string. var attr; while((attr=reAttr.exec(res[2]))!=null){ if(attr.length>0){ var name=attr[1].replace(trim,""); var val=(attr[4]||attr[6]||"").replace(normalize," ") .replace(egt,">") .replace(elt,"<") .replace(eapos,"'") .replace(equot,'"') .replace(eamp,"&"); if(name.indexOf("xmlns")==0){ if(name.indexOf(":")>0){ var ns=name.split(":"); root.namespaces[ns[1]]=val; root._nsPaths[val]=ns[1]; } else { root.namespaces[dNs]=val; root._nsPaths[val]=dNs; } } else { var ln=name; var ns=dNs; if(name.indexOf(":")>0){ var t=name.split(":"); ln=t[1]; ns=t[0]; } o.attributes.push({ nodeType:nodeTypes.ATTRIBUTE, nodeName:name, localName:ln, namespace:ns, nodeValue:val }); // only add id as a property. if(ln=="id"){ o.id=val; } } } } root._add(o); if(obj){ obj.childNodes.push(o); o.parentNode=obj; // if it's not a self-closing node. if(res[2].charAt(res[2].length-1)!="/"){ obj=o; } } var text=res[3]; if(text.length>0){ obj.childNodes.push(_createTextNode(text)); } } } } // set the document element for(var i=0; i