旗下导航:搜·么
当前位置:网站首页 > XML教程 > 正文

XML 题目: 逾越DOM(轻松运用 DOM 的技能和窍门)【XML教程】,XML,超越DOM

作者:搜教程发布时间:2019-12-01分类:XML教程浏览:77评论:0


导读:文档对象模子(DocumentObjectModel,DOM)是用于支配xml和HTML数据的最常用东西之一,然则它的潜力却很少被充足发掘出来。经由过程运用DOM的...
文档对象模子(Document Object Model,DOM)是用于支配 xml 和 HTML 数据的最常用东西之一,然则它的潜力却很少被充足发掘出来。经由过程运用 DOM 的上风,并使它越发易用,您将取得一款运用于 XML 运用顺序(包括动态 Web 运用顺序)的壮大东西。

本期文章引见了一名客串的专栏作家,同时也是我的朋侪和同事 Dethe Elza。Dethe 在运用 XML 举行 Web 运用顺序开辟方面经验丰富,在此,我要谢谢他对我在引见运用 DOM 和 ECMAScript 举行 XML 编程这一方面的协助。请亲昵关注本专栏,以相识 Dethe 的更多专栏文章。
—— David Mertz

DOM 是处置惩罚 XML 和 HTML 的范例 API 之一。由于它占用内存大、速度慢,而且冗杂,所以经常遭到人们的诘问诘责。尽管如此,关于很多运用顺序来讲,它仍然是最好挑选,而且比 XML 的另一个重要 API —— SAX 无疑要简朴很多。DOM 正逐渐出如今一些东西中,比方 Web 浏览器、SVG 浏览器、OpenOffice,等等。

DOM 很好,由于它是一种范例,而且被普遍地完成,同时也内置到其他范例中。作为范例,它对数据的处置惩罚与编程言语无关(这多是长处,也多是瑕玷,但最少使我们处置惩罚数据的体式格局变得一致)。DOM 如今不仅内置于 Web 浏览器,而且也成为很多基于 XML 的范例的一部份。既然它已成为您的东西的一部份,而且也许您偶然还会运用它,我想如今应当充足运用它给我们带来的功用了。

在运用 DOM 一段时候后,您会看到形成了一些形式 —— 您想要反复做的事变。快捷体式格局可以协助您处置惩罚冗杂的 DOM,并建立自诠释的、文雅的代码。这里收集了一些我经常运用的技能和窍门,另有一些 javaScript 示例。

insertAfter 和 PRependChild

第一个窍门就是“没有窍门”。DOM 有两种要领将孩子节点增加到容器节点(经常是一个 Element,也多是一个 Document 或 Document Fragment):appendChild(node) 和 insertBefore(node, referenceNode)。看起来好像缺少了什么。假如我想在一个参考节点背面插进去或许由前新增(prepend)一个子节点(使新节点位于列表中的第一名),我该怎么做呢?很多年以来,我的处理要领是编写以下函数:

清单 1. 插进去和由前新增的毛病要领

function insertAfter(parent, node, referenceNode) {
    if(referenceNode.nextSibling) {
        parent.insertBefore(node, referenceNode.nextSibling);
    } else {
        parent.appendChild(node);
    }
}
function prependChild(parent, node) {
    if (parent.firstChild) {
        parent.insertBefore(node, parent.firstChild);
    } else {
        parent.appendChild(node);
    }
}


实际上,像清单 1 一样,insertBefore() 函数已被定义为,在参考节点为空时返回到 appendChild()。因而,您可以不运用上面的要领,而运用 清单 2 中的要领,或许跳过它们仅运用内置函数:

清单 2. 插进去和由前新增的准确要领

function insertAfter(parent, node, referenceNode) {
    parent.insertBefore(node, referenceNode.nextSibling);
}
function prependChild(parent, node) {
    parent.insertBefore(node, parent.firstChild);
}


假如您方才打仗 DOM 编程,有必要指出的是,虽然您可以使多个指针指向一个节点,但该节点只能存在于 DOM 树中的一个位置。因而,假如您想将它插进去到树中,没必要先将它从树中移除,由于它会自动被移除。当从新将节点排序时,这类机制很轻易,仅需将节点插进去到新位置即可。

依据这类机制,若想交流两个相邻节点(称为 node1 和 node2)的位置,可以运用以下计划之一:

node1.parentNode.insertBefore(node2, node1);

node1.parentNode.insertBefore(node1.nextSibling, node1);

还可以运用 DOM 做什么?

Web 页面中大批运用了 DOM。若接见 bookmarklets 站点(参阅 参考资料),您会发明很多有创意的简短剧本,它们可以从新编排页面,提取链接,隐蔽图片或 Flash 广告,等等。

然则,由于 Internet Explorer 没有定义 Node 接口常量(可以用于辨认节点范例),所以您必需确保在脱漏接口常量时,起首为 Web 在 DOM 剧本中定义接口常量。

清单 3. 确保节点被定义

