[ Index ] |
|
Code source de PRADO 3.0.6 |
1 // Copyright 2005 Google Inc. 2 // All Rights Reserved 3 // 4 // An XML parse and a minimal DOM implementation that just supportes 5 // the subset of the W3C DOM that is used in the XSLT implementation. 6 // 7 // References: 8 // 9 // [DOM] W3C DOM Level 3 Core Specification 10 // <http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/>. 11 // 12 // 13 // Author: Steffen Meschkat <mesch@google.com> 14 15 // NOTE: The split() method in IE omits empty result strings. This is 16 // utterly annoying. So we don't use it here. 17 18 // Resolve entities in XML text fragments. According to the DOM 19 // specification, the DOM is supposed to resolve entity references at 20 // the API level. I.e. no entity references are passed through the 21 // API. See "Entities and the DOM core", p.12, DOM 2 Core 22 // Spec. However, different browsers actually pass very different 23 // values at the API. 24 // 25 function xmlResolveEntities(s) { 26 27 var parts = stringSplit(s, '&'); 28 29 var ret = parts[0]; 30 for (var i = 1; i < parts.length; ++i) { 31 var rp = stringSplit(parts[i], ';'); 32 if (rp.length == 1) { 33 // no entity reference: just a & but no ; 34 ret += parts[i]; 35 continue; 36 } 37 38 var ch; 39 switch (rp[0]) { 40 case 'lt': 41 ch = '<'; 42 break; 43 case 'gt': 44 ch = '>'; 45 break; 46 case 'amp': 47 ch = '&'; 48 break; 49 case 'quot': 50 ch = '"'; 51 break; 52 case 'apos': 53 ch = '\''; 54 break; 55 case 'nbsp': 56 ch = String.fromCharCode(160); 57 break; 58 default: 59 // Cool trick: let the DOM do the entity decoding. We assign 60 // the entity text through non-W3C DOM properties and read it 61 // through the W3C DOM. W3C DOM access is specified to resolve 62 // entities. 63 var span = window.document.createElement('span'); 64 span.innerHTML = '&' + rp[0] + '; '; 65 ch = span.childNodes[0].nodeValue.charAt(0); 66 } 67 ret += ch + rp[1]; 68 } 69 70 return ret; 71 } 72 73 74 // Parses the given XML string with our custom, JavaScript XML parser. Written 75 // by Steffen Meschkat (mesch@google.com). 76 function xmlParse(xml) { 77 Timer.start('xmlparse'); 78 var regex_empty = /\/$/; 79 80 // See also <http://www.w3.org/TR/REC-xml/#sec-common-syn> for 81 // allowed chars in a tag and attribute name. TODO(mesch): the 82 // following is still not completely correct. 83 84 var regex_tagname = /^([\w:-]*)/; 85 var regex_attribute = /([\w:-]+)\s?=\s?('([^\']*)'|"([^\"]*)")/g; 86 87 var xmldoc = new XDocument(); 88 var root = xmldoc; 89 90 // For the record: in Safari, we would create native DOM nodes, but 91 // in Opera that is not possible, because the DOM only allows HTML 92 // element nodes to be created, so we have to do our own DOM nodes. 93 94 // xmldoc = document.implementation.createDocument('','',null); 95 // root = xmldoc; // .createDocumentFragment(); 96 // NOTE(mesch): using the DocumentFragment instead of the Document 97 // crashes my Safari 1.2.4 (v125.12). 98 var stack = []; 99 100 var parent = root; 101 stack.push(parent); 102 103 var x = stringSplit(xml, '<'); 104 for (var i = 1; i < x.length; ++i) { 105 var xx = stringSplit(x[i], '>'); 106 var tag = xx[0]; 107 var text = xmlResolveEntities(xx[1] || ''); 108 109 if (tag.charAt(0) == '/') { 110 stack.pop(); 111 parent = stack[stack.length-1]; 112 113 } else if (tag.charAt(0) == '?') { 114 // Ignore XML declaration and processing instructions 115 } else if (tag.charAt(0) == '!') { 116 // Ignore notation and comments 117 } else { 118 var empty = tag.match(regex_empty); 119 var tagname = regex_tagname.exec(tag)[1]; 120 var node = xmldoc.createElement(tagname); 121 122 var att; 123 while (att = regex_attribute.exec(tag)) { 124 var val = xmlResolveEntities(att[3] || att[4] || ''); 125 node.setAttribute(att[1], val); 126 } 127 128 if (empty) { 129 parent.appendChild(node); 130 } else { 131 parent.appendChild(node); 132 parent = node; 133 stack.push(node); 134 } 135 } 136 137 if (text && parent != root) { 138 parent.appendChild(xmldoc.createTextNode(text)); 139 } 140 } 141 142 Timer.end('xmlparse'); 143 return root; 144 } 145 146 147 // Our W3C DOM Node implementation. Note we call it XNode because we 148 // can't define the identifier Node. We do this mostly for Opera, 149 // where we can't reuse the HTML DOM for parsing our own XML, and for 150 // Safari, where it is too expensive to have the template processor 151 // operate on native DOM nodes. 152 function XNode(type, name, value, owner) { 153 this.attributes = []; 154 this.childNodes = []; 155 156 XNode.init.call(this, type, name, value, owner); 157 } 158 159 // Don't call as method, use apply() or call(). 160 XNode.init = function(type, name, value, owner) { 161 this.nodeType = type - 0; 162 this.nodeName = '' + name; 163 this.nodeValue = '' + value; 164 this.ownerDocument = owner; 165 166 this.firstChild = null; 167 this.lastChild = null; 168 this.nextSibling = null; 169 this.previousSibling = null; 170 this.parentNode = null; 171 } 172 173 XNode.unused_ = []; 174 175 XNode.recycle = function(node) { 176 if (!node) { 177 return; 178 } 179 180 if (node.constructor == XDocument) { 181 XNode.recycle(node.documentElement); 182 return; 183 } 184 185 if (node.constructor != this) { 186 return; 187 } 188 189 XNode.unused_.push(node); 190 for (var a = 0; a < node.attributes.length; ++a) { 191 XNode.recycle(node.attributes[a]); 192 } 193 for (var c = 0; c < node.childNodes.length; ++c) { 194 XNode.recycle(node.childNodes[c]); 195 } 196 node.attributes.length = 0; 197 node.childNodes.length = 0; 198 XNode.init.call(node, 0, '', '', null); 199 } 200 201 XNode.create = function(type, name, value, owner) { 202 if (XNode.unused_.length > 0) { 203 var node = XNode.unused_.pop(); 204 XNode.init.call(node, type, name, value, owner); 205 return node; 206 } else { 207 return new XNode(type, name, value, owner); 208 } 209 } 210 211 XNode.prototype.appendChild = function(node) { 212 // firstChild 213 if (this.childNodes.length == 0) { 214 this.firstChild = node; 215 } 216 217 // previousSibling 218 node.previousSibling = this.lastChild; 219 220 // nextSibling 221 node.nextSibling = null; 222 if (this.lastChild) { 223 this.lastChild.nextSibling = node; 224 } 225 226 // parentNode 227 node.parentNode = this; 228 229 // lastChild 230 this.lastChild = node; 231 232 // childNodes 233 this.childNodes.push(node); 234 } 235 236 237 XNode.prototype.replaceChild = function(newNode, oldNode) { 238 if (oldNode == newNode) { 239 return; 240 } 241 242 for (var i = 0; i < this.childNodes.length; ++i) { 243 if (this.childNodes[i] == oldNode) { 244 this.childNodes[i] = newNode; 245 246 var p = oldNode.parentNode; 247 oldNode.parentNode = null; 248 newNode.parentNode = p; 249 250 p = oldNode.previousSibling; 251 oldNode.previousSibling = null; 252 newNode.previousSibling = p; 253 if (newNode.previousSibling) { 254 newNode.previousSibling.nextSibling = newNode; 255 } 256 257 p = oldNode.nextSibling; 258 oldNode.nextSibling = null; 259 newNode.nextSibling = p; 260 if (newNode.nextSibling) { 261 newNode.nextSibling.previousSibling = newNode; 262 } 263 264 if (this.firstChild == oldNode) { 265 this.firstChild = newNode; 266 } 267 268 if (this.lastChild == oldNode) { 269 this.lastChild = newNode; 270 } 271 272 break; 273 } 274 } 275 } 276 277 XNode.prototype.insertBefore = function(newNode, oldNode) { 278 if (oldNode == newNode) { 279 return; 280 } 281 282 if (oldNode.parentNode != this) { 283 return; 284 } 285 286 if (newNode.parentNode) { 287 newNode.parentNode.removeChild(newNode); 288 } 289 290 var newChildren = []; 291 for (var i = 0; i < this.childNodes.length; ++i) { 292 var c = this.childNodes[i]; 293 if (c == oldNode) { 294 newChildren.push(newNode); 295 296 newNode.parentNode = this; 297 298 newNode.previousSibling = oldNode.previousSibling; 299 oldNode.previousSibling = newNode; 300 if (newNode.previousSibling) { 301 newNode.previousSibling.nextSibling = newNode; 302 } 303 304 newNode.nextSibling = oldNode; 305 306 if (this.firstChild == oldNode) { 307 this.firstChild = newNode; 308 } 309 } 310 newChildren.push(c); 311 } 312 this.childNodes = newChildren; 313 } 314 315 XNode.prototype.removeChild = function(node) { 316 var newChildren = []; 317 for (var i = 0; i < this.childNodes.length; ++i) { 318 var c = this.childNodes[i]; 319 if (c != node) { 320 newChildren.push(c); 321 } else { 322 if (c.previousSibling) { 323 c.previousSibling.nextSibling = c.nextSibling; 324 } 325 if (c.nextSibling) { 326 c.nextSibling.previousSibling = c.previousSibling; 327 } 328 if (this.firstChild == c) { 329 this.firstChild = c.nextSibling; 330 } 331 if (this.lastChild == c) { 332 this.lastChild = c.previousSibling; 333 } 334 } 335 } 336 this.childNodes = newChildren; 337 } 338 339 340 XNode.prototype.hasAttributes = function() { 341 return this.attributes.length > 0; 342 } 343 344 345 XNode.prototype.setAttribute = function(name, value) { 346 for (var i = 0; i < this.attributes.length; ++i) { 347 if (this.attributes[i].nodeName == name) { 348 this.attributes[i].nodeValue = '' + value; 349 return; 350 } 351 } 352 this.attributes.push(new XNode(DOM_ATTRIBUTE_NODE, name, value)); 353 } 354 355 356 XNode.prototype.getAttribute = function(name) { 357 for (var i = 0; i < this.attributes.length; ++i) { 358 if (this.attributes[i].nodeName == name) { 359 return this.attributes[i].nodeValue; 360 } 361 } 362 return null; 363 } 364 365 XNode.prototype.removeAttribute = function(name) { 366 var a = []; 367 for (var i = 0; i < this.attributes.length; ++i) { 368 if (this.attributes[i].nodeName != name) { 369 a.push(this.attributes[i]); 370 } 371 } 372 this.attributes = a; 373 } 374 375 376 function XDocument() { 377 XNode.call(this, DOM_DOCUMENT_NODE, '#document', null, this); 378 this.documentElement = null; 379 } 380 381 XDocument.prototype = new XNode(DOM_DOCUMENT_NODE, '#document'); 382 383 XDocument.prototype.clear = function() { 384 XNode.recycle(this.documentElement); 385 this.documentElement = null; 386 } 387 388 XDocument.prototype.appendChild = function(node) { 389 XNode.prototype.appendChild.call(this, node); 390 this.documentElement = this.childNodes[0]; 391 } 392 393 XDocument.prototype.createElement = function(name) { 394 return XNode.create(DOM_ELEMENT_NODE, name, null, this); 395 } 396 397 XDocument.prototype.createDocumentFragment = function() { 398 return XNode.create(DOM_DOCUMENT_FRAGMENT_NODE, '#document-fragment', 399 null, this); 400 } 401 402 XDocument.prototype.createTextNode = function(value) { 403 return XNode.create(DOM_TEXT_NODE, '#text', value, this); 404 } 405 406 XDocument.prototype.createAttribute = function(name) { 407 return XNode.create(DOM_ATTRIBUTE_NODE, name, null, this); 408 } 409 410 XDocument.prototype.createComment = function(data) { 411 return XNode.create(DOM_COMMENT_NODE, '#comment', data, this); 412 } 413 414 XNode.prototype.getElementsByTagName = function(name, list) { 415 if (!list) { 416 list = []; 417 } 418 419 if (this.nodeName == name) { 420 list.push(this); 421 } 422 423 for (var i = 0; i < this.childNodes.length; ++i) { 424 this.childNodes[i].getElementsByTagName(name, list); 425 } 426 427 return list; 428 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 21:07:04 2007 | par Balluche grâce à PHPXref 0.7 |