dom.js

来自「ajax patterns 这是关于ajax设计模式方面的原代码」· JavaScript 代码 · 共 429 行

JS
429
字号
// Copyright 2005 Google Inc.// All Rights Reserved//// An XML parse and a minimal DOM implementation that just supportes// the subset of the W3C DOM that is used in the XSLT implementation.//// References: //// [DOM] W3C DOM Level 3 Core Specification//       <http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/>.//// // Author: Steffen Meschkat <mesch@google.com>// NOTE: The split() method in IE omits empty result strings. This is// utterly annoying. So we don't use it here.// Resolve entities in XML text fragments. According to the DOM// specification, the DOM is supposed to resolve entity references at// the API level. I.e. no entity references are passed through the// API. See "Entities and the DOM core", p.12, DOM 2 Core// Spec. However, different browsers actually pass very different// values at the API.//function xmlResolveEntities(s) {  var parts = stringSplit(s, '&');  var ret = parts[0];  for (var i = 1; i < parts.length; ++i) {    var rp = stringSplit(parts[i], ';');    if (rp.length == 1) {      // no entity reference: just a & but no ;      ret += parts[i];      continue;    }        var ch;    switch (rp[0]) {      case 'lt':         ch = '<';        break;      case 'gt':         ch = '>';        break;      case 'amp':         ch = '&';        break;      case 'quot':         ch = '"';        break;      case 'apos':         ch = '\'';        break;      case 'nbsp':         ch = String.fromCharCode(160);        break;      default:        // Cool trick: let the DOM do the entity decoding. We assign        // the entity text through non-W3C DOM properties and read it        // through the W3C DOM. W3C DOM access is specified to resolve        // entities.         var span = window.document.createElement('span');        span.innerHTML = '&' + rp[0] + '; ';        ch = span.childNodes[0].nodeValue.charAt(0);    }    ret += ch + rp[1];  }  return ret;}// Parses the given XML string with our custom, JavaScript XML parser. Written// by Steffen Meschkat (mesch@google.com).function xmlParse(xml) {  Timer.start('xmlparse');  var regex_empty = /\/$/;  // See also <http://www.w3.org/TR/REC-xml/#sec-common-syn> for  // allowed chars in a tag and attribute name. TODO(mesch): the  // following is still not completely correct.  var regex_tagname = /^([\w:-]*)/;  var regex_attribute = /([\w:-]+)\s?=\s?('([^\']*)'|"([^\"]*)")/g;  var xmldoc = new XDocument();  var root = xmldoc;  // For the record: in Safari, we would create native DOM nodes, but  // in Opera that is not possible, because the DOM only allows HTML  // element nodes to be created, so we have to do our own DOM nodes.  // xmldoc = document.implementation.createDocument('','',null);  // root = xmldoc; // .createDocumentFragment();  // NOTE(mesch): using the DocumentFragment instead of the Document  // crashes my Safari 1.2.4 (v125.12).  var stack = [];  var parent = root;  stack.push(parent);  var x = stringSplit(xml, '<');  for (var i = 1; i < x.length; ++i) {    var xx = stringSplit(x[i], '>');    var tag = xx[0];    var text = xmlResolveEntities(xx[1] || '');    if (tag.charAt(0) == '/') {      stack.pop();      parent = stack[stack.length-1];    } else if (tag.charAt(0) == '?') {      // Ignore XML declaration and processing instructions    } else if (tag.charAt(0) == '!') {      // Ignore notation and comments    } else {      var empty = tag.match(regex_empty);      var tagname = regex_tagname.exec(tag)[1];      var node = xmldoc.createElement(tagname);      var att;      while (att = regex_attribute.exec(tag)) {        var val = xmlResolveEntities(att[3] || att[4] || '');        node.setAttribute(att[1], val);      }            if (empty) {        parent.appendChild(node);      } else {        parent.appendChild(node);        parent = node;        stack.push(node);      }    }    if (text && parent != root) {      parent.appendChild(xmldoc.createTextNode(text));    }  }  Timer.end('xmlparse');  return root;}// Our W3C DOM Node implementation. Note we call it XNode because we// can't define the identifier Node. We do this mostly for Opera,// where we can't reuse the HTML DOM for parsing our own XML, and for// Safari, where it is too expensive to have the template processor// operate on native DOM nodes.function XNode(type, name, value, owner) {  this.attributes = [];  this.childNodes = [];  XNode.init.call(this, type, name, value, owner);}// Don't call as method, use apply() or call().XNode.init = function(type, name, value, owner) {  this.nodeType = type - 0;  this.nodeName = '' + name;  this.nodeValue = '' + value;  this.ownerDocument = owner;  this.firstChild = null;  this.lastChild = null;  this.nextSibling = null;  this.previousSibling = null;  this.parentNode = null;}XNode.unused_ = [];XNode.recycle = function(node) {  if (!node) {    return;  }  if (node.constructor == XDocument) {    XNode.recycle(node.documentElement);    return;  }  if (node.constructor != this) {    return;  }  XNode.unused_.push(node);  for (var a = 0; a < node.attributes.length; ++a) {    XNode.recycle(node.attributes[a]);  }  for (var c = 0; c < node.childNodes.length; ++c) {    XNode.recycle(node.childNodes[c]);  }  node.attributes.length = 0;  node.childNodes.length = 0;  XNode.init.call(node, 0, '', '', null);}XNode.create = function(type, name, value, owner) {  if (XNode.unused_.length > 0) {    var node = XNode.unused_.pop();    XNode.init.call(node, type, name, value, owner);    return node;  } else {    return new XNode(type, name, value, owner);  }}XNode.prototype.appendChild = function(node) {  // firstChild  if (this.childNodes.length == 0) {    this.firstChild = node;  }  // previousSibling  node.previousSibling = this.lastChild;  // nextSibling  node.nextSibling = null;  if (this.lastChild) {    this.lastChild.nextSibling = node;  }  // parentNode  node.parentNode = this;  // lastChild  this.lastChild = node;  // childNodes  this.childNodes.push(node);}XNode.prototype.replaceChild = function(newNode, oldNode) {  if (oldNode == newNode) {    return;  }  for (var i = 0; i < this.childNodes.length; ++i) {    if (this.childNodes[i] == oldNode) {      this.childNodes[i] = newNode;            var p = oldNode.parentNode;      oldNode.parentNode = null;      newNode.parentNode = p;            p = oldNode.previousSibling;      oldNode.previousSibling = null;      newNode.previousSibling = p;      if (newNode.previousSibling) {        newNode.previousSibling.nextSibling = newNode;      }            p = oldNode.nextSibling;      oldNode.nextSibling = null;      newNode.nextSibling = p;      if (newNode.nextSibling) {        newNode.nextSibling.previousSibling = newNode;      }      if (this.firstChild == oldNode) {        this.firstChild = newNode;      }      if (this.lastChild == oldNode) {        this.lastChild = newNode;      }      break;    }  }}XNode.prototype.insertBefore = function(newNode, oldNode) {  if (oldNode == newNode) {    return;  }  if (oldNode.parentNode != this) {    return;  }  if (newNode.parentNode) {    newNode.parentNode.removeChild(newNode);  }  var newChildren = [];  for (var i = 0; i < this.childNodes.length; ++i) {    var c = this.childNodes[i];    if (c == oldNode) {      newChildren.push(newNode);      newNode.parentNode = this;      newNode.previousSibling = oldNode.previousSibling;      oldNode.previousSibling = newNode;      if (newNode.previousSibling) {        newNode.previousSibling.nextSibling = newNode;      }            newNode.nextSibling = oldNode;      if (this.firstChild == oldNode) {        this.firstChild = newNode;      }    }    newChildren.push(c);  }  this.childNodes = newChildren;}XNode.prototype.removeChild = function(node) {  var newChildren = [];  for (var i = 0; i < this.childNodes.length; ++i) {    var c = this.childNodes[i];    if (c != node) {      newChildren.push(c);    } else {      if (c.previousSibling) {        c.previousSibling.nextSibling = c.nextSibling;      }      if (c.nextSibling) {        c.nextSibling.previousSibling = c.previousSibling;      }      if (this.firstChild == c) {        this.firstChild = c.nextSibling;      }      if (this.lastChild == c) {        this.lastChild = c.previousSibling;      }    }  }  this.childNodes = newChildren;}XNode.prototype.hasAttributes = function() {  return this.attributes.length > 0;}XNode.prototype.setAttribute = function(name, value) {  for (var i = 0; i < this.attributes.length; ++i) {    if (this.attributes[i].nodeName == name) {      this.attributes[i].nodeValue = '' + value;      return;    }  }  this.attributes.push(new XNode(DOM_ATTRIBUTE_NODE, name, value));}XNode.prototype.getAttribute = function(name) {  for (var i = 0; i < this.attributes.length; ++i) {    if (this.attributes[i].nodeName == name) {      return this.attributes[i].nodeValue;    }  }  return null;}XNode.prototype.removeAttribute = function(name) {  var a = [];  for (var i = 0; i < this.attributes.length; ++i) {    if (this.attributes[i].nodeName != name) {      a.push(this.attributes[i]);    }  }  this.attributes = a;}function XDocument() {  XNode.call(this, DOM_DOCUMENT_NODE, '#document', null, this);  this.documentElement = null;}XDocument.prototype = new XNode(DOM_DOCUMENT_NODE, '#document');XDocument.prototype.clear = function() {  XNode.recycle(this.documentElement);  this.documentElement = null;}XDocument.prototype.appendChild = function(node) {  XNode.prototype.appendChild.call(this, node);  this.documentElement = this.childNodes[0];}XDocument.prototype.createElement = function(name) {  return XNode.create(DOM_ELEMENT_NODE, name, null, this);}XDocument.prototype.createDocumentFragment = function() {  return XNode.create(DOM_DOCUMENT_FRAGMENT_NODE, '#document-fragment',                    null, this);}XDocument.prototype.createTextNode = function(value) {  return XNode.create(DOM_TEXT_NODE, '#text', value, this);}XDocument.prototype.createAttribute = function(name) {  return XNode.create(DOM_ATTRIBUTE_NODE, name, null, this);}XDocument.prototype.createComment = function(data) {  return XNode.create(DOM_COMMENT_NODE, '#comment', data, this);}XNode.prototype.getElementsByTagName = function(name, list) {  if (!list) {    list = [];  }  if (this.nodeName == name) {    list.push(this);  }  for (var i = 0; i < this.childNodes.length; ++i) {    this.childNodes[i].getElementsByTagName(name, list);  }  return list;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?