if (!window['Node']) {
    window.Node = new Object();
    Node.ELEMENT_NODE = 1;
    Node.ATTRIBUTE_NODE = 2;
    Node.TEXT_NODE = 3;
    Node.CDATA_SECTION_NODE = 4;
    Node.ENTITY_REFERENCE_NODE = 5;
    Node.ENTITY_NODE = 6;
    Node.PROCESSING_INSTRUCTION_NODE = 7;
    Node.COMMENT_NODE = 8;
    Node.DOCUMENT_NODE = 9;
    Node.DOCUMENT_TYPE_NODE = 10;
    Node.DOCUMENT_FRAGMENT_NODE = 11;
    Node.NOTATION_NODE = 12;
}


清单 4 展现怎样提取包括在节点中的一切文本节点:

清单 4. 内部文本

function innerText(node) {
    // is this a text or CDATA node?
    if (node.nodeType == 3 || node.nodeType == 4) {
        return node.data;
    }
    var i;
    var returnValue = [];
    for (i = 0; i < node.childNodes.length; i++) {
        returnValue.push(innerText(node.childNodes[i]));
    }
    return returnValue.join('');
}


快捷体式格局

人们经常埋怨 DOM 太甚冗杂,而且简朴的功用也须要编写大批代码。比方,假如您想建立一个包括文本并相应点击按钮的 <div> 元素,代码可以相似于:

清单 5. 建立 <div> 的“冗长之路”

function handle_button() {
    var parent = document.getElementById('myContainer');
    var div = document.createElement('div');
    div.className = 'myDivCSSClass';
    div.id = 'myDivId';
    div.style.position = 'absolute';
    div.style.left = '300px';
    div.style.top = '200px';
    var text = "This is the first text of the rest of this code";
    var textNode = document.createTextNode(text);
    div.appendChild(textNode);
    parent.appendChild(div);
}



若频仍根据这类体式格局建立节点,键入一切这些代码会使您很快筋疲力竭。必需有更好的处理计划 —— 确切有如许的处理计划!下面这个实用东西可以协助您建立元素、设置元素属性和作风,并增加文簿子节点。除了 name 参数,其他参数都是可选的。

清单 6. 函数 elem() 快捷体式格局

function elem(name, attrs, style, text) {
    var e = document.createElement(name);
    if (attrs) {
        for (key in attrs) {
            if (key == 'class') {
                e.className = attrs[key];
            } else if (key == 'id') {
                e.id = attrs[key];
            } else {
                e.setAttribute(key, attrs[key]);
            }
        }
    }
    if (style) {
        for (key in style) {
            e.style[key] = style[key];
        }
    }
    if (text) {
        e.appendChild(document.createTextNode(text));
    }
    return e;
}


运用该快捷体式格局,您可以以越发简约的要领建立 清单 5 中的 <div> 元素。注重,attrs 和 style 参数是运用 Javascript 文本对象而给出的。

清单 7. 建立 <div> 的轻便要领

function handle_button() {
    var parent = document.getElementById('myContainer');
    parent.appendChild(elem('div',
      {class: 'myDivCSSClass', id: 'myDivId'}
      {position: 'absolute', left: '300px', top: '200px'},
      'This is the first text of the rest of this code'));
}

在您想要疾速建立大批庞杂的 DHTML 对象时,这类实用东西可以节约您大批的时候。形式在这里就是指,假如您有一种须要频仍建立的特定的 DOM 构造,则运用实用东西来建立它们。这不只减少了您编写的代码量,而且也减少了反复的剪切、粘贴代码(毛病的罪魁祸首),而且在浏览代码时思绪越发清楚。

接下来是什么?
DOM 一般很难告诉您,根据文档的递次,下一个节点是什么。下面有一些实用东西,可以协助您在节点间前后挪动:

清单 8. nextNode 和 prevNode

// return next node in document order
function nextNode(node) {
    if (!node) return null;
    if (node.firstChild){
        return node.firstChild;
    } else {
        return nextWide(node);
    }
}
// helper function for nextNode()
function nextWide(node) {
    if (!node) return null;
    if (node.nextSibling) {
        return node.nextSibling;
    } else {
        return nextWide(node.parentNode);
    }
}
// return previous node in document order
function prevNode(node) {
    if (!node) return null;
    if (node.previousSibling) {
      return previousDeep(node.previousSibling);
    }
    return node.parentNode;
}
// helper function for prevNode()
function previousDeep(node) {
    if (!node) return null;
    while (node.childNodes.length) {
        node = node.lastChild;
    }
    return node;
}



轻松运用 DOM
有时候,您可以想要遍历 DOM,在每一个节点挪用函数或从每一个节点返回一个值。实际上,由于这些主意异常具有普遍性,所以 DOM Level 2 已包括了一个称为 DOM Traversal and Range 的扩大(为迭代 DOM 一切节点定义了对象和 API),它用来为 DOM 中的一切节点运用函数和在 DOM 中挑选一个局限。由于这些函数没有在 Internet Explorer 中定义(最少现在是如许),所以您可以运用 nextNode() 来做一些
相似的事变。

在这里,我们的主意是建立一些简朴、一般的东西,然后以差别的体式格局组装它们来到达预期的结果。假如您很熟悉函数式编程,这看起来会很亲热。Beyond JS 库(参阅 参考资料)将此理念发扬光大。

