1 /** 2 * ==================================================================== 3 * About 4 * ==================================================================== 5 * Sarissa cross browser XML library 6 * @version 0.9.6 7 * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net 8 * 9 * Sarissa is an ECMAScript library acting as a cross-browser wrapper for native XML APIs. 10 * The library supports Gecko based browsers like Mozilla and Firefox, 11 * Internet Explorer (5.5+ with MSXML3.0+) and, last but not least, KHTML based browsers like 12 * Konqueror and Safari. 13 * 14 * ==================================================================== 15 * Licence 16 * ==================================================================== 17 * This program is free software; you can redistribute it and/or modify 18 * it under the terms of the GNU General Public License version 2 or 19 * the GNU Lesser General Public License version 2.1 as published by 20 * the Free Software Foundation (your choice of the two). 21 * 22 * This program is distributed in the hope that it will be useful, 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 * GNU General Public License or GNU Lesser General Public License for more details. 26 * 27 * You should have received a copy of the GNU General Public License 28 * or GNU Lesser General Public License along with this program; if not, 29 * write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 30 * or visit http://www.gnu.org 31 * 32 */ 33 /** 34 * <p>Sarissa is a utility class. Provides static methods for DOMDocument and 35 * XMLHTTP objects, DOM Node serializatrion to XML strings and other goodies.</p> 36 * @constructor 37 */ 38 function Sarissa(){}; 39 /** @private */ 40 Sarissa.PARSED_OK = "Document contains no parsing errors"; 41 /** 42 * Tells you whether transformNode and transformNodeToObject are available. This functionality 43 * is contained in sarissa_ieemu_xslt.js and is deprecated. If you want to control XSLT transformations 44 * use the XSLTProcessor 45 * @deprecated 46 * @type boolean 47 */ 48 Sarissa.IS_ENABLED_TRANSFORM_NODE = false; 49 /** 50 * tells you whether XMLHttpRequest (or equivalent) is available 51 * @type boolean 52 */ 53 Sarissa.IS_ENABLED_XMLHTTP = false; 54 /** 55 * tells you whether selectNodes/selectSingleNode is available 56 * @type boolean 57 */ 58 Sarissa.IS_ENABLED_SELECT_NODES = false; 59 var _sarissa_iNsCounter = 0; 60 var _SARISSA_IEPREFIX4XSLPARAM = ""; 61 var _SARISSA_HAS_DOM_IMPLEMENTATION = document.implementation && true; 62 var _SARISSA_HAS_DOM_CREATE_DOCUMENT = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.createDocument; 63 var _SARISSA_HAS_DOM_FEATURE = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.hasFeature; 64 var _SARISSA_IS_MOZ = _SARISSA_HAS_DOM_CREATE_DOCUMENT && _SARISSA_HAS_DOM_FEATURE; 65 var _SARISSA_IS_SAFARI = navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1; 66 var _SARISSA_IS_IE = document.all && window.ActiveXObject && navigator.userAgent.toLowerCase().indexOf("msie") > -1 && navigator.userAgent.toLowerCase().indexOf("opera") == -1; 67 68 if(!window.Node || !window.Node.ELEMENT_NODE){ 69 var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12}; 70 }; 71 72 // IE initialization 73 if(_SARISSA_IS_IE){ 74 // for XSLT parameter names, prefix needed by IE 75 _SARISSA_IEPREFIX4XSLPARAM = "xsl:"; 76 // used to store the most recent ProgID available out of the above 77 var _SARISSA_DOM_PROGID = ""; 78 var _SARISSA_XMLHTTP_PROGID = ""; 79 /** 80 * Called when the Sarissa_xx.js file is parsed, to pick most recent 81 * ProgIDs for IE, then gets destroyed. 82 * @param idList an array of MSXML PROGIDs from which the most recent will be picked for a given object 83 * @param enabledList an array of arrays where each array has two items; the index of the PROGID for which a certain feature is enabled 84 */ 85 pickRecentProgID = function (idList, enabledList){ 86 // found progID flag 87 var bFound = false; 88 for(var i=0; i < idList.length && !bFound; i++){ 89 try{ 90 var oDoc = new ActiveXObject(idList[i]); 91 o2Store = idList[i]; 92 bFound = true; 93 for(var j=0;j<enabledList.length;j++) 94 if(i <= enabledList[j][1]) 95 Sarissa["IS_ENABLED_"+enabledList[j][0]] = true; 96 }catch (objException){ 97 // trap; try next progID 98 }; 99 }; 100 if (!bFound) 101 throw "Could not retreive a valid progID of Class: " + idList[idList.length-1]+". (original exception: "+e+")"; 102 idList = null; 103 return o2Store; 104 }; 105 // pick best available MSXML progIDs 106 _SARISSA_DOM_PROGID = pickRecentProgID(["Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"], [["SELECT_NODES", 2],["TRANSFORM_NODE", 2]]); 107 _SARISSA_XMLHTTP_PROGID = pickRecentProgID(["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"], [["XMLHTTP", 4]]); 108 _SARISSA_THREADEDDOM_PROGID = pickRecentProgID(["Msxml2.FreeThreadedDOMDocument.5.0", "MSXML2.FreeThreadedDOMDocument.4.0", "MSXML2.FreeThreadedDOMDocument.3.0"]); 109 _SARISSA_XSLTEMPLATE_PROGID = pickRecentProgID(["Msxml2.XSLTemplate.5.0", "Msxml2.XSLTemplate.4.0", "MSXML2.XSLTemplate.3.0"], [["XSLTPROC", 2]]); 110 // we dont need this anymore 111 pickRecentProgID = null; 112 //============================================ 113 // Factory methods (IE) 114 //============================================ 115 // see non-IE version 116 Sarissa.getDomDocument = function(sUri, sName){ 117 var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID); 118 // if a root tag name was provided, we need to load it in the DOM 119 // object 120 if (sName){ 121 // if needed, create an artifical namespace prefix the way Moz 122 // does 123 if (sUri){ 124 oDoc.loadXML("<a" + _sarissa_iNsCounter + ":" + sName + " xmlns:a" + _sarissa_iNsCounter + "=\"" + sUri + "\" />"); 125 // don't use the same prefix again 126 ++_sarissa_iNsCounter; 127 } 128 else 129 oDoc.loadXML("<" + sName + "/>"); 130 }; 131 return oDoc; 132 }; 133 // see non-IE version 134 Sarissa.getParseErrorText = function (oDoc) { 135 var parseErrorText = Sarissa.PARSED_OK; 136 if(oDoc.parseError != 0){ 137 parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason + 138 "\nLocation: " + oDoc.parseError.url + 139 "\nLine Number " + oDoc.parseError.line + ", Column " + 140 oDoc.parseError.linepos + 141 ":\n" + oDoc.parseError.srcText + 142 "\n"; 143 for(var i = 0; i < oDoc.parseError.linepos;i++){ 144 parseErrorText += "-"; 145 }; 146 parseErrorText += "^\n"; 147 }; 148 return parseErrorText; 149 }; 150 // see non-IE version 151 Sarissa.setXpathNamespaces = function(oDoc, sNsSet) { 152 oDoc.setProperty("SelectionLanguage", "XPath"); 153 oDoc.setProperty("SelectionNamespaces", sNsSet); 154 }; 155 /** 156 * Basic implementation of Mozilla's XSLTProcessor for IE. 157 * Reuses the same XSLT stylesheet for multiple transforms 158 * @constructor 159 */ 160 XSLTProcessor = function(){ 161 this.template = new ActiveXObject(_SARISSA_XSLTEMPLATE_PROGID); 162 this.processor = null; 163 }; 164 /** 165 * Impoprts the given XSLT DOM and compiles it to a reusable transform 166 * @argument xslDoc The XSLT DOMDocument to import 167 */ 168 XSLTProcessor.prototype.importStylesheet = function(xslDoc){ 169 // convert stylesheet to free threaded 170 var converted = new ActiveXObject(_SARISSA_THREADEDDOM_PROGID); 171 converted.loadXML(xslDoc.xml); 172 this.template.stylesheet = converted; 173 this.processor = this.template.createProcessor(); 174 // (re)set default param values 175 this.paramsSet = new Array(); 176 }; 177 /** 178 * Transform the given XML DOM 179 * @argument sourceDoc The XML DOMDocument to transform 180 * @return The transformation result as a DOM Document 181 */ 182 XSLTProcessor.prototype.transformToDocument = function(sourceDoc){ 183 this.processor.input = sourceDoc; 184 var outDoc = new ActiveXObject(_SARISSA_DOM_PROGID); 185 this.processor.output = outDoc; 186 this.processor.transform(); 187 return outDoc; 188 }; 189 /** 190 * Not sure if this works in IE. Maybe this will allow non-well-formed 191 * transformation results (i.e. with no single root element) 192 * @argument sourceDoc The XML DOMDocument to transform 193 * @return The transformation result as a DOM Fragment 194 */ 195 XSLTProcessor.prototype.transformToFragment = function(sourceDoc, ownerDocument){ 196 return this.transformToDocument(sourceDoc); 197 }; 198 /** 199 * Set global XSLT parameter of the imported stylesheet 200 * @argument nsURI The parameter namespace URI 201 * @argument name The parameter base name 202 * @argument value The new parameter value 203 */ 204 XSLTProcessor.prototype.setParameter = function(nsURI, name, value){ 205 /* nsURI is optional but cannot be null */ 206 if(nsURI){ 207 this.processor.addParameter(name, value, nsURI); 208 }else{ 209 this.processor.addParameter(name, value); 210 }; 211 /* update updated params for getParameter */ 212 if(!this.paramsSet[""+nsURI]){ 213 this.paramsSet[""+nsURI] = new Array(); 214 }; 215 this.paramsSet[""+nsURI][name] = value; 216 }; 217 /** 218 * Gets a parameter if previously set by setParameter. Returns null 219 * otherwise 220 * @argument name The parameter base name 221 * @argument value The new parameter value 222 * @return The parameter value if reviously set by setParameter, null otherwise 223 */ 224 XSLTProcessor.prototype.getParameter = function(nsURI, name){ 225 if(this.paramsSet[""+nsURI] && this.paramsSet[""+nsURI][name]) 226 return this.paramsSet[""+nsURI][name]; 227 else 228 return null; 229 }; 230 } 231 else{ /* end IE initialization, try to deal with real browsers now ;-) */ 232 if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){ 233 if(window.XMLDocument){ 234 /** 235 * <p>Emulate IE's onreadystatechange attribute</p> 236 */ 237 XMLDocument.prototype.onreadystatechange = null; 238 /** 239 * <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p> 240 * <ul><li>1 == LOADING,</li> 241 * <li>2 == LOADED,</li> 242 * <li>3 == INTERACTIVE,</li> 243 * <li>4 == COMPLETED</li></ul> 244 */ 245 XMLDocument.prototype.readyState = 0; 246 /** 247 * <p>Emulate IE's parseError attribute</p> 248 */ 249 XMLDocument.prototype.parseError = 0; 250 251 // NOTE: setting async to false will only work with documents 252 // called over HTTP (meaning a server), not the local file system, 253 // unless you are using Moz 1.4+. 254 // BTW the try>catch block is for 1.4; I haven't found a way to check if 255 // the property is implemented without 256 // causing an error and I dont want to use user agent stuff for that... 257 var _SARISSA_SYNC_NON_IMPLEMENTED = false; 258 try{ 259 /** 260 * <p>Emulates IE's async property for Moz versions prior to 1.4. 261 * It controls whether loading of remote XML files works 262 * synchronously or asynchronously.</p> 263 */ 264 XMLDocument.prototype.async = true; 265 _SARISSA_SYNC_NON_IMPLEMENTED = true; 266 }catch(e){/* trap */}; 267 /** 268 * <p>Keeps a handle to the original load() method. Internal use and only 269 * if Mozilla version is lower than 1.4</p> 270 * @private 271 */ 272 XMLDocument.prototype._sarissa_load = XMLDocument.prototype.load; 273 274 /** 275 * <p>Overrides the original load method to provide synchronous loading for 276 * Mozilla versions prior to 1.4, using an XMLHttpRequest object (if 277 * async is set to false)</p> 278 * @returns the DOM Object as it was before the load() call (may be empty) 279 */ 280 XMLDocument.prototype.load = function(sURI) { 281 var oDoc = document.implementation.createDocument("", "", null); 282 Sarissa.copyChildNodes(this, oDoc); 283 this.parseError = 0; 284 Sarissa.__setReadyState__(this, 1); 285 try { 286 if(this.async == false && _SARISSA_SYNC_NON_IMPLEMENTED) { 287 var tmp = new XMLHttpRequest(); 288 tmp.open("GET", sURI, false); 289 tmp.send(null); 290 Sarissa.__setReadyState__(this, 2); 291 Sarissa.copyChildNodes(tmp.responseXML, this); 292 Sarissa.__setReadyState__(this, 3); 293 } 294 else { 295 this._sarissa_load(sURI); 296 }; 297 } 298 catch (objException) { 299 this.parseError = -1; 300 } 301 finally { 302 if(this.async == false){ 303 Sarissa.__handleLoad__(this); 304 }; 305 }; 306 return oDoc; 307 }; 308 };//if(window.XMLDocument) 309 310 /** 311 * <p>Ensures the document was loaded correctly, otherwise sets the 312 * parseError to -1 to indicate something went wrong. Internal use</p> 313 * @private 314 */ 315 Sarissa.__handleLoad__ = function(oDoc){ 316 if (!oDoc.documentElement || oDoc.documentElement.tagName == "parsererror") 317 oDoc.parseError = -1; 318 Sarissa.__setReadyState__(oDoc, 4); 319 }; 320 321 /** 322 * <p>Attached by an event handler to the load event. Internal use.</p> 323 * @private 324 */ 325 _sarissa_XMLDocument_onload = function(){ 326 Sarissa.__handleLoad__(this); 327 }; 328 329 /** 330 * <p>Sets the readyState property of the given DOM Document object. 331 * Internal use.</p> 332 * @private 333 * @argument oDoc the DOM Document object to fire the 334 * readystatechange event 335 * @argument iReadyState the number to change the readystate property to 336 */ 337 Sarissa.__setReadyState__ = function(oDoc, iReadyState){ 338 oDoc.readyState = iReadyState; 339 if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function") 340 oDoc.onreadystatechange(); 341 }; 342 /** 343 * <p>Factory method to obtain a new DOM Document object</p> 344 * @argument sUri the namespace of the root node (if any) 345 * @argument sUri the local name of the root node (if any) 346 * @returns a new DOM Document 347 */ 348 Sarissa.getDomDocument = function(sUri, sName){ 349 var oDoc = document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null); 350 oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false); 351 return oDoc; 352 }; 353 };//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT) 354 }; 355 //========================================== 356 // Common stuff 357 //========================================== 358 if(!window.DOMParser){ 359 /** 360 * DOMParser is a utility class, used to construct DOMDocuments from XML strings 361 * @constructor 362 */ 363 DOMParser = function() { 364 }; 365 /** 366 * Construct a new DOM Document from the given XMLstring 367 * @param sXml the given XML string 368 * @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml). 369 * @return a new DOM Document from the given XML string 370 */ 371 DOMParser.prototype.parseFromString = function(sXml, contentType){ 372 var doc = Sarissa.getDomDocument(); 373 doc.loadXML(sXml); 374 return doc; 375 }; 376 377 }; 378 379 if(window.XMLHttpRequest){ 380 Sarissa.IS_ENABLED_XMLHTTP = true; 381 } 382 else if(_SARISSA_IS_IE){ 383 /** 384 * Emulate XMLHttpRequest 385 * @constructor 386 */ 387 XMLHttpRequest = function() { 388 return new ActiveXObject(_SARISSA_XMLHTTP_PROGID); 389 }; 390 Sarissa.IS_ENABLED_XMLHTTP = true; 391 }; 392 393 if(!window.document.importNode && _SARISSA_IS_IE){ 394 try{ 395 /** 396 * Implements importNode for the current window document in IE using innerHTML. 397 * Testing showed that DOM was multiple times slower than innerHTML for this, 398 * sorry folks. If you encounter trouble (who knows what IE does behind innerHTML) 399 * please gimme a call. 400 * @param oNode the Node to import 401 * @param bChildren whether to include the children of oNode 402 * @returns the imported node for further use 403 */ 404 window.document.importNode = function(oNode, bChildren){ 405 var importNode = document.createElement("div"); 406 if(bChildren) 407 importNode.innerHTML = Sarissa.serialize(oNode); 408 else 409 importNode.innerHTML = Sarissa.serialize(oNode.cloneNode(false)); 410 return importNode.firstChild; 411 }; 412 }catch(e){}; 413 }; 414 if(!Sarissa.getParseErrorText){ 415 /** 416 * <p>Returns a human readable description of the parsing error. Usefull 417 * for debugging. Tip: append the returned error string in a <pre> 418 * element if you want to render it.</p> 419 * <p>Many thanks to Christian Stocker for the initial patch.</p> 420 * @argument oDoc The target DOM document 421 * @returns The parsing error description of the target Document in 422 * human readable form (preformated text) 423 */ 424 Sarissa.getParseErrorText = function (oDoc){ 425 var parseErrorText = Sarissa.PARSED_OK; 426 if(oDoc.parseError != 0){ 427 /*moz*/ 428 if(oDoc.documentElement.tagName == "parsererror"){ 429 parseErrorText = oDoc.documentElement.firstChild.data; 430 parseErrorText += "\n" + oDoc.documentElement.firstChild.nextSibling.firstChild.data; 431 }/*konq*/ 432 else if(oDoc.documentElement.tagName == "html"){ 433 parseErrorText = Sarissa.getText(oDoc.documentElement.getElementsByTagName("h1")[0], false) + "\n"; 434 parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("body")[0], false) + "\n"; 435 parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("pre")[0], false); 436 }; 437 }; 438 return parseErrorText; 439 }; 440 }; 441 Sarissa.getText = function(oNode, deep){ 442 var s = ""; 443 var nodes = oNode.childNodes; 444 for(var i=0; i < nodes.length; i++){ 445 var node = nodes[i]; 446 var nodeType = node.nodeType; 447 if(nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE){ 448 s += node.data; 449 } 450 else if(deep == true 451 && (nodeType == Node.ELEMENT_NODE 452 || nodeType == Node.DOCUMENT_NODE 453 || nodeType == Node.DOCUMENT_FRAGMENT_NODE)){ 454 s += Sarissa.getText(node, true); 455 }; 456 }; 457 return s; 458 }; 459 if(window.XMLSerializer){ 460 /** 461 * <p>Factory method to obtain the serialization of a DOM Node</p> 462 * @returns the serialized Node as an XML string 463 */ 464 Sarissa.serialize = function(oDoc){ 465 return (new XMLSerializer()).serializeToString(oDoc); 466 }; 467 }else{ 468 if((Sarissa.getDomDocument("","foo", null)).xml){ 469 // see non-IE version 470 Sarissa.serialize = function(oDoc) { 471 // TODO: check for HTML document and return innerHTML instead 472 return oDoc.xml; 473 }; 474 /** 475 * Utility class to serialize DOM Node objects to XML strings 476 * @constructor 477 */ 478 XMLSerializer = function(){}; 479 /** 480 * Serialize the given DOM Node to an XML string 481 * @param oNode the DOM Node to serialize 482 */ 483 XMLSerializer.prototype.serializeToString = function(oNode) { 484 return oNode.xml; 485 }; 486 }; 487 }; 488 489 /** 490 * strips tags from a markup string 491 */ 492 Sarissa.stripTags = function (s) { 493 return s.replace(/<[^>]+>/g,""); 494 }; 495 /** 496 * <p>Deletes all child nodes of the given node</p> 497 * @argument oNode the Node to empty 498 */ 499 Sarissa.clearChildNodes = function(oNode) { 500 while(oNode.hasChildNodes()){ 501 oNode.removeChild(oNode.firstChild); 502 }; 503 }; 504 /** 505 * <p> Copies the childNodes of nodeFrom to nodeTo</p> 506 * <p> <b>Note:</b> The second object's original content is deleted before 507 * the copy operation, unless you supply a true third parameter</p> 508 * @argument nodeFrom the Node to copy the childNodes from 509 * @argument nodeTo the Node to copy the childNodes to 510 * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is false 511 */ 512 Sarissa.copyChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) { 513 if(!bPreserveExisting){ 514 Sarissa.clearChildNodes(nodeTo); 515 }; 516 var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument; 517 var nodes = nodeFrom.childNodes; 518 if(ownerDoc.importNode && (!_SARISSA_IS_IE)) { 519 for(var i=0;i < nodes.length;i++) { 520 nodeTo.appendChild(ownerDoc.importNode(nodes[i], true)); 521 }; 522 } 523 else{ 524 for(var i=0;i < nodes.length;i++) { 525 nodeTo.appendChild(nodes[i].cloneNode(true)); 526 }; 527 }; 528 }; 529 530 /** 531 * <p> Moves the childNodes of nodeFrom to nodeTo</p> 532 * <p> <b>Note:</b> The second object's original content is deleted before 533 * the move operation, unless you supply a true third parameter</p> 534 * @argument nodeFrom the Node to copy the childNodes from 535 * @argument nodeTo the Node to copy the childNodes to 536 * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is false 537 */ 538 Sarissa.moveChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) { 539 if(!bPreserveExisting){ 540 Sarissa.clearChildNodes(nodeTo); 541 }; 542 543 var nodes = nodeFrom.childNodes; 544 // if within the same doc, just move, else copy and delete 545 if(nodeFrom.ownerDocument == nodeTo.ownerDocument){ 546 nodeTo.appendChild(nodes[i]); 547 }else{ 548 var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument; 549 if(ownerDoc.importNode && (!_SARISSA_IS_IE)) { 550 for(var i=0;i < nodes.length;i++) { 551 nodeTo.appendChild(ownerDoc.importNode(nodes[i], true)); 552 }; 553 } 554 else{ 555 for(var i=0;i < nodes.length;i++) { 556 nodeTo.appendChild(nodes[i].cloneNode(true)); 557 }; 558 }; 559 Sarissa.clearChildNodes(nodeFrom); 560 }; 561 562 }; 563 564 /** 565 * <p>Serialize any object to an XML string. All properties are serialized using the property name 566 * as the XML element name. Array elements are rendered as <code>array-item</code> elements, 567 * using their index/key as the value of the <code>key</code> attribute.</p> 568 * @argument anyObject the object to serialize 569 * @argument objectName a name for that object 570 * @return the XML serializationj of the given object as a string 571 */ 572 Sarissa.xmlize = function(anyObject, objectName, indentSpace){ 573 indentSpace = indentSpace?indentSpace:''; 574 var s = indentSpace + '<' + objectName + '>'; 575 var isLeaf = false; 576 if(!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String 577 || anyObject instanceof Boolean || anyObject instanceof Date){ 578 s += Sarissa.escape(""+anyObject); 579 isLeaf = true; 580 }else{ 581 s += "\n"; 582 var itemKey = ''; 583 var isArrayItem = anyObject instanceof Array; 584 for(var name in anyObject){ 585 s += Sarissa.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + " "); 586 }; 587 s += indentSpace; 588 }; 589 return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n"); 590 }; 591 592 /** 593 * Escape the given string chacters that correspond to the five predefined XML entities 594 * @param sXml the string to escape 595 */ 596 Sarissa.escape = function(sXml){ 597 return sXml.replace(/&/g, "&") 598 .replace(/</g, "<") 599 .replace(/>/g, ">") 600 .replace(/"/g, """) 601 .replace(/'/g, "'"); 602 }; 603 604 /** 605 * Unescape the given string. This turns the occurences of the predefined XML 606 * entities to become the characters they represent correspond to the five predefined XML entities 607 * @param sXml the string to unescape 608 */ 609 Sarissa.unescape = function(sXml){ 610 return sXml.replace(/'/g,"'") 611 .replace(/"/g,"\"") 612 .replace(/>/g,">") 613 .replace(/</g,"<") 614 .replace(/&/g,"&"); 615 }; 616 // EOF