////////////////////////////////////////////////////////// ////////// JSXML XML Tools //////////// ////////// Ver 1.3 Aug 29 2009 //////////// ////////// Copyright 2000-2009 Peter Tracey //////////// ////////// http://levelthreesoltions.com/jsxml/ //// //// Objects: //// //// REXML //// Regular Expression-based XML parser //// //// JSXMLIterator //// Iterates through the tree structure without recursion //// //// JSXMLBuilder //// Loads xml into a linear structure and provides //// interface for adding and removing elements //// and setting attributes, generates XML //// //// Utility functions: //// //// ParseAttribute //// Takes string of attibutes and attribute name //// Returns attribute value //// //// Array_Remove //// Removes element in array //// //// Array_Add //// Adds element to array //// //// RepeatChar //// Repeats string specified number of times //// /////////////////////////////////////////////////////////////// function REXML(XML) { this.XML = XML; this.rootElement = null; this.parse = REXML_parse; if (this.XML && this.XML !== "") this.parse(); } function REXML_parse() { var reTag = new RegExp("<([^>/ ]*)([^>]*)>","g"); // matches that tag name $1 and attribute string $2 var reTagText = new RegExp("<([^>/ ]*)([^>]*)>([^<]*)","g"); // matches tag name $1, attribute string $2, and text $3 var strType = ""; var strTag = ""; var strText = ""; var strAttributes = ""; var strOpen = ""; var strClose = ""; var iElements = 0; var xmleLastElement = null; if (this.XML.length === 0) return; var arrElementsUnparsed = this.XML.match(reTag); var arrElementsUnparsedText = this.XML.match(reTagText); var i=0; if (arrElementsUnparsed[0].replace(reTag, "$1") == "?xml") i++; for (; i -1) strText = arrElementsUnparsedText[i]; else { for (; i0) ? this.elements.length-1 : 0; if (iElemLevel < 0 || typeof(iElemLevel) != "number" || isNaN(iElemLevel)) iElemLevel = this.elements[iElemIndex-1].level; if (!Attributes) Attributes = ""; var Elem = []; var iAddIndex = iElemIndex; if (iElemIndex > 0) { for (var i=iElemIndex; i iElemLevel) iAddIndex++; else if (this.elements[i].level <= this.elements[iElemIndex].level) break; Elem = new JSXMLBuilder_XMLElement(strElement,Attributes,strText,iElemLevel+1,this); } else { Elem = new JSXMLBuilder_XMLElement(strElement,Attributes,strText,1,this); } this.elements = this.elements.add(iAddIndex,Elem); for (var i=iAddIndex; i0) ? this.elements.length-1 : 0; if (iElemLevel < 0 || typeof(iElemLevel) != "number" || isNaN(iElemLevel)) iElemLevel = this.elements[iElemIndex-1].level; if (!Attributes) Attributes = ""; var Elem = null; var iAddIndex = iElemIndex; if (iElemIndex > 0 && iElemLevel > 0) { Elem = new JSXMLBuilder_XMLElement(strElement,Attributes,strText,iElemLevel+1,this); } else { Elem = new JSXMLBuilder_XMLElement(strElement,Attributes,strText,1,this); } this.elements = this.elements.add(iAddIndex,Elem); for (var i=iAddIndex; i this.elements[iElem1Index].level) arrElem1Elements[arrElem1Elements.length] = this.elements[i]; else if (i>iElem1Index) break; for (var i=iElem2Index; i this.elements[iElem2Index].level) arrElem2Elements[arrElem2Elements.length] = this.elements[i]; else if (i>iElem2Index) break; var arrMovedElements = []; if (iElem1Index < iElem2Index) { for (i=0; i]$/gi, ""); if (((this.elements[i+1] && this.elements[i+1].level <= this.elements[i].level) || // next element is a lower or equal to (!this.elements[i+1] && this.elements[i-1])) // no next element, previous element && this.element(i).text === "") { strXML += "/"; } strXML += ">"; if (this.element(i).text !== "") strXML += this.element(i).text; else strXML += "\n"; if (((this.elements[i+1] && this.elements[i+1].level <= this.elements[i].level) || // next element is a lower or equal to (!this.elements[i+1] && this.elements[i-1])) // no next element, previous element && this.element(i).text !== "") strXML += "\n"; if (!this.elements[i+1]) { var lastelem = i; for (var j=i; j>-1; j--) { if (this.elements[j].level >= this.elements[i].level) continue; else { if (this.elements[j].level < this.elements[lastelem].level) { strXML += RepeatChar("\t",this.elements[j].level-1) + "\n"; lastelem = j; } } } } else { if (this.elements[i+1].level < this.elements[i].level) { var lastelem = i; for (var j=i; this.elements[j].level>=this.elements[i+1].level; j--) { if (this.elements[i] && this.elements[j] && this.elements[j].level < this.elements[i].level && this.elements[j].level < this.elements[lastelem].level) { strXML += RepeatChar("\t",this.elements[j].level-1) + "\n"; lastelem = j; } } } } if (strXML.length > 1000) { arrXML[arrXML.length] = strXML; strXML = ""; } } arrXML[arrXML.length] = strXML; return arrXML.join(""); } function JSXMLBuilder_XMLElement(strName,Attributes,strText,iLevel,xmlBuilder) { this.type = "element"; this.name = strName; this.attributes = (typeof(Attributes) != "string") ? Attributes : null; this.attributeString = (typeof(Attributes) == "string") ? Attributes : ""; this.text = strText; this.level = iLevel; this.index = -1; this.xmlBuilder = xmlBuilder; this.parseAttributes = JSXMLBuilder_XMLElement_parseAttributes; this.attribute = JSXMLBuilder_XMLElement_attribute; this.setAttribute = JSXMLBuilder_XMLElement_setAttribute; this.removeAttribute = JSXMLBuilder_XMLElement_removeAttribute; this.parentElement = JSXMLBuilder_XMLElement_parentElement; this.childElement = JSXMLBuilder_XMLElement_childElement; } function JSXMLBuilder_XMLElement_parseAttributes() { if (!this.attributes) { var reAttributes = new RegExp(" ([^= ]*)=","g"); // matches attributes if (this.attributeString.match(reAttributes) && this.attributeString.match(reAttributes).length) { var arrAttributes = this.attributeString.match(reAttributes); if (!arrAttributes.length) arrAttributes = null; else for (var j=0; j0) { // move down for (; this.iElemLevel > 0; this.iElemLevel--) { if (this.xmleElem.parentElement && this.xmleElem.parentElement.childElements[this.arrElemIndex[this.iElemLevel]]) { this.xmleElem = this.xmleElem.parentElement.childElements[this.arrElemIndex[this.iElemLevel]]; this.iElemLevel++; this.arrElemIndex = this.arrElemIndex.slice(0,this.iElemLevel+1); break; } else { this.xmleElem = this.xmleElem.parentElement; } } this.iElemLevel--; } else { return false; } } } return (typeof(this.xmleElem) == "object" && this.iElemLevel > -1); } function ParseAttribute(str,Attribute) { var str = str + ">"; if (str.indexOf(Attribute + "='")>-1) var Attr = new RegExp(".*" + Attribute + "='([^']*)'.*>"); else if (str.indexOf(Attribute + '="')>-1) var Attr = new RegExp(".*" + Attribute + '="([^"]*)".*>'); return str.replace(Attr, "$1"); } function Array_Remove(c) { var tmparr = []; for (var i=0; i