清单 9. 函数式 DOM 实用东西

// return an Array of all nodes, starting at startNode and
// continuing through the rest of the DOM tree
function listNodes(startNode) {
    var list = new Array();
    var node = startNode;
    while(node) {
        list.push(node);
        node = nextNode(node);
    }
    return list;
}
// The same as listNodes(), but works backwards from startNode.
// Note that this is not the same as running listNodes() and
// reversing the list.
function listNodesReversed(startNode) {
    var list = new Array();
    var node = startNode;
    while(node) {
        list.push(node);
        node = prevNode(node);
    }
    return list;
}
// apply func to each node in nodeList, return new list of results
function map(list, func) {
    var result_list = new Array();
    for (var i = 0; i < list.length; i++) {
        result_list.push(func(list[i]));
    }
    return result_list;
}
// apply test to each node, return a new list of nodes for which
// test(node) returns true
function filter(list, test) {
    var result_list = new Array();
    for (var i = 0; i < list.length; i++) {
        if (test(list[i])) result_list.push(list[i]);
    }
    return result_list;
}


清单 9 包括了 4 个基础东西。listNodes() 和 listNodesReversed() 函数可以扩大到一个可选的长度,这与 Array 的 slice() 要领结果相似,我把这个作为留给您的演习。另一个须要注重的是,map() 和 filter() 函数是完整通用的,用于处置惩罚任何 列表(不只是节点列表)。如今,我向您展现它们的几种组合体式格局。

清单 10. 运用函数式实用东西

// A list of all the element names in document order
function isElement(node) {
    return node.nodeType == Node.ELEMENT_NODE;
}
function nodeName(node) {
    return node.nodeName;
}
var elementNames = map(filter(listNodes(document),isElement), nodeName);
// All the text from the document (ignores CDATA)
function isText(node) {
    return node.nodeType == Node.TEXT_NODE;
}
function nodeValue(node) {
    return node.nodeValue;
}
var allText = map(filter(listNodes(document), isText), nodeValue);


您可以运用这些实用东西来提取 ID、修正款式、找到某种节点并移除,等等。一旦 DOM Traversal and Range API 被普遍完成,您无需起首构建列表,就可以用它们修正 DOM 树。它们不只功用壮大,而且事情体式格局也与我在上面所强调的体式格局相似。

DOM 的风险地带
注重,中心 DOM API 并不能使您将 XML 数据剖析到 DOM,或许将 DOM 序列化为 XML。这些功用都定义在 DOM Level 3 的扩大部份“Load and Save”,但它们还没有被完整完成,因而如今不要斟酌这些。每一个平台(浏览器或其他专业 DOM 运用顺序)有本身在 DOM 和 XML间转换的要领,但跨平台转换不在本文议论局限以内。

DOM 并非非常平安的东西 —— 特别是运用 DOM API 建立不能作为 XML 序列化的树时。相对不要在同一个顺序中夹杂运用 DOM1 非称号空间 API 和 DOM2 称号空间感知的 API(比方,createElement 和 createElementNS)。假如您运用称号空间,请只管在根元素位置声明一切称号空间,而且不要掩盖称号空间前缀,不然状况会异常杂沓。一般来讲,只需根据通例,就不会触发使您堕入贫苦的临界状况。

假如您一向运用 Internet Explorer 的 innerText 和 innerHTML 举行剖析,那末您可以尝尝运用 elem() 函数。经由过程构建相似的一些实用东西,您会获得更多方便,而且继续了跨平台代码的优越性。将这两种要领夹杂运用是异常蹩脚的。

某些 Unicode 字符并没有包括在 XML 中。DOM 的完成使您可以增加它们,但效果是没法序列化。这些字符包括大多数的控制字符和Unicode 代办对(surrogate pair)中的单个字符。只要您试图在文档中包括二进制数据时才会碰到这类状况,但这是另一种转向(gotcha)状况。


结束语
我已引见了 DOM 能做的很多事变,然则 DOM(和 JavaScript)可以做的事变远不止这些。细致研讨、琢磨这些例子,看看是怎样运用它们来处理可以须要客户端剧本、模板或专用 API 的题目。

DOM 有本身的局限性和瑕玷,但同时也具有浩瀚长处:它内置于很多运用顺序中;不管运用 Java 手艺、Python 或 JavaScript,它都以雷同体式格局事情;它异常便于运用 SAX;运用上述的模板,它运用起来既简约又壮大。越来越多的运用顺序最先支撑 DOM,这包括基于 Mozilla的运用顺序、OpenOffice 和 Blast Radius 的 XMetaL。越来越多的范例须要 DOM,并对它加以扩大(比方,SVG),因而 DOM 每时每刻就在您的身旁。运用这类被普遍布置的东西,相对是您的明智之举。

以上就是XML 题目: 逾越DOM(轻松运用 DOM 的技能和窍门)的内容,更多相关内容请关注ki4网(www.ki4.cn)!

标签:XML超越DOM


欢迎 发表评论: