-
DOM接口(API)
核心接口
DOM是语言无关的API,这意味着它的实现并不与Java、JavaScript或者其他语言绑定。DOM定义了Node的接口以及组成DOM树(也称之为文档)各元素的Node子接口,组成树的各元素都是Node节点。下面这些都是Node的子接口(即各节点类型),它们是组成DOM树的核心接口 :
Document ——最顶层的节点,所有的其他节点都是附属于它的。
DocumentType ——DTD引用(使用 <!DOCTYPE >语法)的对象表现形式,例如 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">。它不能包含子节点。
DocumentFragment ——可以像Document一样来保存其他节点。
Element ——表示起始标签和结束标签之间的内容,例如 <tag> </tag>或者 <tag/>。这是唯一可以同时包含属性和子节点的节点类型。
Attr ——代表一对属性名和属性值。这个节点类型不能包含子节点。
Text ——代表XML文档中的在起始标签和结束标签之间,或者CData Section内包含的普通文本。这个节点类型不能包含子节点。
CDataSection —— <![CDATA[ ]]>的对象表现形式。这个节点类型仅能包含文本节点Text作为子节点。
Entity ——表示在DTD中的一个实体定义,例如 <!ENTITY foo "foo">。这个节点类型不能包含子节点。
EntityReference ——代表一个实体引用,例如"。这个节点类型不能包含子节点。
ProcessingInstruction ——代表一个PI(处理指令)。这个节点类型不能包含子节点。
Comment ——代表XML注释。这个节点类型不能包含子节点。
Notation ——代表在DTD中定义的记号。这个很少用到。
节点类型常量
Node接口定义了对应不同节点类型的12个常量 (Node . nodeType),不同的节点对应不同的节点类型:
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)
Node接口
Node接口也定义了一些所有节点类型都包含的属性和方法 ,下面的表格中列出了这些属性和方法:
属性 / 方法 | 返回类型 | 说 明 |
nodeName | String | 节点的名字;根据节点的类型而定义 |
nodeValue | String | 节点的值;根据节点的类型而定义 |
nodeType | Number | 节点的类型常量值之一 |
ownerDocument | Document | 指向这个节点所属的文档 |
firstChild | Node | 指向在 childNodes 列表中的第一个节点 |
lastChild | Node | 指向在 childNodes 列表中的最后一个节点 |
childNodes | NodeList | 所有子节点的列表 |
previousSibling | Node | 指向前一个兄弟节点;如果这个节点就是第一个兄弟节点,那么该值为 null |
nextSibling | Node | 指向后一个兄弟节点;如果这个节点就是最后一个兄弟节点,那么该值为 null |
hasChildNodes() | Boolean | 当 childNodes 包含一个或多个节点时,返回真 |
attributes | NamedNodeMap | 包含了代表一个元素的 属性的 Attr 对象;仅用于 Element 节点 |
appendChild(node ) | Node | 将 node 添加到 childNodes 的末尾 |
removeChild(node ) | Node | 从 childNodes 中删除 node |
replaceChild(newnode , oldnode ) | Node | 将 childNodes 中的 oldnode 替换成 newnode |
insertBefore(newnode , refnode ) | Node | 在 childNodes 中的 refnode 之前插入 newnode |
除节点外, DOM 还定义了一些助手对象,它们可以和节点一起使用,但不是 DOM 文档必有的部分。
NodeList ——节点数组,按照数值进行索引;用来表示一个元素的子节点。
NamedNodeMap ——同时用数值和名字进行索引的节点表;用于表示元素属性。
这些助手对象为处理 DOM 文档提供附加的访问和遍历方法。
Document接口
Document 对象的属性
属性 | 描述 | IE | F | O | W3C |
---|---|---|---|---|---|
async | 规定 XML 文件的下载是否应当被同步处理。 | 5 | 1.5 | 9 | No |
childNodes | 返回属于文档的子节点的节点列表。 | 5 | 1 | 9 | Yes |
doctype | 返回与文档相关的文档类型声明 (DTD)。 | 6 | 1 | 9 | Yes |
documentElement | 返回文档的根节点 | 5 | 1 | 9 | Yes |
documentURI | 设置或返回文档的位置 | No | 1 | 9 | Yes |
domConfig | 返回normalizeDocument()被调用时所使用的配置 | No | Yes | ||
firstChild | 返回文档的首个子节点 | 5 | 1 | 9 | Yes |
implementation | 返回处理该文档的 DOMImplementation 对象。 | No | 1 | 9 | Yes |
inputEncoding | 返回用于文档的编码方式(在解析时)。 | No | 1 | No | Yes |
lastChild | 返回文档的最后一个子节点。 | 5 | 1 | 9 | Yes |
nodeName | 依据节点的类型返回其名称。 | 5 | 1 | 9 | Yes |
nodeType | 返回节点的节点类型。 | 5 | 1 | 9 | Yes |
nodeValue | 根据节点的类型来设置或返回节点的值。 | 5 | 1 | 9 | Yes |
strictErrorChecking | 设置或返回是否强制进行错误检查。 | No | 1 | No | Yes |
text | 返回节点及其后代的文本(仅用于 IE)。 | 5 | No | No | No |
xml | 返回节点及其后代的 XML(仅用于 IE)。 | 5 | No | No | No |
xmlEncoding | 返回文档的编码方法。 | No | 1 | No | Yes |
xmlStandalone | 设置或返回文档是否为 standalone。 | No | 1 | No | Yes |
xmlVersion | 设置或返回文档的 XML 版本。 | No | 1 | No | Yes |
Document 对象的方法
属性 | 描述 | IE | F | O | W3C |
---|---|---|---|---|---|
adoptNode(sourcenode) | 从另一个文档向本文档选定一个节点,然后返回被选节点。 | No | Yes | ||
createAttribute(name) | 创建拥有指定名称的属性节点,并返回新的 Attr 对象。 | 6 | 1 | 9 | Yes |
createAttributeNS(uri,name) | 创建拥有指定名称和命名空间的属性节点,并返回新的 Attr 对象。 | 9 | Yes | ||
createCDATASection() | 创建 CDATA 区段节点。 | 5 | 1 | 9 | Yes |
createComment() | 创建注释节点。 | 6 | 1 | 9 | Yes |
createDocumentFragment() | 创建空的 DocumentFragment 对象,并返回此对象。 | 5 | 1 | 9 | Yes |
createElement() | 创建元素节点。 | 5 | 1 | 9 | Yes |
createElementNS() | 创建带有指定命名空间的元素节点。 | No | 1 | 9 | Yes |
createEvent() | 创建新的 Event 对象。 | Yes | |||
createEntityReference(name) | 创建 EntityReference 对象,并返回此对象。 | 5 | No | Yes | |
createExpression() | 创建一个XPath表达式以供稍后计算。 | Yes | |||
createProcessingInstruction(target,data) | 创建 ProcessingInstruction 对象,并返回此对象。 | 5 | 9 | Yes | |
createRange() | 创建 Range 对象,并返回此对象。 | No | Yes | ||
evaluate() | 计算一个 XPath 表达式。 | No | 1 | 9 | Yes |
createTextNode() | 创建文本节点。 | 5 | 1 | 9 | Yes |
getElementById() | 查找具有指定的唯一 ID 的元素。 | 5 | 1 | 9 | Yes |
getElementsByTagName() | 返回所有具有指定名称的元素节点。 | 5 | 1 | 9 | Yes |
getElementsByTagNameNS() | 返回所有具有指定名称和命名空间的元素节点。 | No | 1 | 9 | Yes |
importNode() | 把一个节点从另一个文档复制到该文档以便应用。 | 9 | Yes | ||
loadXML() | 通过解析XML标签字符串来组成文档。 | ||||
normalizeDocument() | No | Yes | |||
renameNode() | 重命名元素或者属性节点。 | No | Yes |
Node的名、值、属性
nodeName 、 nodeValue 和 attributes 的值将根据以下节点类型的不同而不同:
Interface | nodeName | nodeValue | attributes |
Attr | 与 Attr.name 相同 | 与 Attr.value 相同 | null |
CDATASection | "#cdata-section" | 与 CharacterData.data 相同,CDATA 节的内容 | null |
Comment | "#comment" | 与 CharacterData.data 相同,该注释的内容 | null |
Document | "#document" | null | null |
DocumentFragment | "#document-fragment" | null | null |
DocumentType | 与 DocumentType.name 相同 | null | null |
Element | 与 Element.tagName 相同 | null | NamedNodeMap |
Entity | entity name | null | null |
EntityReference | 引用的实体名称 | null | null |
Notation | notation name | null | null |
ProcessingInstruction | 与 ProcessingInstruction.target 相同 | 与 ProcessingInstruction.data 相同 | null |
Text | "#text" | 与 CharacterData.data 相同,该文本节点的 |
|
IE与Mozilla上的childNodes区别
如同對於標準 HTML,對於可各方面控制 XML 檔的 DOM 的支援,Mozilla 也是依 W3C 所定的 XML DOM 規格。Mozilla 與 Internet Explorer 在 XML DOM 上的不同處大多在於 Internet Explorer 非標準的處理方式 。一個常見的差異是對空白字元節點的處理。 通常在建立 XML 時,XML 節點間會有空白。 Internet Explorer 用 XMLNode.childNodes[] 時不會包括這些空白節點,但在 Mozilla 上這些節點會在 array 裡 。
XML: <?xml version="1.0"?> <myXMLdoc xmlns:myns="http://myfoo.com"> <myns:foo>bar</myns:foo> </myXMLdoc> JavaScript: var myXMLDoc = getXMLDocument().documentElement; alert(myXMLDoc.childNodes.length);
The first line of JavaScript 的第一行載入 XML 檔並用 documentElement 來存取它的 root 元素 (myXMLDoc,getXMLDocument()为XML DOM类型,即文档类型,是一个自定义方法 )。第二行顯示子節點的數目。根據 W3C 規格,接在一起的空白與換行字符組成一個文字節點 。在 Mozilla 上 myXMLdoc 節點有三個子:一個有換行字符與兩個空白的文字節點、myns:foo 節點、與另一個有換行字符的文字節點 。Internet Explorer 並不遵循這個,因此上面的程式碼會顯示 "1",表示只有 myns:foo 節點 。所以,如要迴走(遍历、迭代的意思)子節點並掠過文字節點,要分辨這些節點。
如前所述,每个节点都有一个节点类型属性代表节点类型。例如,一个元素节点有类型1,而文档节点类型9。忽略文本节点,你必须检查类型3(文本节点)和8(注释节点),像这样:
XML: <?xml version="1.0"?> <myXMLdoc xmlns:myns="http://myfoo.com"> <myns:foo>bar</myns:foo> </myXMLdoc> JavaScript: var myXMLDoc = getXMLDocument().documentElement; var myChildren = myXMLDoc.childNodes; for (var run = 0; run < myChildren.length; run++){ if ( (myChildren[run].nodeType != 3) && myChildren[run].nodeType != 8) ){ // not a text or comment node } }
另:特别要注意的是,Mozilla上存在此种情况是因为某节点下的子节点即含有文本 (TEXT)节点(一般是元素前有回车符、TAB键、空格,或其他可打印字符),又含有元素(ELEMENT)节点时childNodes才把空白字符也 算作节点。但如果某节点下只有文本时(没有其他ELEMENT元素节点),此时的childNodes只会有一个节点(即一个文本节点),详细请看下一节 内容。
IE上的nodeValue与text区别
在IE上文本节点除了有nodeValue属性外还有一个text属性,作用都是返回文本的值,但两者区别在于:nodeValue返回的数据会包含文本节点前后的空白字符,包含回车符,但text就只返回文本本身,不包含前后空白字符。
<root> data </root>
<script type="text/javascript" src="detect.js"></script> <script type="text/javascript" src="xmldom.js"></script> <script type="text/javascript"> var oXmlDom = new XmlDom(); oXmlDom.onreadystatechange = function () { if (oXmlDom.readyState == 4 || (oXmlDom.getReadyState && oXmlDom.getReadyState() == 4)) { var nodeList = oXmlDom.documentElement.childNodes; alert(nodeList.length);//IE与Mozilla上都是 1 for(var i = 0 ; i < nodeList.length; i++){ alert('nodeValue.length = ' + nodeList[i].nodeValue.length + '-->' + nodeList[i].nodeValue + '<--'); //Mozilla上没有text属性,所以不会输出 if(nodeList[i].text){ alert('text.length = ' + nodeList[i].text.length + '-->' + nodeList[i].text + '<--'); } } } }; oXmlDom.load("test.xml"); </script>
IE上结果如下:
注:text不会返回子节点的文本内容
Mozilla上结果如下(注:Mozilla无text属性,所以不输出):
-
利用 HTML DOM 在 HTML 元素之间导航
可以使用document的documentElement属性来得到HTML文档的根节点:
var oHtml = document.documentElement;
如果想继续得到 <head/>与 <body/>元素时,可以这样实现:
var oHead = oHtml.firstChild; var oBody = oHtml.lastChild;
也可以使用childNodes属性来完成同样的工作:
var oHead = oHtml.childNodes[0]; var oBody = oHtml.childNodes[1];
你还可以通过使用childNodes.length属性来获取子节点的数量:
oHtml.childNodes.length;//2
注意:方括号标记其实是NodeList在JavaScript中的简便实现。实际上正式的从childNodes列表中获取子节点的方法是使用item()方法 :
var oHead = oHtml.childNodes.item(0); var oBody = oHtml.childNodes.item(1);
HTML DOM页定义了document.body作为指向 <body/>元素的指针:
var oBody = document.body;
测试oHtml、oHead和oBody这三个元素之间的关系:
alert(oHead.parentNode == oHtml);//true alert(oBody.parentNode == oHtml); //true alert(oBody.previousSibling == oHead); //true alert(oHead.nextSibling == oBody); //true alert(oHead.ownerDocument == document); //true
-
检测 HTML DOM 节点类型
我们可以通过使用nodeType属性检验节点类型:
alert(document.nodeType); //9 alert(document.documentElement.nodeType);//1
也可以用Node常量来匹配这些值:
alert(document.nodeType == Node.DOCUMENT_NODE); //true alert(document.documentElement.nodeType == Node.ELEMENT_NODE);//true
这段代码可以在Mozilla 1.0+、Opera 7.0+和Safari 1.0+上正常运行。不幸的是,IE不支持这些常量,所以这些代码在IE上会产生错误。所幸,可以通过定义匹配节点类型的常量来纠正这种情况,正如下面这样:
if (typeof Node == "undefined") { var Node = {ELEMENT_NODE:1, //... NOTATION_NODE:12 }; }
-
处理 Element 元素的属性
Node接口已具有attributes属性,且已被所有类型的节点继承,然而,只有Element节点才能有属性。Element节点的attributes属性其实是NamedNodeMap,它提供一些用于访问和处理其内容的方法:
getNamedItem (name )——返回nodeName属性值等于name的Attr节点;
remove NamedItem (name )——删除nodeName属性值等于name的Attr节点;
setNamedItem (node )——将node添加到列表中,按其nodeName属性进行索引;
item (pos )——像NodeList一样,返回在位置pos的Attr节点;
NamedNodeMap 对象也有一个length属性来指示它所包含的属性个数。
NamedNodeMap中存储的为Attr节点,Attr的nodeName属性被设置为元素属性名称,而nodeValue属性被设置为元素属性的值。例如,假设有这样一个元素:
<p style='color:red' id='p1'>Hello world! </p>
同时,假设变量oP包含指向这个元素的一个引用。于是可以这样访问id属性的值:
var sId = oP.attributes.getNamedItem('id').nodeValue;
当然,还可以用数值方式访问id属性:
var sId = oP.attributes.item(1).nodeValue;
还可以通过给nodeValue属性赋新值来改变id属性:
oP.attributes.getNamedItem('id').nodeValue = 'newId';
Attr节点也有一个完全等同于(同时也完全同步于)nodeValue属性的value属性,并且有name属性和nodeName属性保持同步 。我们可以随意使用这些属性来修改或变更属性。
因为这个方法有些累赘,DOM又定义了三个Element元素方法来帮助访问其属性:
getAttribute (name )——等于attributes.getNamedItem(name).value
setAttribute (name, newvalue )——等于attribute.getNamedItem(name).value = newvalue
removeAttribute (name )——等于attributes.removeNamedItem(name)
这些方法相当有用,可以直接处理属性值,完全地隐藏Attr节点。所以,要获取前面用的 <p/>的id属性,只需这样做:
var sId = oP.getAttribute("id");
同时要更改ID,可以这样做
op.setAttribute('id','newId');
正如你所看到的,这些方法要比使用NamedNodeMap的方法简洁得多。
-
访问指定节点
如何访问父节点和子节点前面已讲过了,都很简单,但是如果想访问文档中位置很深的某个节点 (或者一组节点),要怎么做呢?
1、getElementsByTagName()
核心(XML核心DOM的属性和方法是通用的)DOM定义了getElementsByTagName()方法,用来返回一个包含所有的tagName(标签名)等于某个指定值的元素的NodeList。下一行代码返回文档中所有 <img/>元素的列表:
var oImgs = document.getElementsByTagName("img");
访问第一个 <img/>元素:
alert(oImgs.item(0).tagName);//IMG
注:大部分浏览器按照大写来记录标签名,即使XHTML约定指出标签名应当全部小写
但是假如你只想获取在某个页面第一个段落中的所有图像呢?可以通过对第一个段落元素调用getElementsByTagName()来完成,像这样:
var oPs = document.getElementsByTagname('p'); var oImgsInP = oPs[0].getElementsByTagName('img');
这样就限制元素的搜索范围。
返回文档中所有元素:
var oAllElements = document.getElementsByTagname('*');
注:IE不支持,使用document.all
2. getElementsByName()
HTML DOM定义了getElementsByName(),它用来获取所有HTML标签中的name属性等于指定值元素的NodeList。该方法只适用于HTML文档,不是核心(XML)DOM所定义的。
注:IE 6.0和Opera 7.5在这个方法的使用上还存在一些错误。首先,除了返回name属性等于指定值的元素,它们还会返回id等于指定值的元素。第二,它们仅仅检查 <input/>和 <img/>元素。
3. getElementById()
这是HTML DOM定义的第二种方法,它将返回id 属性等于指定值的元素。在HTML中,id 属性是唯一的。
注:如果给定的ID匹配某个元素的name属性,且是每个,IE 6.0会返回这个元素。这是一个bug,使用时必须非常小心的一个问题。