XML 文档对象模型定义访问和操作XML文档的标准方法。
DOM 将 XML 文档作为一个树形结构,而树叶被定义为节点。
XML DOM 是:
用于 XML 的标准对象模型
用于 XML 的标准编程接口
中立于平台和语言
W3C 的标准
XML DOM 定义了所有 XML 元素的对象和属性,以及访问它们的方法(接口)。
换句话说:
XML DOM 是用于获取、更改、添加或删除 XML 元素的标准。
XML DOM 节点
XML 文档中的每个成分都是一个节点。
根据 DOM,XML 文档中的每个成分都是一个节点。
DOM 是这样规定的:
整个文档是一个文档节点
每个 XML 标签是一个元素节点
包含在 XML 元素中的文本是文本节点
每一个 XML 属性是一个属性节点
注释属于注释节点
请看下面的 XML 文件 (books.xml):
<?xml version="1.0" encoding="ISO-8859-1"?> <bookstore> <book category="children"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="cooking"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="web"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> <book category="web"> <title lang="en">XQuery Kick Start</title> <author>James McGovern</author> <author>Per Bothner</author> <author>Kurt Cagle</author> <author>James Linn</author> <author>Vaidyanathan Nagarajan</author> <year>2003</year> <price>49.99</price> </book> </bookstore>
在上面的 XML 中,根节点是
根节点
第一个
在 DOM 处理中一个普遍的错误是,认为元素节点包含文本。
不过,元素节点的文本是存储在文本节点中的。
在这个例子中:
"2005" 不是
XML DOM 节点树
XML DOM 把 XML DOM 文档视为一棵节点树 (node-tree)。
树中的所有节点彼此之间都有关系。
XML DOM 把 XML 文档视为一种树结构。这种树结构被称为节点树。
可通过这棵树访问所有节点。可以修改或删除它们的内容,也可以创建新的元素。
这颗节点树展示了节点的集合,以及它们之间的联系。这棵树从根节点开始,然后在树的最低层级向文本节点长出枝条:
上面的图片表示 XML 文件 books.xml。
节点树中的节点彼此之间都有等级关系。
父、子和同级节点用于描述这种关系。父节点拥有子节点,位于相同层级上的子节点称为同级节点(兄弟或姐妹)。
在节点树中,顶端的节点成为根节点
根节点之外的每个节点都有一个父节点
节点可以有任何数量的子节点
叶子是没有子节点的节点
同级节点是拥有相同父节点的节点
下面的图片展示出节点树的一个部分,以及节点间的关系:
因为 XML 数据是按照树的形式进行构造的,所以可以在不了解树的确切结构且不了解其中包含的数据类型的情况下,对其进行遍历。
您将在本教程稍后的章节学习更多有关遍历节点树的知识。
注释:父节点:Parent Node,子节点:Children Node,同级节点:Sibling Node。
请看下面的 XML 片段:
<bookstore> <book category="CHILDREN"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> </bookstore>
在上面的 XML 中,
此外,
解析 XML DOM
所有现代浏览器都内建了用于读取和操作 XML 的 XML 解析器。
解析器把 XML 读入内存,并把它转换为可被 JavaScript 访问的 XML DOM 对象。
微软的 XML 解析器与其他浏览器中的解析器是有差异的。微软的解析器支持对 XML 文件和 XML 字符串(文本)的加载,而其他浏览器使用单独的解析器。不过,所有的解析器都含有遍历 XML 树、访问、插入及删除节点的函数。
在本教程中,我们将为您讲解如何创建可在 IE 及其他浏览器中运行的脚本。
微软的 XML 解析器内建于 Internet Explorer 5 及更高版本中。
下面的 JavaScript 片段把 XML 文档 ("books.xml") 载入了解析器:
xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async="false"; xmlDoc.load("books.xml");
第一行创建空的微软 XML 文档对象
第二行关闭异步加载,这样可确保在文档完整加载之前,解析器不会继续执行脚本
第三行告知解析器加载名为 "books.xml" 的文档
下面的 JavaScript 片段把名为 txt 的字符串载入解析器中:
xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async="false"; xmlDoc.loadXML(txt);
注释:loadXML() 方法用于加载字符串(文本),而load() 用于加载文件。
下面的 JavaScript 片段把 XML 文档 ("books.xml") 载入了解析器:
xmlDoc=document.implementation.createDocument("","",null); xmlDoc.async="false"; xmlDoc.load("books.xml");
第一行创建空的 XML 文档对象
第二行关闭异步加载,这样可确保在文档完整加载之前,解析器不会继续执行脚本
第三行告知解析器加载名为 "books.xml" 的文档
下面的 JavaScript 片段把名为 txt 的字符串载入解析器中:
parser=new DOMParser(); xmlDoc=parser.parseFromString(txt,"text/xml");
第一行创建一个空的 XML 文档对象
第二行告知解析器加载名为 txt 的字符串
注释:Internet Explorer 使用loadXML() 方法来解析 XML 字符串,而其他浏览器使用 DOMParser 对象。
下面的例子把 XML 文档 ("books.xml") 载入 XML 解析器:
<html> <body> <script type="text/javascript"> try //Internet Explorer { xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); } catch(e) { try //Firefox, Mozilla, Opera, etc. { xmlDoc=document.implementation.createDocument("","",null); } catch(e) {alert(e.message)} } try { xmlDoc.async=false; xmlDoc.load("books.xml"); document.write("xmlDoc is loaded, ready for use"); } catch(e) {alert(e.message)} </script> </body> </html>
出于安全方面的原因,现代的浏览器不允许跨域的访问。
这意味着,网页以及它试图加载的 XML 文件,都必须位于相同的服务器上。
W3School 的实例所打开的 XML 文件位于 W3School 的域上。
假如你打算在自己的网页上使用上面的例子,则必须把 XML 文件放到自己的服务器上。否则,xmlDoc.load() 将产生错误 "Access is denied"。
下面的代码加载并解析了一个 XML 字符串:
<html> <body> <script type="text/javascript"> text="<bookstore>" text=text+"<book>"; text=text+"<title>Harry Potter</title>"; text=text+"<author>J K. Rowling</author>"; text=text+"<year>2005</year>"; text=text+"</book>"; text=text+"</bookstore>"; try //Internet Explorer { xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async="false"; xmlDoc.loadXML(text); } catch(e) { try //Firefox, Mozilla, Opera, etc. { parser=new DOMParser(); xmlDoc=parser.parseFromString(text,"text/xml"); } catch(e) {alert(e.message)} } document.write("xmlDoc is loaded, ready for use"); </script> </body> </html>
XML DOM 加载函数
XML DOM 含有遍历 XML 树以及访问、插入、删除节点的方法(函数)。
然后,在访问并处理 XML 文档之前,必须把它载入 XML DOM 对象。
上一节演示了如何加载 XML 文档。为了避免因加载文档而重复编写代码,可以把代码存储在一个单独的 JavaScript 文件中:
function loadXMLDoc(dname) { try //Internet Explorer { xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); } catch(e) { try //Firefox, Mozilla, Opera, etc. { xmlDoc=document.implementation.createDocument("","",null); } catch(e) {alert(e.message)} } try { xmlDoc.async=false; xmlDoc.load(dname); return(xmlDoc); } catch(e) {alert(e.message)} return(null); }
上面的函数存储在名为 "loadxmldoc.js" 的文件中。
下面的例子在其 部分有一个指向 "loadxmldoc.js" 的链接,并使用 loadXMLDoc() 函数加载 XML 文档 ("books.xml"):
<html> <head><script type="text/javascript" src="loadxmldoc.js"></script> </head> <body> <script type="text/javascript"> xmlDoc=loadXMLDoc("books.xml"); document.write("xmlDoc is loaded, ready for use"); </script> </body> </html>
XML DOM - 属性和方法
DOM 把 XML 模拟为一系列节点接口。可通过 JavaScript 或其他编程语言来访问节点。在本教程中,我们使用 JavaScript。
对 DOM 的编程接口是通过一套标准的属性和方法来定义的。
属性经常按照“某事物是什么”的方式来使用(例如节点名是 "book")。
方法经常按照“对某事物做什么”的方式来使用(例如删除 "book" 节点)。
一些典型的 DOM 属性:
x.nodeName - x 的名称
x.nodeValue - x 的值
x.parentNode - x 的父节点
x.childNodes - x 的子节点
x.attributes - x 的属性节点
注释:在上面的列表中,x 是一个节点对象。
x.getElementsByTagName(name) - 获取带有指定标签名称的所有元素
x.appendChild(node) - 向 x 插入子节点
x.removeChild(node) - 从 x 删除子节点
注释:在上面的列表中,x 是一个节点对象。
从 books.xml 中的
txt=xmlDoc.getElementsByTagName("title")[0].childNodes[0].nodeValue
在此语句执行后,txt 保存的值是 "Everyday Italian"。
xmlDoc - 由解析器创建的 XML DOM
getElementsByTagName("title")[0] - 第一个
childNodes[0] -
nodeValue - 节点的值 (文本自身)
在上面的例子中,getElementsByTagName 是方法,而 childNodes 和 nodeValue 是属性。
下面的代码片段使用 loadXMLDoc 函数把 books.xml 载入 XML 解析器中,并显示第一个 book 的数据:
xmlDoc=loadXMLDoc("books.xml"); document.write(xmlDoc.getElementsByTagName("title") [0].childNodes[0].nodeValue); document.write("<br />"); document.write(xmlDoc.getElementsByTagName("author") [0].childNodes[0].nodeValue); document.write("<br />"); document.write(xmlDoc.getElementsByTagName("year") [0].childNodes[0].nodeValue);
输出:
Harry Potter J K. Rowling 2005
在上面的例子中,我们为每个文本节点使用 childNodes[0],即使每个元素只有一个文本节点。这是由于 getElementsByTagName() 方法总是会返回数组。
下面的代码加载并解析一个 XML 字符串:
下面的代码片段使用 loadXMLString 函数把 books.xml 载入 XML 解析器,并显示第一个 book 的数据:
text="<bookstore>" text=text+"<book>"; text=text+"<title>Harry Potter</title>"; text=text+"<author>J K. Rowling</author>"; text=text+"<year>2005</year>"; text=text+"</book>"; text=text+"</bookstore>"; xmlDoc=loadXMLString(text); document.write(xmlDoc.getElementsByTagName("title") [0].childNodes[0].nodeValue); document.write("<br />"); document.write(xmlDoc.getElementsByTagName("author") [0].childNodes[0].nodeValue); document.write("<br />"); document.write(xmlDoc.getElementsByTagName("year") [0].childNodes[0].nodeValue);
输出:
Harry Potter J K. Rowling 2005
您可以通过三种方法来访问节点:
通过使用 getElementsByTagName() 方法
通过循环(遍历)节点树
通过利用节点的关系在节点树中导航
getElementsByTagName() 返回拥有指定标签名的所有元素。
node.getElementsByTagName("tagname");
下面的例子返回 x 元素下的所有
x.getElementsByTagName("title");
请注意,上面的例子仅返回 x 节点下的
xmlDoc.getElementsByTagName("title");
在这里,xmlDoc 就是文档本身(文档节点)。
getElementsByTagName() 方法返回节点列表 (node list)。节点列表是节点的数组。
下面的代码通过使用 loadXMLDoc() 把 "books.xml"
载入 xmlDoc 中,然后在变量 x 中存储
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title");
可通过下标访问 x 中的
y=x[2];
注释:下标以 0 起始。
在本教程中稍后的章节,您将学到更多有关 Node List 的知识。
length 属性定义节点列表的长度(即节点的数目)。
您能够通过使用 length 属性来循环一个节点列表:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title"); for (i=0;i"); }
使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc
取得所有
输出每个
XML 文档的 documentElement 属性是根节点。
节点的 nodeName 属性是节点的名称。
节点的 nodeType 属性是节点的类型。
您将在本教程的下一节中学习更多有关节点属性的知识。
下面的代码循环根节点的子节点,同时也是元素节点:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.documentElement.childNodes; for (i=0;i<x.length;i++) { if (x[i].nodeType==1) {//Process only element nodes (type 1) document.write(x[i].nodeName); document.write("<br />"); } }
通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中
获得根元素的子节点
检查每个子节点的节点类型。如果节点类型是 "1",则是元素节点
如果是元素节点,则输出节点的名称
下面的代码通过利用节点的关系在节点树中进行导航:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("book")[0].childNodes; y=xmlDoc.getElementsByTagName("book")[0].firstChild; for (i=0;i<x.length;i++) { if (y.nodeType==1) {//Process only element nodes (type 1) document.write(y.nodeName + "<br />"); } y=y.nextSibling; }
通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中
获得第一个 book 元素的子节点
把 "y" 变量设置为第一个 book 元素的第一个子节点
检查每个子节点的节点类型,如果节点类型是 "1",则是元素节点
如果是元素节点,则输出该节点的名称
把 "y" 变量设置为下一个同级节点,并再次运行循环
在 XML 文档对象模型 (DOM) 中,每个节点都是一个对象。
对象拥有方法(功能)和属性(关于对象的信息),并可通过 JavaScript 进行访问和操作。
三个重要的 XML DOM 节点属性是:
nodeName
nodeValue
nodeType
nodeName 属性规定节点的名称。
nodeName 是只读的
元素节点的 nodeName 与标签名相同
属性节点的 nodeName 是属性的名称
文本节点的 nodeName 永远是 #text
文档节点的 nodeName 永远是 #document
nodeValue 属性规定节点的值。
元素节点的 nodeValue 是 undefined
文本节点的 nodeValue 是文本自身
属性节点的 nodeValue 是属性的值
下面的代码检索第一个
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title")[0].childNodes[0]; txt=x.nodeValue;
结果:txt = "Everyday Italian"
通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中
获取第一个
把 txt 变量设置为文本节点的值
下面的代码更改第一个
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title")[0].childNodes[0]; x.nodeValue="Easy Cooking";
通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中
获取第一个
把文本节点的值更改为 "Easy Cooking"
nodeType 属性规定节点的类型。
nodeType 是只读的。
元素类型 | 节点类型 |
---|---|
元素 | 1 |
属性 | 2 |
文本 | 3 |
注释 | 8 |
文档 | 9 |
当使用诸如 childNodes 或 getElementsByTagName() 属性或方法时,会返回 NodeList 对象。
NodeList 对象表示节点的列表,以 XML 中的相同顺序。
使用从 0 开始的下标来访问节点列表中的节点。
下面的图像表示 "books.xml" 中
下面的代码片段通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中,并返回 "books.xml" 中 title 元素的一个节点列表:
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("title");
以上语句执行之后,x 成为一个 NodeList 对象。
下面的代码片段从节点列表 x 中的第一个
txt=x[0].childNodes[0].nodeValue;
在以上语句执行之后,txt = "Everyday Italian"。
NodeList 对象会保持自身的更新。如果删除或添加了元素,列表会自动更新。
节点列表的 length 属性是列表中节点的数量。
下面的代码片段通过使用 loadXMLDoc() 把 "books.xml"
载入 xmlDoc,并返回 "books.xml" 中
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName('title').length;
在上面的语句执行之后,x = 4。
节点列表的长度可用于循环列表中所有的元素。
下面的代码片段使用 length 属性来遍历
xmlDoc=loadXMLDoc("books.xml"); //the x variable will hold a node list x=xmlDoc.getElementsByTagName('title'); for (i=0;i<x.length;i++) { document.write(x[i].childNodes[0].nodeValue); document.write("<br />"); }
输出:
Harry Potter Everyday Italian XQuery Kick Start Learning XML
通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc
设置保存所有 title 元素的节点列表的 x 变量
从所有
元素节点的 attributes 属性返回属性节点的列表。
这被称为 Named Node Map,除了方法和属性上的一些差别以外,它与节点列表相似。
属性列表会保持自身的更新。如果删除或添加属性,这个列表会自动更新。
下面的代码片段通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中,并从 "books.xml"
中的第一个
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);
输出:
children 1
通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中
把 x 变量设置为第一个
从 "category" 属性输出其值
输出属性列表的长度
遍历 (Traverse) 意味着在节点树中进行循环或移动。
下面的例子使用 XML 文件 books.xml。
函数 loadXMLString(),位于外部 JavaScript 中,用于加载 XML 文件。
遍历一棵节点树
循环
您经常需要循环 XML 文档,比如:当你需要提取每个元素的值时。
这个过程叫作“遍历节点树”。
下面的例子循环
<html> <head> <script type="text/javascript" src="loadxmlstring.js"></script> </head> <body> <script type="text/javascript"> text="<book>"; text=text+"<title>Harry Potter</title>"; text=text+"<author>J K. Rowling</author>"; text=text+"<year>2005</year>"; text=text+"</book>"; xmlDoc=loadXMLString(text); // documentElement always represents the root node x=xmlDoc.documentElement.childNodes; for (i=0;i<x.length;i++) { document.write(x[i].nodeName); document.write(": "); document.write(x[i].childNodes[0].nodeValue); document.write("<br />"); } </script> </body> </html>
输出:
title: Harry Potter author: J K. Rowling year: 2005
loadXMLString() 把 XML 字符串载入 xmlDoc 中
获取根元素的子节点
输出每个子节点的名称,以及文本节点的节点值
通过节点间的关系访问节点树中的节点,通常称为定位节点 ("navigating nodes")。
在 XML DOM 中,节点的关系被定义为节点的属性:
parentNode
childNodes
firstChild
lastChild
nextSibling
previousSibling
下面的图像展示了 books.xml 中节点树的一个部分,并说明了节点之间的关系:
所有的节点都仅有一个父节点。下面的代码定位到
xmlDoc=loadXMLDoc("books.xml"); x=xmlDoc.getElementsByTagName("book")[0]; document.write(x.parentNode.nodeName);
通过使用 loadXMLDoc() 把 "books.xml" 载入到 xmlDoc 中
获取第一个
输出 "x" 的父节点的节点名
TIY
Firefox,以及其他一些浏览器,把空的空白或换行当作文本节点,而 IE 不会这么做。
这会在使用下列属性使产生一个问题:firstChild、lastChild、nextSibling、previousSibling。
为了避免定位到空的文本节点(元素节点之间的空格和换行符号),我们使用一个函数来检查节点的类型:
function get_nextSibling(n) { y=n.nextSibling; while (y.nodeType!=1) { y=y.nextSibling; } return y; }
有了上面的函数,我们就可以使用 get_nextSibling(node) 来代替 node.nextSibling 属性。
元素节点的类型是 1。如果同级节点不是元素节点,就移动到下一个节点,直到找到元素节点为止。通过这个办法,在 IE 和 Firefox 中,都可以得到相同的结果。
下面的代码显示第一个
<html> <head> <script type="text/javascript" src="loadxmldoc.js"> </script> <script type="text/javascript"> //check if the first node is an element node function get_firstChild(n) { y=n.firstChild; while (y.nodeType!=1) { y=y.nextSibling; } return y; } </script> </head> <body> <script type="text/javascript"> xmlDoc=loadXMLDoc("books.xml"); x=get_firstChild(xmlDoc.getElementsByTagName("book")[0]); document.write(x.nodeName); </script> </body> </html>
输出:
title
通过使用 loadXMLDoc() 把 "books.xml" 载入 xmlDoc 中
在第一个
输出第一个子节点(属于元素节点)的节点名
以上就是疯狂XML学习笔记(13)---------XML DOM的内容,更多相关内容请关注PHP中文网(www.php.cn)!