XML DOM 定义了访问和处理 XML 文档的标准方法。
XML DOM 是 XML Document Object Model 的缩写,即 XML 文档对象模型。
DOM 是这样规定的:
- 整个文档是一个文档节点
- 每个 XML 标签是一个元素节点
- 包含在 XML 元素中的文本是文本节点
- 每一个 XML 属性是一个属性节点
- 注释属于注释节点
文本总是存储在文本节点中
在 DOM 处理中一个普遍的错误是,认为元素节点包含文本。不过,元素节点的文本是存储在文本节点中的。在这个例子中:<year>2005</year>,元素节点<year>,拥有一个值为 "2005" 的文本节点。"2005" 不是 <year> 元素的值!
节点关系
XML DOM 把 XML DOM 文档视为一棵节点树 (node-tree)。树中的所有节点彼此之间都有关系。
可通过这棵树访问所有节点。可以修改或删除它们的内容,也可以创建新的元素。这颗节点树展示了节点的集合,以及它们之间的联系。这棵树从根节点开始,然后在树的最低层级向文本节点长出枝条:
父、子和同级节点、第一个子节点和最后一个子节点
节点树中的节点彼此之间都有等级关系。
父、子和同级节点用于描述这种关系。父节点拥有子节点,位于相同层级上的子节点称为同级节点(兄弟或姐妹)。
- 在节点树中,顶端的节点成为根节点
- 根节点之外的每个节点都有一个父节点
- 节点可以有任何数量的子节点
- 叶子是没有子节点的节点
- 同级节点是拥有相同父节点的节点
下面的图片展示出节点树的一个部分,以及节点间的关系:
因为 XML 数据是按照树的形式进行构造的,所以可以在不了解树的确切结构且不了解其中包含的数据类型的情况下,对其进行遍历。
节点的三个重要属性
节点的属性
在 XML 文档对象模型 (DOM) 中,每个节点都是一个对象。
对象拥有方法(功能)和属性(关于对象的信息),并可通过 JavaScript 进行访问和操作。
三个重要的 XML DOM 节点属性是:
- nodeName
- nodeValue
- nodeType
nodeName 属性
nodeName 属性规定节点的名称。
- nodeName 是只读的
- 元素节点的 nodeName 与标签名相同
- 属性节点的 nodeName 是属性的名称
- 文本节点的 nodeName 永远是 #text
- 文档节点的 nodeName 永远是 #document
nodeValue 属性
nodeValue 属性规定节点的值。
- 元素节点的 nodeValue 是 undefined
- 文本节点的 nodeValue 是文本自身
- 属性节点的 nodeValue 是属性的值
- 是可读写的,利用这个特性可以很方便的操作文本节点和属性节点值;
1、获取元素的值:
下面的代码检索第一个 <title> 元素的文本节点的值:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title")[0].childNodes[0]; txt=x.nodeValue;
2、更改元素的值:
下面的代码更改第一个 <title> 元素的文本节点的值:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title")[0].childNodes[0]; x.nodeValue="Easy Cooking
nodeType 属性
nodeType 属性规定节点的类型。
nodeType 是只读的。
最重要的节点类型是:
元素类型 | 节点类型 |
---|---|
元素 | 1 |
属性 | 2 |
文本 | 3 |
注释 | 8 |
文档 | 9 |
XMLDOM NodeList
DOmNodelist:
当使用诸如 childNodes 或 getElementsByTagName() 属性或方法时,会返回 NodeList 对象。NodeList 对象表示节点的列表,以 XML 中的相同顺序。使用从 0 开始的下标来访问节点列表中的节点。
下面的代码片段通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中,并返回 "books.xml" 中 title 元素的一个节点列表
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title")
以上语句执行之后,x 成为一个 NodeList 对象。下面的代码片段从节点列表 x 中的第一个 <title> 元素中返回文本:
txt=x[0].childNodes[0].nodeValue;
Node List Length
NodeList 对象会保持自身的更新。如果删除或添加了元素,列表会自动更新。
节点列表的 length 属性是列表中节点的数量。
下面的代码片段通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc,并返回 "books.xml" 中 <title> 元素的数量:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName('title').length;
DOM Attribute List (Named Node Map)
元素节点的 attributes 属性返回属性节点的列表。
这被称为 Named Node Map,除了方法和属性上的一些差别以外,它与节点列表相似。
属性列表会保持自身的更新。如果删除或添加属性,这个列表会自动更新。
下面的代码片段通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中,并从 "books.xml" 中的第一个 <book> 元素返回属性节点的一个列表:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName('book')[0].attributes;
以上代码执行之后,x.length 等于属性的数量,可使用 x.getNamedItem() 返回属性节点。下面的代码片段一个 book 的 "category" 属性的值,以及其属性的数量:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("book")[0].attributes; document.write(x.getNamedItem("category").nodeValue); document.write("<br />" + x.length);
XMLDOM节点访问
访问节点
您可以通过三种方法来访问节点:
- 通过使用 getElementsByTagName() 方法
- 通过循环(遍历)节点树
- 通过利用节点的关系在节点树中导航
XMLDOM定位节点
定位 DOM 节点
通过节点间的关系访问节点树中的节点,通常称为定位节点 ("navigating nodes")。
在 XML DOM 中,节点的关系被定义为节点的属性:
- parentNode
- childNodes
- firstChild
- lastChild
- nextSibling
- previousSibling
下面的图像展示了 books.xml 中节点树的一个部分,并说明了节点之间的关系:
DOM - 父节点:所有的节点都仅有一个父节点。下面的代码定位到 <book> 的父节点:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("book")[0]; document.write(x.parentNode.nodeName);
其他的关系需要参考《处理空白和换行的方式差异》
XML DOM 浏览器差异
XMLDOM节点操作
XML DOM 获取节点值:
nodeValue 属性用于获取节点的文本值。
getAttribute() 方法返回属性的值。
获取元素的值
在 DOM 中,每种成分都是节点。元素节点没有文本值。元素节点的文本存储在子节点中。该节点称为文本节点。获取元素文本的方法,就是获取这个子节点(文本节点)的值。
获取属性的值
在 DOM 中,属性也是节点。与元素节点不同,属性节点拥有文本值。获取属性的值的方法,就是获取它的文本值。可以通过使用 getAttribute() 方法或属性节点的 nodeValue 属性来完成这个任务。
获取属性节点 - getAttributeNode()
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title")[0].getAttributeNode("lang"); txt=x.nodeValue;
XMLDOM改变节点值:
nodeValue 属性用于改变节点值。
setAttribute() 方法用于改变属性的值。
改变元素的值
在 DOM 中,每种成分都是节点。元素节点没有文本值。元素节点的文本存储在子节点中。该节点称为文本节点。改变元素文本的方法,就是改变这个子节点(文本节点)的值。
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title")[0].childNodes[0]; x.nodeValue="Hello World";
改变属性的值
在 DOM 中,属性也是节点。与元素节点不同,属性节点拥有文本值。改变属性的值的方法,就是改变它的文本值。可以通过使用 setAttribute() 方法或属性节点的 nodeValue 属性来完成这个任务。
通过使用 setAttribute() 来改变属性
setAttribute() 方法设置已有属性的值,或创建新属性。
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName('book'); x[0].setAttribute("category","child");
注释:如果属性节点不存在,则创建一个新属性(拥有指定的名称和值)。
通过使用 nodeValue 改变属性
nodeValue 属性可用于更改属性节点的值:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("book")[0] y=x.getAttributeNode("category"); y.nodeValue="child";
XML DOM 删除节点
removeChild() 方法删除指定节点。
removeAttribute() 方法删除指定属性。
删除元素节点
removeChild() 方法删除指定的节点。当一个节点被删除时,其所有子节点也会被删除。
下面的代码片段将从载入的 xml 中删除第一个 <book> 元素:
xmlDoc=loadXMLDoc("books.xml"); y=xmlDoc.getElementsByTagName("book")[0]; xmlDoc.documentElement.removeChild(y);
例子解释:
- 通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中
- 把变量 y 设置为要删除的元素节点
- 通过使用 removeChild() 方法从父节点删除元素节点
删除自身 - 删除当前的节点
removeChild() 方法是唯一可以删除指定节点的方法。当你已定位需要删除的节点时,就可以通过使用 parentNode 属性和 removeChild() 方法来删除此节点:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("book")[0]; x.parentNode.removeChild(x);
根据名称删除属性节点
removeAttribute(name) 方法用于根据名称删除属性节点。下面的代码片段删除第一个 <book> 元素中的 "category" 属性:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("book"); x[0].removeAttribute("category");
根据对象删除属性节点
removeAttributeNode(node) 方法通过使用 Node 对象作为参数,来删除属性节点。下面的代码片段删除所有 <book> 元素的所有属性:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("book"); for (i=0;i<x.length;i++) { while (x[i].attributes.length>0) { attnode=x[i].attributes[0]; old_att=x[i].removeAttributeNode(attnode); } }
XML DOM 替换节点
replaceChild() 方法替换指定节点。
nodeValue 属性替换文本节点中的文本。
替换元素节点
replaceChild() 方法用于替换节点。
下面的代码片段替换第一个 <book> 元素:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.documentElement; //创建一个 book 元素、一个 title 元素,以及一个 text 节点 newNode=xmlDoc.createElement("book"); newTitle=xmlDoc.createElement("title"); newText=xmlDoc.createTextNode("Hello World"); //向 title 节点添加文本节点 newTitle.appendChild(newText); //向 book 节点添加 title 节点 newNode.appendChild(newTitle); y=xmlDoc.getElementsByTagName("book")[0]; //用这个新节点替换第一个 book 节点 x.replaceChild(newNode,y);
替换文本节点中的数据
replaceData() 方法用于替换文本节点中的数据。
replaceData() 方法有三个参数:
- offset - 在何处开始替换字符。Offset 值以 0 开始。
- length - 要替换多少字符
- string - 要插入的字符串
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title")[0].childNodes[0]; x.replaceData(0,8,"hello");
使用 nodeValue 属性
用 nodeValue 属性来替换文本节点中数据会更加容易。
XML DOM 创建节点
创建新的元素节点
createElement() 方法创建新的元素节点:
创建新的属性节点
createAttribute() 用于创建新的属性节点:
通过使用 setAttribute() 来创建属性
由于 setAttribute() 可以在属性不存在的情况下创建新的属性,我们可以使用这个方法来创建新属性。
创建文本节点
createTextNode() 方法创建新的文本节点:
创建一个 CDATA Section 节点
createCDATASection() 方法创建一个新的 CDATA section 节点。
xmlDoc=loadXMLDoc("books.xml"); newCDATA=xmlDoc.createCDATASection("Special Offer & Book Sale"); x=xmlDoc.getElementsByTagName("book")[0]; x.appendChild(newCDATA);
创建注释节点
createComment() 方法创建一个新的注释节点。
XML DOM 添加节点
添加节点 - appendChild()
appendChild() 方法向已存在的节点添加子节点。新节点会添加(追加)到任何已存在的子节点之后。
注释:如果节点的位置很重要,请使用 insertBefore() 方法。
下面的代码片段创建一个元素(<edition>),并把它添加到第一个 <book> 元素最后一个子节点后面:
xmlDoc=loadXMLDoc("books.xml"); newel=xmlDoc.createElement("edition"); x=xmlDoc.getElementsByTagName("book")[0]; x.appendChild(newel);
插入节点 - insertBefore()
insertBefore() 方法用于在指定的子节点之前插入节点。在被添加的节点的位置很重要时,此方法很有用。
xmlDoc=loadXMLDoc("books.xml"); newNode=xmlDoc.createElement("book"); x=xmlDoc.documentElement; y=xmlDoc.getElementsByTagName("book")[3]; x.insertBefore(newNode,y);
例子解释:
- 通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中
- 创建一个新的元素节点 <book>
- 把这个节点插到最后一个 <book> 元素节点之前
如果 insertBefore() 的第二个参数是 null,新节点将添加到最后一个已有的子节点之后。x.insertBefore(newNode,null) 和 x.appendChild(newNode) 都可以向 x 追加一个新的子节点。
添加新属性
如果属性不存在,则 setAttribute() 可创建一个新的属性:
向文本节点添加文本 - insertData()
insertData() 方法将数据插入已有的文本节点中。
insertData() 方法有两个参数:
- offset - 在何处开始插入字符(以 0 开始)
- string - 要插入的字符串
下面的代码片段将把 "Easy" 添加到已加载的 XML 的第一个 <title> 元素的文本节点:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title")[0].childNodes[0]; x.insertData(0,"Hello ");
XML DOM 克隆节点
复制节点
cloneNode() 方法创建指定节点的副本。cloneNode() 方法有一个参数(true 或 false)。该参数指示被复制的节点是否包括原节点的所有属性和子节点。
下面的代码片段拷贝第一个 <book> 节点,并把它追加到文档的根节点:
xmlDoc=loadXMLDoc("books.xml"); oldNode=xmlDoc.getElementsByTagName('book')[0]; newNode=oldNode.cloneNode(true); xmlDoc.documentElement.appendChild(newNode); //Output all titles y=xmlDoc.getElementsByTagName("title"); for (i=0;i<y.length;i++) { document.write(y[i].childNodes[0].nodeValue); document.write("<br />"); }