IE中的XML DOM
当微软在
IE 5.0
中第一次加入对
XML
支持时,他们只是在
MSXML ActiveX
库(最初是为了在
IE 4.0
中解析
Active Channels
的组件)中实现
XML
的功能。最初的版本并没有打算公开使用,然而随着开发人员逐渐了解这个组件并尝试使用时,微软才意识到这个库的重要性,很快就在
IE 4.01
中发布了
MSXML
完全升级版本。
MSXML
最初还只是
IE
的一个组件。直到
2001
年,微软发布了
MSXML 3.0
,这是一个通过其公司网站独立发布的产品。在
2001
年晚些时候,微软又发布了
MSXML 4.0
,并且将其更名为微软
XML
核心服务组件。
MSXML
从最初一个基本的、无校验功能的
XML
解析器,逐渐发展成一个功能强大的组件,能够校验
XML
文档,进行
XSL
转化,支持命名空间、
XML
的简单
API
(
SAX
),以及
W3C XPath
和
XML Schema
标准,并且每个新版本都在性能上有一定的提升。
为了在
JavaScript
中创建
ActiveX
对象,微软实现一个新的
ActiveXObject
类,该类用来实例化
ActiveX
对象。
ActiveXObject
类的构造函数包含一个字符串参数,该参数表示要创建的
ActiveX
对象的版本,在此指的就是
XML
文档的版本。第一个
XML DOM ActiveX
对象名为
Microsoft.XmlDom
,其创建方法如下所示:
var oXmlDom = new ActiveXObject("Microsoft.XmlDom");
这个新创建的
XML DOM
对象与其他
DOM
对象一样,可以用来遍历
DOM
树,操作
DOM
节点。
到本书截稿为止,
MSXML DOM
文档共有五个不同的版本,分别是:
q
Microsoft.XmlDom
;
q
MSXML2.DOMDocument
;
q
MSXML2.DOMDocument.3.0
;
q
MSXML2.DOMDocument.4.0
;
q
MSXML2.DOMDocument.5.0
。
MSXML
是基于
ActiveX
的实现,因此只能够在
Windows
平台上使用。在
Mac
平台上的
IE 5
是不提供
XML DOM
支持的。
因为存在五个不同版本,而你总是会使用最新版,所以使用一个函数来判断浏览器所使用的版本是相当有用的。这样就可以确保使用最新的
XML
支持,获取最佳的性能。下面的函数
createDocument()
将使你能够创建正确的
MSXML DOM
文档。
function createDocument() {
var aVersions = [ "MSXML2.DOMDocument.5.0",
"MSXML2.DOMDocument.4.0","MSXML2.DOMDocument.3.0",
"MSXML2.DOMDocument","Microsoft.XmlDom"
];
for (var i = 0; i < aVersions.length; i++) {
try {
var oXmlDom = new ActiveXObject(aVersions[i]);
return oXmlDom;
} catch (oError) {
//
不做任何处理
}
}
throw new Error("MSXML is not installed.");
}
该函数遍历存放
MSXML DOM
文档的版本号的
aVersions
数组,从最新版本
MSXML2.DOMDocument.5.0
开始尝试创建
DOM
文档。如果成功创建对象,那么返回该对象且退出
createDocument();
否则
try...catch
语句将捕获所抛出的异常,并继续下一次循环,尝试下一个版本。如果
MSXML DOM
文档创建失败,那么抛出异常,说明
MSXML
未安装。由于该函数不是一个类,所以用法与其他函数类似,都将返回一个值:
var oXmlDom = createDocument();
使用
createDocument()
函数将确保程序使用最新的
DOM
文档。当创建了
XML
文档后,下一步就是载入
XML
数据。
1.
在
IE
中载入
XML
数据
MSXML
支持两种载入
XML
的方法:
load()
和
loadXML()
。
Load()
方法从
Web
的指定位置载入一个
XML
文件。与
XMLHttp
一样,
load()
方法可以以同步或异步两种模式载入数据。默认情况下,
load()
方法
采用异步模式;如果要采用同步模式,那么必须将
MSXML
对象的
async
属性设置为
false
,代码如下:
oXmlDom.async = false;
当采用异步模式时,
MSXML
对象公开了
readyState
属性,该属性和
XMLHttp
的
readyState
属性一样,包含五种状态。
此外,
DOM
文档支持
onreadystatechange
事件处理函数,可以监控
readyState
属性。因为异步模式是默认选项,因此将
async
属性设置为
true
是可选的:
oXmlDom.async = true;
oXmlDom.onreadystatechange = function () {
if (oXmlDom.readyState == 4) {
//
当
document
完全载入后,进行某些操作
}
};
oXmlDom.load("myxml.xml");
本示例中,将把虚构的、名为
myxml.xml
的
XML
文档载入到
XML DOM
文档中。当
readyState
值为
4
时,说明文档已经完全载入,则执行
if
语句中的代码。
第二种载入
XML
数据的方法是
loadXML()
,该方法与
load()
方法的主要区别在于从字符串载入
XML
,而不是根据指定的文件名载入
XML
。该字符串必须包含正确格式的
XML
,如下所示:
var sXml = "<root><person><name>Jeremy McPeak</name></person></root>";
oXmlDom.loadXML(sXml);
在此,
oXmlDom
文档将载入
sXml
变量中包含的
XML
数据。
loadXML()
方法不需要像
load()
方法那样检查
readyState
属性,也不需要设置
async
属性,因为该方法并不涉及服务器请求。
2.
在
IE
中遍历
XML DOM
文档
XML DOM
文档的遍历与
HTML DOM
的遍历非常类似,因为它们都是节点层次的结构。节点树的最顶部是
documentElement
属性,包含文档的根元素。使用表
4-1
中所列出的属性,可以访问文档中任何元素或属性。
表
4-1 XML DOM
属性
属
性
|
描
述
|
attributes
|
包含当前节点属性的数组
|
childNodes
|
包含子节点数组
|
firstChild
|
指向当前节点的第一个子节点
|
lastChild
|
指向当前节点的最后一个子节点
|
nextSibling
|
返回当前节点的下一个邻居节点
|
nodeName
|
返回当前节点的名字
|
nodeType
|
指定当前节点的
XML DOM
节点类型
|
nodeValue
|
包含当前节点的文本
|
ownerDocument
|
返回文档的根元素
|
parentNode
|
指向当前节点的父节点
|
previousSibling
|
返回当前节点的前一个邻居节点
|
text
|
返回当前节点的内容或当前节点及其子节点的文本(只有
IE
才支持的属性)
|
xml
|
以字符串返回当前节点及其子节点的
XML
(只有
IE
才支持的属性)
|
遍历
DOM
文档并获取数据,是一个很直观的过程。让我们看看下面的
XML
文档:
<?xml version="1.0" encoding="utf-8"?>
<books>
<book isbn="0471777781">Professional Ajax</book>
<book isbn="0764579088">Professional JavaScript for Web Developers</book>
<book isbn="0764557599">Professional C#</book>
<book isbn="1861002025">Professional Visual Basic 6 Databases</book>
</books>
这是一个简单的
XML
文档,包含一个根元素
<books/>
以及四个子元素
<book/>
。以该文档为例,我们可以研究
DOM
的细节。
DOM
树是基于节点之间的关系构造的。一个节点可能包含其他节点或者子节点。另一个节点可能与其他节点拥有相同的父节点,我们称之为邻居节点。
如果要获取文档中第一个
<book/>
元素,那么只需简单通过访问
firstChild
属性就可以达到目的:
var oRoot = oXmlDom.documentElement;
var oFirstBook = oRoot.firstChild;
将
documentElement
赋给变量
oRoot
,可以节省程序空间和输入的内容,尽管这并不是必需的。使用
firstChild
属性可以引用根元素
<books/>
的第一个子元素
<books/>
的引用,并将其赋值给变量
oFirstBook
。
使用
childNodes
集合也可以达到相同的目的:
var oFirstBook2 = oRoot.childNodes[0];
选择
childNodes
集合中的第一项将返回根节点的第一个子节点。因为
childNodes
是
JavaScript
中的
NodeList
类型,所以使用
length
属性可以得到子节点的数量,如下:
var iChildren = oRoot.childNodes.length;
本示例中,因为文档元素有四个子节点,所以
iChildren
值为
4
。
正如前面所述,节点可以有子节点,也就意味着它可以有父节点。通过
parentNode
属性可以选择当前节点的父节点:
var oParent = oFirstBook.parentNode;
在本小节前面已经提到变量
oFirstBook
,不过很快,它现在已经是文档中第一个
<book/>
元素,所以其
parentNode
属性就是指
DOM
的
documentElement
属性,也就是
<books/>
元素。
如果当前节点是
book
元素,那么如何选择另一个
book
元素呢?因为
<book/>
元素有共同的父节点,所以它们互为邻居关系。通过
nextSibling
和
previousSibling
属性可以选择当前节点的临近节点。
nextSibling
属性指向下一个邻居,而
previousSibling
属性
指向前一个邻居:
var oSecondBook = oFirstBook.nextSibling;
oFirstBook2 = oSecondBook.previousSibling;
这段代码引用第二个
<book/>
元素,并将其赋值给
oSecondBook
。通过
oSecondBook
邻居节点对变量
oFirstBook2
重新赋值,
oFirstBook2
的值不变。如果节点没有下一个邻居节点,那么
nextSibling
为
null
。对于
previousSibling
也是同样的,
如果当前节点没有前一个邻居节点,那么
previousSibling
也为
null
。
现在我们知道了如何遍历文档结构,接下来要了解的是如何从树的节点获取数据。例如,使用
text
属性可以得到包含第三个
<book/>
元素的文本,代码如下:
var sText = oRoot.childNodes[2].text;
text
属性(微软特有的属性)可以得到该节点包含的所有文本节点,该属性相当有用。如果没有
text
属性,访问文本节点必须:
var sText = oRoot.childNodes[2].firstChild.nodeValue;
这段代码与前面使用
text
属性的代码一样得到同样的结果。类似上一个例子,使用
childNodes
集合引用第三个
<book/>
元素,而使用
firstChild
指向
<book/>
元素的文本节点,因为文本节点在
DOM
中仍是一个节点。使用
nodeValue
属性获取当前节点的值,就可以获取文本。
这两个示例所产生的结果是相同的,然而使用
text
属性和使用文本节点的
nodeValue
属性之间存在一个主要的区别。
text
属性将得到包含当前元素及其子节点的所有文本节点的值,而
nodeValue
属性只能得到当前节点的值。它虽然是个有用的属性,但可能会返回比预期值更多的内容。例如,假设我们将
XML
文档修改成:
<?xml version="1.0" encoding="utf-8"?>
<books>
<book isbn="0471777781">
<title>Professional Ajax</title>
<author>Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett</author>
</book>
<book isbn="0764579088">Professional JavaScript for Web Developers</book>
<book isbn="0764557599">Professional C#</book>
<book isbn="1861002025">Professional Visual Basic 6 Databases</book>
</books>
新的
XML
文档在第一个
<book/>
元素中添加了两个新的子节点:
<title/>
元素(书名),
<author/>
元素(作者)。我们再一次使用
text
属性
:
alert(oFirstChild.text);
代码中没有其他新的内容,我们可以看看图
4-1
中所显示的结果。
图
4-1
请注意,这时我们将获得
<title/>
和
<author/>
元素的文本节点,并将其连接在一起。这就是
text
与
nodeValue
的不同之处。
nodeValue
属性只能得到当前节点的值,而
text
属性则将得到包含当前节点及其子节点的所有文本节点。
MSXML
还提供其他一些获取特定节点或数值的方法,最常用的方法是
getAttribute()
和
getElementsByTagName()
。
getAttribute()
方法将接受一个包含属性名称的字符串型参数,并返回属性值。如果指定的属性不存在,那么返回的值为
null
。我们还将使用本小节前面提到的那个
XML
文档,请看下列代码:
var sAttribute = oFirstChild.getAttribute("isbn");
alert(sAttribute);
这段代码获取第一个
<book/>
元素的
isbn
属性值,并将其赋值给变量
sAttribute
,
然后使用
Alert()
方法显示该值。
getElementsByTagName()
方法根据其参数所指定的名字,返回子元素的
NodeList
。该方法只搜索给定的节点中的元素,所以返回的
NodeList
不包含任何外部元素。例如:
var cBooks = oRoot.getElementsByTagName("book");
alert(cBooks.length);
这段代码获取文档中所有的
<book/>
元素,并将返回的
NodeList
赋值给变量
cBooks
。对于前面那个
XML
文档例子而言,警告框将显示找到的四个
<book/>
元素。如果要获取所有子节点,那么必须用“
*
”作为
getElementsByTagName()
方法的参数,其代码如下所示:
var cElements = oRoot.getElementsByTagName("*");
因为前面的
XML
文档例子中只包含
<book/>
元素,所以这段代码的结果与上一个示例相同。
3.
在
IE
中获取
XML
数据
要获取
XML
数据只需使用一个属性,即
xml
。该属性将对当前节点的
XML
数据进行序列化。
序列化(serialization
)
是将对象转换成简单的可存储或可传输格式的过程。
xml
属性将
XML
转换成字符串形式,包括完整的标签名称、属性和文本:
var sXml = oRoot.xml;
alert(sXml);
这段代码从文档元素开始序列化
XML
数据,并将其作为参数传递给
alert()
方法。下面就是部分已序列化的
XML
:
<books><book isbn="0471777781">Professional Ajax</book></books>
已序列化的数据可以载入到另一个
XML DOM
对象,发送到服务器,或者传给另一个页面。通过
xml
属性返回的已序列化
XML
数据,取决于当前节点。如果是在
documentElement
节点使用
xml
属性
,那么将返回整个文档的
XML
数据;如果只是在
<book/>
元素上使用它,那么将返回该
<book/>
元素所包含的
XML
数据。
xml
属性是只读属性。如果希望往文档中添加元素,那么必须使用
DOM
方法来实现。
4.
在
IE
中操作
DOM
现在为止,我们已经学习如何遍历
DOM
,从
DOM
中提取信息,将
XML
转换成字符串格式。接下来学习的是如何在
DOM
中添加、删除和替换节点。
l
创建节点
使用
DOM
方法可以创建多种不同的节点。第一种就是用
createElement()
方法创建的元素。向该方法传入一个参数,指明要创建的元素标签名称,并返回一个对
XMLDOMElement
的引用:
var oNewBook = oXmlDom.createElement("book");
oXmlDom.documentElement.appendChild(oNewBook);
这段代码创建一个新的
<book/>
元素,并通过
appendChild()
方法把它添加到
documentElement
中。
appendChild()
方法添加由其参数指定的新元素,并且将其作为最后一个子节点。但在该例子中,添加到该文档中的是一个空的
<book/>
元素,因而还需要为该元素添加一些文本:
var oNewBook = oXmlDom.createElement("book");
var oNewBookText = oXmlDom.createTextNode("Professional .NET 2.0 Generics");
oNewBook.appendChild(oNewBookText);
oXmlDom.documentElement.appendChild(oNewBook);
这段代码通过
createTextNode()
方法创建一个文本节点,并通过
appendChild()
方法把它添加到新创建的
<book/>
元素中。
createTextNode()
方法只有一个字符串参数,用来指定文本节点的值。
现在已经通过程序创建了新的
<book/>
元素,为其提供了一个文本节点,并将它添加到文档中。对于这个新元素而言,还需要像其他邻居节点一样,为其设置
isbn
属性。这很简单,只要通过
setAttribute()
方法就可以创建属性,该方法适用于所有元素节点。
var oNewBook = oXmlDom.createElement("book");
var oNewBookText = oXmlDom.createTextNode("Professional .NET 2.0 Generics");
oNewBook.appendChild(oNewBookText);
oNewBook.setAttribute("isbn","0764559885");
oXmlDom.documentElement.appendChild(oNewBook);
上面这段代码中,新添加的一行是用来创建
isbn
属性的,并将其值赋为
0764559885
。
setAttribute()
方法有两个参数:第一个参数是属性名,第二个参数则是赋给该属性的值。对于向元素添加属性,
IE
还提供其他一些方法,不过它们实际上并不比
setAttribute()
更好用,而且还需要更多的编码。
l
删除、替换和插入节点
如果能够往文档中添加节点,那么同样意味着可以删除节点。
removeChild()
方法正是用来实现该功能的。该方法包含一个参数:要删除的节点。例如,要从文档中删除第一个
<book/>
元素,则可以使用以下代码:
var oRemovedChild = oRoot.removeChild(oRoot.firstChild);
removeChild()
方法返回被删除的子节点,因而
oRemoveChild
变量将指向已删除的
<book/>
元素。当拥有对旧节点的引用时,就可以将其放置在文档的任何地方。
如果想用
oRemovedChild
指向的元素来替换第三个
<book/>
元素,那么可以通过
replaceChild()
方法来实现,该方法返回被替换的节点:
var oReplacedChild = oRoot.replaceChild(oRemovedChild, oRoot.childNodes[2]);
replaceChild()
方法接受两个参数:新添加的节点和将被替换的节点。在这段代码中,将用
oRemovedChild
变量引用的节点替换第三个
<book/>
元素,而被替换节点的引用将存在
oReplacedChild
变量中。
由于
oReplaceChild
变量是被替换节点的引用,因而可以容易地将其插入到文档中。使用
appendChild()
方法可以该其添加到子节点列表的最后,也可以使用
insertBefore()
方法将该节点插入到某个节点之前:
oRoot.insertBefore(oReplacedChild, oRoot.lastChild);
这段代码将之前被替换的节点插入到最后一个
<book/>
元素的前面。
lastChild
属性的用法与
firstChild
选择第一个子节点
非常相似,通过该属性可以获取最后一个子节点。
insertBefore()
方法接受两个参数:要插入的节点和表示插入点的节点(插入点在该节点之前)。该方法也将返回插入节点的值,但上述例子中并不需要。
如你所见,
DOM
是一个相当强大的接口,通过它可以实现数据的获取、删除和添加等操作。
5.
在
IE
中处理错误
在
XML
数据的载入过程中,可能会由于不同的原因而抛出错误。例如,外部的
XML
文件找不到,或者
XML
的格式不正确。为了处理这些情况,
MSXML
提供了一个包含错误信息的
parseError
对象。对于每个由
MSXML
创建的
XML DOM
文档对象而言,该对象都是其所属的属性值之一。
我们可以通过
parseError
对象公开的与整数
0
进行比较的
errorCode
属性来检查错误。如果
errorCode
不等于
0
,则表示有错误发生。下面的例子故意设计出现一个错误。
var sXml = "<root><person><name>Jeremy McPeak</name></root>";
var oXmlDom = createDocument();
oXmlDom.loadXML(sXml);
if (oXmlDom.parseError.errorCode != 0) {
alert("An Error Occurred: " + oXmlDom.parseError.reason);
} else {
//
当
XML
载入成功后的操作
}
大家会注意到,在突出显示的代码行中,
<person>
元素是不完整的(没有相应的
</person>
标签)。由于要载入的
XML
的格式不正确,因此将产生一个错误。然后
errorCode
与
0
进行比较,如果不相等(在本例中就不相等),那么将显示发生错误的警告。要实现该功能,可以使用
parseError
对象的
reason
属性来获取错误出现的原因。
parseError
对象提供了以下属性,能够帮助你更好地了解错误:
q
errorCode:
错误代码(长整型);
q
filePos:
在文件中发生错误的位置(长整型);
q
line:
包含错误的代码行的行号(长整型);
q
linePos
:
在特定行中发生错误的位置(长整型);
q
reason:
错误的原因(字符串型);
q
srcText:
发生错误的代码行内容(字符串型);
q
url:
XML
文档的
URL
(字符串型)。
尽管这些属性提供了每种错误的信息,但是应该使用哪个属性,则取决于你的需要。
errorCode
属性可以是正数也可以是负数,只有当
errorCode
为
0
时才表示没有错误发生。
Firefox中的XML DOM
现在我们来看看
Firefox
中的
XML DOM
实现,
Firefox
的开发人员采用更为标准的方法,将其作为
JavaScript
实现的一部分。
Mozilla
确保所有基于
Gecko
的浏览器的所有平台都支持
XML DOM
。
Firefox
中创建一个
XML DOM
,需要调用
document.implementation
对象的
createDocument()
方法。该方法接受三个参数:第一个参数是包含文档所使用的命名空间
URI
的字符串;第二个参数是包含文档根元素名称的字符串;第三个参数是要创建的文档类型(也称为
doctype
)。如果要创建空的
DOM
文档,则代码如下所示:
var oXmlDom = document.implementation.createDocument("", "", null);
前两个参数是空字符串,第三个参数为
null
,这样可以确保生成一个彻底的空文档。事实上,现在
Firefox
中并不提供针对文档类型的
JavaScript
支持,所以第三个参数总是为
null
。如果要创建包含文档元素的
XML DOM
,那么可以在第二个参数中指定标签名称:
var oXmlDom = document.implementation.createDocument("", "books", null);
这段代码创建了一个
XML DOM
,其
documentElement
是
<books/>
。如果要创建包含指定命名空间的
DOM
,可以在第一个参数中指定命名空间
URI
:
var oXmlDom = document.implementation.createDocument("http://www.site1.com",
"books", null);
当在
createDocument()
方法中指定命名空间时,
Firefox
会自动附上前缀
a0
以表示
命名空间
URI
:
<a0:books xmlns:a0="http://www.site1.com" />
接着,你可以通过程序来填充
XML
文档,不过在一般情况下,还需要在空的
XML DOM
对象中载入现有的
XML
文档。
1.
在
Firefox
中载入
XML
数据
在
Firefox
中,将
XML
载入
XML DOM
的方法和微软采用的方法大致相同,只存在一个显著区别:
Firefox
只支持
load()
方法。因此,在这两种浏览器中载入外部
XML
数据的代码是相同的:
oXmlDom.load("books.xml");
与微软的
IE
一样,
Firefox
同样实现了
async
属性,该属性的行为也与其一致:将
async
设置为
false
,表示以同步模式载入文档;否则,以异步模式载入文档。
Firefox
的
XML DOM
实现和微软的
XML DOM
实现还存在另一个不同,即
Firefox
不支持
readyState
属性及
onreadystatechange
事件处理函数。在
Firefox
中,支持
load
事件和
onload
事件处理函数。在文档完全载入后将触发
load
事件:
oXmlDom.load("books.xml");
oXmlDom.onload = function () {
//
文档完全载入后的操作
};
正如前面所说,在
Firefox
的
XML DOM
实现中,并没有
loadXML()
方法,不过通过
Firefox
中的
DOMParser
类可以模拟
loadXML()
的行为。该类有一个名为
parseFromString()
的方法,用来载入字符串并解析成文档:
var sXml = "<root><person><name>Jeremy McPeak</name></person></root>";
var oParser = new DOMParser();
var oXmlDom = oParser.parseFromString(sXml,"text/xml");
在这段代码中,创建了一个
XML
字符串,并作为参数传递给
DOMParser
的
parseFromString()
方法。
parseFromString()
方法的两个参数分别是
XML
字符串和数据的内容类型(一般设置为
text/xml
)
。
parseFromString()
方法返回
XML DOM
对象,因此这里得到的
oXmlDom
与第一个例子相同。
2.
在
Firefox
中获取
XML
数据
尽管存在这样那样的不同,但
IE
和
Firefox
中用于获取文档中
XML
数据的大多数属性和方法是一致的。正如在
IE
中,可以使用
documentElement
属性来获取文档的根元素,例如:
var oRoot = oXmlDom.documentElement;
Firefox
同样支持
W3C
标准属性,包括
childNodes
、
firstChild
、
lastChild
、
nextSibling
、
nodeName
、
nodeType
、
nodeValue
、
ownerDocument
、
parentNode
和
previousSibling
。不幸的是,对于微软专有的
text
和
xml
属性,
Firefox
并不支持,不过可以利用其他方法来模拟该属性的行为。
大家应该还记得,
text
属性返回了当前节点的内容,或者是当前节点及其子节点的内容。这不仅仅返回当前节点的文本,还有所有子节点的文本,因此要模拟该功能实现是十分容易的。下面这个简单的函数就能够完成该功能,该函数唯一的参数是一个节点:
function getText(oNode) {
var sText = "";
for (var i = 0; i < oNode.childNodes.length; i++) {
if (oNode.childNodes[i].hasChildNodes()) {
sText += getText(oNode.childNodes[i]);
} else {
sText += oNode.childNodes[i].nodeValue;
}
}
return sText;
}
在
getText()
函数中,
sText
变量用来保存获取的所有文本。接着对
oNode
的子节点使用
for
循环
进行遍历,检查每个子节点是否包含子节点。如果有子节点,那么就将其
childNode
传给
getText()
函数,并进行同样的处理;如果没有子节点,那么将当前节点的
nodeValue
加到字符串中(对文本节点而言,这只是文本字符串)。处理了所有子节点后,该函数返回变量
sText
。
IE
中的
xml
属性将存放对当前节点包含的所有
XML
进行序列化的结果。在
Firefox
中,提供了一个名为
XMLSerializer
对象来完成这一功能。该对象提供一个使用
JavaScript
可访问的
serializeToString()
方法,使用该方法可以对
XML
数据进行序列化。
function serializeXml(oNode) {
var oSerializer = new XMLSerializer();
return oSerializer.serializeToString(oNode);
}
serializeXml()
函数以
XML
节点作为参数,创建一个
XMLSerializer
对象,并将该节点传给
serializeToString()
方法。该方法将向调用者返回
XML
数据的字符串表示。
对于节点操作的DOM
方法,Firefox
与IE
大致相同。参见“在IE
中操作DOM
”小节。
3.
在
Firefox
中处理错误
Firefox
与
IE
的错误处理并不一样。当
IE
遇到错误时,它会填充
parseError
对象;而当
Firefox
遇到错误时,它会将包含错误信息的
XML
文档载入到
XML DOM
文档中。看下面的这个例子:
var sXml = "<root><person><name>Jeremy McPeak</name></root>";
var oParser = new DOMParser();
var oXmlDom = oParser.parseFromString(sXml,"text/xml");
if (oXmlDom.documentElement.tagName != "parsererror") {
//
没有错误发生,进行所需操作
} else {
alert("An Error Occurred");
}
在突出显示的代码行中,你会发现其中将产生一个错误:
XML
字符串格式不正确(因为
<person>
元素不完整,没有相应的
</person>
元素)。当载入错误的
XML
时,
XML DOM
对象将会载入一个
documentElement
为
<parsererror/>
的错误文档。我们可以通过检查
documentElement
的
tagName
属性来很容易地确定是否发生错误。如果
tagName
属性不是
parsererror
,就可以确定没有发生任何错误。
在本例中,可能会生成如下所示的错误文档:
<parsererror xmlns="http://www.mozilla.org/newlayout/xml/parsererror.xml">XML
Parsing Error: mismatched tag. Expected: </person>.
Location: [url]http://yoda/fooreader/test.htm[/url]
Line Number 1, Column 43:<sourcetext><root><person><name>Jeremy
McPeak</name></root>
------------------------------------------^</sourcetext></parsererror>
所有的错误信息都包含在错误文档的文本中。如果要通过程序使用这些错误信息,那么首先就要对其进行解析。最简单的方法是使用一个稍长的正则表达式:
var reError = />([\s\S]*?)Location:([\s\S]*?)Line Number (\d+), Column
(\d+):<sourcetext>([\s\S]*?)(?:\-*\^)/;
该正则表达式将错误文档分为五个部分:错误消息、发生错误的文件名、行号、该行中发生错误的位置,以及发生错误的源代码。使用正则表达式对象的
test()
方法可以使用这些信息:
if (oXmlDom.firstChild.tagName != "parsererror") {
//
没有错误发生,进行所需操作
} else {
var oXmlSerializer = new XMLSerializer();
var sXmlError = oXmlSerializer.serializeToString(oXmlDom);
var reError = />([\s\S]*?)Location:([\s\S]*?)Line Number (\d+), Column
(\d+):<sourcetext>([\s\S]*?)(?:\-*\^)/;
reError.test(sXmlError);
正则表达式捕获到的第一部分数据是错误消息,第二部分是文件名,第三部分是行号,第四部分是行内位置,第五部分是源码。你可以使用这些解析后的信息来创建自定义的错误消息:
var str = "An error occurred!!\n" +
"Description: " + RegExp.$1 + "\n" +
"File: " + RegExp.$2 + "\n" +
"Line: " + RegExp.$3 + "\n" +
"Line Position: " + RegExp.$4 + "\n" +
"Source Code: " + RegExp.$5;
alert(str);
如果发生错误,那么
alert()
方法会以易于阅读的格式在警告框中来显示相关的错误信息。