1 /** 2 * ==================================================================== 3 * About 4 * ==================================================================== 5 * Sarissa is an ECMAScript library acting as a cross-browser wrapper for native XML APIs. 6 * The library supports Gecko based browsers like Mozilla and Firefox, 7 * Internet Explorer (5.5+ with MSXML3.0+), Konqueror, Safari and a little of Opera 8 * @version ${project.version} 9 * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net 10 * ==================================================================== 11 * Licence 12 * ==================================================================== 13 * Sarissa is free software distributed under the GNU GPL version 2 (see <a href="gpl.txt">gpl.txt</a>) or higher, 14 * GNU LGPL version 2.1 (see <a href="lgpl.txt">lgpl.txt</a>) or higher and Apache Software License 2.0 or higher 15 * (see <a href="asl.txt">asl.txt</a>). This means you can choose one of the three and use that if you like. If 16 * you make modifications under the ASL, i would appreciate it if you submitted those. 17 * In case your copy of Sarissa does not include the license texts, you may find 18 * them online in various formats at <a href="http://www.gnu.org">http://www.gnu.org</a> and 19 * <a href="http://www.apache.org">http://www.apache.org</a>. 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 21 * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 22 * WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE 23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 24 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 26 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 */ 29 /** 30 * <p>Sarissa is a utility class. Provides "static" methods for DOMDocument, 31 * DOM Node serialization to XML strings and other utility goodies.</p> 32 * @constructor 33 */ 34 function Sarissa(){}; 35 Sarissa.VERSION = "${project.version}"; 36 Sarissa.PARSED_OK = "Document contains no parsing errors"; 37 Sarissa.PARSED_EMPTY = "Document is empty"; 38 Sarissa.PARSED_UNKNOWN_ERROR = "Not well-formed or other error"; 39 Sarissa.IS_ENABLED_TRANSFORM_NODE = false; 40 var _sarissa_iNsCounter = 0; 41 var _SARISSA_IEPREFIX4XSLPARAM = ""; 42 var _SARISSA_HAS_DOM_IMPLEMENTATION = document.implementation && true; 43 var _SARISSA_HAS_DOM_CREATE_DOCUMENT = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.createDocument; 44 var _SARISSA_HAS_DOM_FEATURE = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.hasFeature; 45 var _SARISSA_IS_MOZ = _SARISSA_HAS_DOM_CREATE_DOCUMENT && _SARISSA_HAS_DOM_FEATURE; 46 var _SARISSA_IS_SAFARI = (navigator.userAgent && navigator.vendor && (navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1 || navigator.vendor.indexOf("Apple") != -1)); 47 var _SARISSA_IS_IE = document.all && window.ActiveXObject && navigator.userAgent.toLowerCase().indexOf("msie") > -1 && navigator.userAgent.toLowerCase().indexOf("opera") == -1; 48 if(!window.Node || !Node.ELEMENT_NODE){ 49 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}; 50 }; 51 52 if(typeof XMLDocument == "undefined" && typeof Document !="undefined"){ XMLDocument = Document; } 53 54 // IE initialization 55 if(_SARISSA_IS_IE){ 56 // for XSLT parameter names, prefix needed by IE 57 _SARISSA_IEPREFIX4XSLPARAM = "xsl:"; 58 // used to store the most recent ProgID available out of the above 59 var _SARISSA_DOM_PROGID = ""; 60 var _SARISSA_XMLHTTP_PROGID = ""; 61 var _SARISSA_DOM_XMLWRITER = ""; 62 /** 63 * Called when the Sarissa_xx.js file is parsed, to pick most recent 64 * ProgIDs for IE, then gets destroyed. 65 * @private 66 * @param idList an array of MSXML PROGIDs from which the most recent will be picked for a given object 67 * @param enabledList an array of arrays where each array has two items; the index of the PROGID for which a certain feature is enabled 68 */ 69 Sarissa.pickRecentProgID = function (idList){ 70 // found progID flag 71 var bFound = false; 72 for(var i=0; i < idList.length && !bFound; i++){ 73 try{ 74 var oDoc = new ActiveXObject(idList[i]); 75 o2Store = idList[i]; 76 bFound = true; 77 }catch (objException){ 78 // trap; try next progID 79 }; 80 }; 81 if (!bFound) { 82 throw "Could not retreive a valid progID of Class: " + idList[idList.length-1]+". (original exception: "+e+")"; 83 }; 84 idList = null; 85 return o2Store; 86 }; 87 // pick best available MSXML progIDs 88 _SARISSA_DOM_PROGID = null; 89 _SARISSA_THREADEDDOM_PROGID = null; 90 _SARISSA_XSLTEMPLATE_PROGID = null; 91 _SARISSA_XMLHTTP_PROGID = null; 92 if(!window.XMLHttpRequest){ 93 /** 94 * Emulate XMLHttpRequest 95 * @constructor 96 */ 97 XMLHttpRequest = function() { 98 if(!_SARISSA_XMLHTTP_PROGID){ 99 _SARISSA_XMLHTTP_PROGID = Sarissa.pickRecentProgID(["Msxml2.XMLHTTP.6.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]); 100 }; 101 return new ActiveXObject(_SARISSA_XMLHTTP_PROGID); 102 }; 103 }; 104 // we dont need this anymore 105 //============================================ 106 // Factory methods (IE) 107 //============================================ 108 // see non-IE version 109 Sarissa.getDomDocument = function(sUri, sName){ 110 if(!_SARISSA_DOM_PROGID){ 111 _SARISSA_DOM_PROGID = Sarissa.pickRecentProgID(["Msxml2.DOMDocument.6.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"]); 112 }; 113 var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID); 114 // if a root tag name was provided, we need to load it in the DOM object 115 if (sName){ 116 // create an artifical namespace prefix 117 // or reuse existing prefix if applicable 118 var prefix = ""; 119 if(sUri){ 120 if(sName.indexOf(":") > 1){ 121 prefix = sName.substring(0, sName.indexOf(":")); 122 sName = sName.substring(sName.indexOf(":")+1); 123 }else{ 124 prefix = "a" + (_sarissa_iNsCounter++); 125 }; 126 }; 127 // use namespaces if a namespace URI exists 128 if(sUri){ 129 oDoc.loadXML('<' + prefix+':'+sName + " xmlns:" + prefix + "=\"" + sUri + "\"" + " />"); 130 } else { 131 oDoc.loadXML('<' + sName + " />"); 132 }; 133 }; 134 return oDoc; 135 }; 136 // see non-IE version 137 Sarissa.getParseErrorText = function (oDoc) { 138 var parseErrorText = Sarissa.PARSED_OK; 139 if(oDoc && oDoc.parseError && oDoc.parseError.errorCode && oDoc.parseError.errorCode != 0){ 140 parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason + 141 "\nLocation: " + oDoc.parseError.url + 142 "\nLine Number " + oDoc.parseError.line + ", Column " + 143 oDoc.parseError.linepos + 144 ":\n" + oDoc.parseError.srcText + 145 "\n"; 146 for(var i = 0; i < oDoc.parseError.linepos;i++){ 147 parseErrorText += "-"; 148 }; 149 parseErrorText += "^\n"; 150 } 151 else if(oDoc.documentElement == null){ 152 parseErrorText = Sarissa.PARSED_EMPTY; 153 }; 154 return parseErrorText; 155 }; 156 // see non-IE version 157 Sarissa.setXpathNamespaces = function(oDoc, sNsSet) { 158 oDoc.setProperty("SelectionLanguage", "XPath"); 159 oDoc.setProperty("SelectionNamespaces", sNsSet); 160 }; 161 /** 162 * Basic implementation of Mozilla's XSLTProcessor for IE. 163 * Reuses the same XSLT stylesheet for multiple transforms 164 * @constructor 165 */ 166 XSLTProcessor = function(){ 167 if(!_SARISSA_XSLTEMPLATE_PROGID){ 168 _SARISSA_XSLTEMPLATE_PROGID = Sarissa.pickRecentProgID(["Msxml2.XSLTemplate.6.0", "MSXML2.XSLTemplate.3.0"]); 169 }; 170 this.template = new ActiveXObject(_SARISSA_XSLTEMPLATE_PROGID); 171 this.processor = null; 172 }; 173 /** 174 * Imports the given XSLT DOM and compiles it to a reusable transform 175 * <b>Note:</b> If the stylesheet was loaded from a URL and contains xsl:import or xsl:include elements,it will be reloaded to resolve those 176 * @argument xslDoc The XSLT DOMDocument to import 177 */ 178 XSLTProcessor.prototype.importStylesheet = function(xslDoc){ 179 if(!_SARISSA_THREADEDDOM_PROGID){ 180 _SARISSA_THREADEDDOM_PROGID = Sarissa.pickRecentProgID(["MSXML2.FreeThreadedDOMDocument.6.0", "MSXML2.FreeThreadedDOMDocument.3.0"]); 181 }; 182 xslDoc.setProperty("SelectionLanguage", "XPath"); 183 xslDoc.setProperty("SelectionNamespaces", "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'"); 184 // convert stylesheet to free threaded 185 var converted = new ActiveXObject(_SARISSA_THREADEDDOM_PROGID); 186 // make included/imported stylesheets work if exist and xsl was originally loaded from url 187 if(xslDoc.url && xslDoc.selectSingleNode("//xsl:*[local-name() = 'import' or local-name() = 'include']") != null){ 188 converted.async = false; 189 if (_SARISSA_THREADEDDOM_PROGID == "MSXML2.FreeThreadedDOMDocument.6.0") { 190 converted.setProperty("AllowDocumentFunction", true); 191 converted.resolveExternals = true; 192 } 193 converted.load(xslDoc.url); 194 } else { 195 converted.loadXML(xslDoc.xml); 196 }; 197 converted.setProperty("SelectionNamespaces", "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'"); 198 var output = converted.selectSingleNode("//xsl:output"); 199 this.outputMethod = output ? output.getAttribute("method") : "html"; 200 this.template.stylesheet = converted; 201 this.processor = this.template.createProcessor(); 202 // for getParameter and clearParameters 203 this.paramsSet = new Array(); 204 }; 205 206 /** 207 * Transform the given XML DOM and return the transformation result as a new DOM document 208 * @argument sourceDoc The XML DOMDocument to transform 209 * @return The transformation result as a DOM Document 210 */ 211 XSLTProcessor.prototype.transformToDocument = function(sourceDoc){ 212 // fix for bug 1549749 213 if(_SARISSA_THREADEDDOM_PROGID){ 214 this.processor.input=sourceDoc; 215 var outDoc=new ActiveXObject(_SARISSA_DOM_PROGID); 216 this.processor.output=outDoc; 217 this.processor.transform(); 218 return outDoc; 219 } 220 else{ 221 if(!_SARISSA_DOM_XMLWRITER){ 222 _SARISSA_DOM_XMLWRITER = Sarissa.pickRecentProgID(["Msxml2.MXXMLWriter.6.0", "Msxml2.MXXMLWriter.3.0", "MSXML2.MXXMLWriter", "MSXML.MXXMLWriter", "Microsoft.XMLDOM"]); 223 }; 224 this.processor.input = sourceDoc; 225 var outDoc = new ActiveXObject(_SARISSA_DOM_XMLWRITER); 226 this.processor.output = outDoc; 227 this.processor.transform(); 228 var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID); 229 oDoc.loadXML(outDoc.output+""); 230 return oDoc; 231 }; 232 }; 233 234 /** 235 * Transform the given XML DOM and return the transformation result as a new DOM fragment. 236 * <b>Note</b>: The xsl:output method must match the nature of the owner document (XML/HTML). 237 * @argument sourceDoc The XML DOMDocument to transform 238 * @argument ownerDoc The owner of the result fragment 239 * @return The transformation result as a DOM Document 240 */ 241 XSLTProcessor.prototype.transformToFragment = function (sourceDoc, ownerDoc) { 242 this.processor.input = sourceDoc; 243 this.processor.transform(); 244 var s = this.processor.output; 245 var f = ownerDoc.createDocumentFragment(); 246 if (this.outputMethod == 'text') { 247 f.appendChild(ownerDoc.createTextNode(s)); 248 } else if (ownerDoc.body && ownerDoc.body.innerHTML) { 249 var container = ownerDoc.createElement('div'); 250 container.innerHTML = s; 251 while (container.hasChildNodes()) { 252 f.appendChild(container.firstChild); 253 } 254 } 255 else { 256 var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID); 257 if (s.substring(0, 5) == '<?xml') { 258 s = s.substring(s.indexOf('?>') + 2); 259 } 260 var xml = ''.concat('<my>', s, '</my>'); 261 oDoc.loadXML(xml); 262 var container = oDoc.documentElement; 263 while (container.hasChildNodes()) { 264 f.appendChild(container.firstChild); 265 } 266 } 267 return f; 268 }; 269 270 /** 271 * Set global XSLT parameter of the imported stylesheet 272 * @argument nsURI The parameter namespace URI 273 * @argument name The parameter base name 274 * @argument value The new parameter value 275 */ 276 XSLTProcessor.prototype.setParameter = function(nsURI, name, value){ 277 // make value a zero length string if null to allow clearing 278 value = value ? value : ""; 279 // nsURI is optional but cannot be null 280 if(nsURI){ 281 this.processor.addParameter(name, value, nsURI); 282 }else{ 283 this.processor.addParameter(name, value); 284 }; 285 // update updated params for getParameter 286 if(!this.paramsSet[""+nsURI]){ 287 this.paramsSet[""+nsURI] = new Array(); 288 }; 289 this.paramsSet[""+nsURI][name] = value; 290 }; 291 /** 292 * Gets a parameter if previously set by setParameter. Returns null 293 * otherwise 294 * @argument name The parameter base name 295 * @argument value The new parameter value 296 * @return The parameter value if reviously set by setParameter, null otherwise 297 */ 298 XSLTProcessor.prototype.getParameter = function(nsURI, name){ 299 nsURI = "" + nsURI; 300 if(this.paramsSet[nsURI] && this.paramsSet[nsURI][name]){ 301 return this.paramsSet[nsURI][name]; 302 }else{ 303 return null; 304 }; 305 }; 306 /** 307 * Clear parameters (set them to default values as defined in the stylesheet itself) 308 */ 309 XSLTProcessor.prototype.clearParameters = function(){ 310 for(var nsURI in this.paramsSet){ 311 for(var name in this.paramsSet[nsURI]){ 312 if(nsURI){ 313 this.processor.addParameter(name, "", nsURI); 314 }else{ 315 this.processor.addParameter(name, ""); 316 }; 317 }; 318 }; 319 this.paramsSet = new Array(); 320 }; 321 }else{ /* end IE initialization, try to deal with real browsers now ;-) */ 322 if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){ 323 /** 324 * <p>Ensures the document was loaded correctly, otherwise sets the 325 * parseError to -1 to indicate something went wrong. Internal use</p> 326 * @private 327 */ 328 Sarissa.__handleLoad__ = function(oDoc){ 329 Sarissa.__setReadyState__(oDoc, 4); 330 }; 331 /** 332 * <p>Attached by an event handler to the load event. Internal use.</p> 333 * @private 334 */ 335 _sarissa_XMLDocument_onload = function(){ 336 Sarissa.__handleLoad__(this); 337 }; 338 /** 339 * <p>Sets the readyState property of the given DOM Document object. 340 * Internal use.</p> 341 * @private 342 * @argument oDoc the DOM Document object to fire the 343 * readystatechange event 344 * @argument iReadyState the number to change the readystate property to 345 */ 346 Sarissa.__setReadyState__ = function(oDoc, iReadyState){ 347 oDoc.readyState = iReadyState; 348 oDoc.readystate = iReadyState; 349 if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function") 350 oDoc.onreadystatechange(); 351 }; 352 Sarissa.getDomDocument = function(sUri, sName){ 353 var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null); 354 if(!oDoc.onreadystatechange){ 355 356 /** 357 * <p>Emulate IE's onreadystatechange attribute</p> 358 */ 359 oDoc.onreadystatechange = null; 360 }; 361 if(!oDoc.readyState){ 362 /** 363 * <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p> 364 * <ul><li>1 == LOADING,</li> 365 * <li>2 == LOADED,</li> 366 * <li>3 == INTERACTIVE,</li> 367 * <li>4 == COMPLETED</li></ul> 368 */ 369 oDoc.readyState = 0; 370 }; 371 oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false); 372 return oDoc; 373 }; 374 if(window.XMLDocument){ 375 // do nothing 376 }// TODO: check if the new document has content before trying to copynodes, check for error handling in DOM 3 LS 377 else if(_SARISSA_HAS_DOM_FEATURE && window.Document && !Document.prototype.load && document.implementation.hasFeature('LS', '3.0')){ 378 //Opera 9 may get the XPath branch which gives creates XMLDocument, therefore it doesn't reach here which is good 379 /** 380 * <p>Factory method to obtain a new DOM Document object</p> 381 * @argument sUri the namespace of the root node (if any) 382 * @argument sUri the local name of the root node (if any) 383 * @returns a new DOM Document 384 */ 385 Sarissa.getDomDocument = function(sUri, sName){ 386 var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null); 387 return oDoc; 388 }; 389 } 390 else { 391 Sarissa.getDomDocument = function(sUri, sName){ 392 var oDoc = document.implementation.createDocument(sUri?sUri:null, sName?sName:null, null); 393 // looks like safari does not create the root element for some unknown reason 394 if(oDoc && (sUri || sName) && !oDoc.documentElement){ 395 oDoc.appendChild(oDoc.createElementNS(sUri, sName)); 396 }; 397 return oDoc; 398 }; 399 }; 400 };//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT) 401 }; 402 //========================================== 403 // Common stuff 404 //========================================== 405 if(!window.DOMParser){ 406 if(_SARISSA_IS_SAFARI){ 407 /* 408 * DOMParser is a utility class, used to construct DOMDocuments from XML strings 409 * @constructor 410 */ 411 DOMParser = function() { }; 412 /** 413 * Construct a new DOM Document from the given XMLstring 414 * @param sXml the given XML string 415 * @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml). 416 * @return a new DOM Document from the given XML string 417 */ 418 DOMParser.prototype.parseFromString = function(sXml, contentType){ 419 var xmlhttp = new XMLHttpRequest(); 420 xmlhttp.open("GET", "data:text/xml;charset=utf-8," + encodeURIComponent(sXml), false); 421 xmlhttp.send(null); 422 return xmlhttp.responseXML; 423 }; 424 }else if(Sarissa.getDomDocument && Sarissa.getDomDocument()){ 425 DOMParser = function() { }; 426 DOMParser.prototype.parseFromString = function(sXml, contentType){ 427 var doc = Sarissa.getDomDocument(); 428 doc.loadXML(sXml); 429 return doc; 430 }; 431 }; 432 }; 433 434 if((typeof(document.importNode) == "undefined") && _SARISSA_IS_IE){ 435 try{ 436 /** 437 * Implementation of importNode for the context window document in IE. 438 * If <code>oNode</code> is a TextNode, <code>bChildren</code> is ignored. 439 * @param oNode the Node to import 440 * @param bChildren whether to include the children of oNode 441 * @returns the imported node for further use 442 */ 443 document.importNode = function(oNode, bChildren){ 444 var tmp; 445 if (oNode.nodeName=='#text') { 446 return document.createTextElement(oNode.data); 447 } 448 else { 449 if(oNode.nodeName == "tbody" || oNode.nodeName == "tr"){ 450 tmp = document.createElement("table"); 451 } 452 else if(oNode.nodeName == "td"){ 453 tmp = document.createElement("tr"); 454 } 455 else if(oNode.nodeName == "option"){ 456 tmp = document.createElement("select"); 457 } 458 else{ 459 tmp = document.createElement("div"); 460 }; 461 if(bChildren){ 462 tmp.innerHTML = oNode.xml ? oNode.xml : oNode.outerHTML; 463 }else{ 464 tmp.innerHTML = oNode.xml ? oNode.cloneNode(false).xml : oNode.cloneNode(false).outerHTML; 465 }; 466 return tmp.getElementsByTagName("*")[0]; 467 }; 468 469 }; 470 }catch(e){ }; 471 }; 472 if(!Sarissa.getParseErrorText){ 473 /** 474 * <p>Returns a human readable description of the parsing error. Usefull 475 * for debugging. Tip: append the returned error string in a <pre> 476 * element if you want to render it.</p> 477 * <p>Many thanks to Christian Stocker for the initial patch.</p> 478 * @argument oDoc The target DOM document 479 * @returns The parsing error description of the target Document in 480 * human readable form (preformated text) 481 */ 482 Sarissa.getParseErrorText = function (oDoc){ 483 var parseErrorText = Sarissa.PARSED_OK; 484 if(!oDoc.documentElement){ 485 parseErrorText = Sarissa.PARSED_EMPTY; 486 } else if(oDoc.documentElement.tagName == "parsererror"){ 487 parseErrorText = oDoc.documentElement.firstChild.data; 488 parseErrorText += "\n" + oDoc.documentElement.firstChild.nextSibling.firstChild.data; 489 } else if(oDoc.getElementsByTagName("parsererror").length > 0){ 490 var parsererror = oDoc.getElementsByTagName("parsererror")[0]; 491 parseErrorText = Sarissa.getText(parsererror, true)+"\n"; 492 } else if(oDoc.parseError && oDoc.parseError.errorCode != 0){ 493 parseErrorText = Sarissa.PARSED_UNKNOWN_ERROR; 494 }; 495 return parseErrorText; 496 }; 497 }; 498 Sarissa.getText = function(oNode, deep){ 499 var s = ""; 500 var nodes = oNode.childNodes; 501 for(var i=0; i < nodes.length; i++){ 502 var node = nodes[i]; 503 var nodeType = node.nodeType; 504 if(nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE){ 505 s += node.data; 506 } else if(deep == true 507 && (nodeType == Node.ELEMENT_NODE 508 || nodeType == Node.DOCUMENT_NODE 509 || nodeType == Node.DOCUMENT_FRAGMENT_NODE)){ 510 s += Sarissa.getText(node, true); 511 }; 512 }; 513 return s; 514 }; 515 if(!window.XMLSerializer 516 && Sarissa.getDomDocument 517 && Sarissa.getDomDocument("","foo", null).xml){ 518 /** 519 * Utility class to serialize DOM Node objects to XML strings 520 * @constructor 521 */ 522 XMLSerializer = function(){}; 523 /** 524 * Serialize the given DOM Node to an XML string 525 * @param oNode the DOM Node to serialize 526 */ 527 XMLSerializer.prototype.serializeToString = function(oNode) { 528 return oNode.xml; 529 }; 530 }; 531 532 /** 533 * strips tags from a markup string 534 */ 535 Sarissa.stripTags = function (s) { 536 return s.replace(/<[^>]+>/g,""); 537 }; 538 /** 539 * <p>Deletes all child nodes of the given node</p> 540 * @argument oNode the Node to empty 541 */ 542 Sarissa.clearChildNodes = function(oNode) { 543 // need to check for firstChild due to opera 8 bug with hasChildNodes 544 while(oNode.firstChild) { 545 oNode.removeChild(oNode.firstChild); 546 }; 547 }; 548 /** 549 * <p> Copies the childNodes of nodeFrom to nodeTo</p> 550 * <p> <b>Note:</b> The second object's original content is deleted before 551 * the copy operation, unless you supply a true third parameter</p> 552 * @argument nodeFrom the Node to copy the childNodes from 553 * @argument nodeTo the Node to copy the childNodes to 554 * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is false 555 */ 556 Sarissa.copyChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) { 557 if((!nodeFrom) || (!nodeTo)){ 558 throw "Both source and destination nodes must be provided"; 559 }; 560 if(!bPreserveExisting){ 561 Sarissa.clearChildNodes(nodeTo); 562 }; 563 var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument; 564 var nodes = nodeFrom.childNodes; 565 if(typeof(ownerDoc.importNode) != "undefined") { 566 for(var i=0;i < nodes.length;i++) { 567 nodeTo.appendChild(ownerDoc.importNode(nodes[i], true)); 568 }; 569 } else { 570 for(var i=0;i < nodes.length;i++) { 571 nodeTo.appendChild(nodes[i].cloneNode(true)); 572 }; 573 }; 574 }; 575 576 /** 577 * <p> Moves the childNodes of nodeFrom to nodeTo</p> 578 * <p> <b>Note:</b> The second object's original content is deleted before 579 * the move operation, unless you supply a true third parameter</p> 580 * @argument nodeFrom the Node to copy the childNodes from 581 * @argument nodeTo the Node to copy the childNodes to 582 * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is 583 */ 584 Sarissa.moveChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) { 585 if((!nodeFrom) || (!nodeTo)){ 586 throw "Both source and destination nodes must be provided"; 587 }; 588 if(!bPreserveExisting){ 589 Sarissa.clearChildNodes(nodeTo); 590 }; 591 var nodes = nodeFrom.childNodes; 592 // if within the same doc, just move, else copy and delete 593 if(nodeFrom.ownerDocument == nodeTo.ownerDocument){ 594 while(nodeFrom.firstChild){ 595 nodeTo.appendChild(nodeFrom.firstChild); 596 }; 597 } else { 598 var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument; 599 if(typeof(ownerDoc.importNode) != "undefined") { 600 for(var i=0;i < nodes.length;i++) { 601 nodeTo.appendChild(ownerDoc.importNode(nodes[i], true)); 602 }; 603 }else{ 604 for(var i=0;i < nodes.length;i++) { 605 nodeTo.appendChild(nodes[i].cloneNode(true)); 606 }; 607 }; 608 Sarissa.clearChildNodes(nodeFrom); 609 }; 610 }; 611 612 /** 613 * <p>Serialize any object to an XML string. All properties are serialized using the property name 614 * as the XML element name. Array elements are rendered as <code>array-item</code> elements, 615 * using their index/key as the value of the <code>key</code> attribute.</p> 616 * @argument anyObject the object to serialize 617 * @argument objectName a name for that object 618 * @return the XML serializationj of the given object as a string 619 */ 620 Sarissa.xmlize = function(anyObject, objectName, indentSpace){ 621 indentSpace = indentSpace?indentSpace:''; 622 var s = indentSpace + '<' + objectName + '>'; 623 var isLeaf = false; 624 if(!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String 625 || anyObject instanceof Boolean || anyObject instanceof Date){ 626 s += Sarissa.escape(""+anyObject); 627 isLeaf = true; 628 }else{ 629 s += "\n"; 630 var itemKey = ''; 631 var isArrayItem = anyObject instanceof Array; 632 for(var name in anyObject){ 633 s += Sarissa.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + " "); 634 }; 635 s += indentSpace; 636 }; 637 return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n"); 638 }; 639 640 /** 641 * Escape the given string chacters that correspond to the five predefined XML entities 642 * @param sXml the string to escape 643 */ 644 Sarissa.escape = function(sXml){ 645 return sXml.replace(/&/g, "&") 646 .replace(/</g, "<") 647 .replace(/>/g, ">") 648 .replace(/"/g, """) 649 .replace(/'/g, "'"); 650 }; 651 652 /** 653 * Unescape the given string. This turns the occurences of the predefined XML 654 * entities to become the characters they represent correspond to the five predefined XML entities 655 * @param sXml the string to unescape 656 */ 657 Sarissa.unescape = function(sXml){ 658 return sXml.replace(/'/g,"'") 659 .replace(/"/g,"\"") 660 .replace(/>/g,">") 661 .replace(/</g,"<") 662 .replace(/&/g,"&"); 663 }; 664 // EOF