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