3.1.2 将响应解析为XML
你已经了解到,服务器不一定按XML格式发送响应。只要
Content-Type响应首部正确地设置为text/plain(如果是XML,Content-Type响应首部则是text/xml),将响应作为简单文本发送是完全可以的。复杂的数据结构就很适合以XML格式发送。对于导航XML文档以及修改XML文档的结构和内容,当前浏览器已经提供了很好的支持。
浏览器到底怎么处理服务器返回的XML呢?当前浏览器把XML看作是遵循W3C DOM的XML文档。W3C DOM指定了一组很丰富的API,可用于搜索和处理XML文档。DOM兼容的浏览器必须实现这些API,而且不允许有自定义的行为,这样就能尽可能地改善脚本在不同浏览器之间的可移植性。
W3C DOM
W3C DOM到底是什么?W3C主页提供了清晰的定义:
文档对象模型(DOM
)是与平台和语言无关的接口,允许程序和脚本动态地访问和更新文档的内容、结构和样式。文档可以进一步处理,处理的结果可以放回到所提供的页面中。
不仅如此,W3C还解释了为什么要定义标准的DOM。W3C从其成员处收到了大量请求,这些请求都是关于将XML和HTML文档的对象模型提供给脚本所要采用的方法。提案并没有提出任何新的标记或样式表技术,而只是力图确保这些可互操作而且与脚本语言无关的解决方案能得到共识,并为开发社区所采纳。简单地说,W3C DOM标准的目的是尽量避免20世纪90年代末的脚本恶梦,那时相互竞争的浏览器都有自己专用的对象模型,而且通常都是不兼容的,这就使得实现跨平台的脚本极其困难。
W3C DOM和JavaScript
W3C DOM
和
JavaScript
很容易混淆不清。
DOM
是面向
HTML
和
XML
文档的
API
,为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构。
JavaScript
则是
用于
访问和处理
DOM
的语言。如果没有
DOM
,
JavaScript
根本没有
Web
页面和构成页面元素的概念。文档中的每个元素都是
DOM
的一部分,这就使得
JavaScript
可以访问元素的属性和方法。
DOM独立于具体的编程语言,通常通过JavaScript访问DOM,不过并不严格要求这样。可以使用任何脚本语言来访问DOM,这要归功于其一致的API。表3-1列出了DOM元素的一些有用的属性,表3-2列出了一些有用的方法。
表3-1 用于处理XML文档的DOM元素属性
属性名
|
描述
|
childNodes
|
返回当前元素所有子元素的数组
|
firstChild
|
返回当前元素的第一个下级子元素
|
lastChild
|
返回当前元素的最后一个子元素
|
nextSibling
|
返回紧跟在当前元素后面的元素
|
nodeValue
|
指定表示元素值的读
/
写属性
|
parentNode
|
返回元素的父节点
|
previousSibling
|
返回紧邻当前元素之前的元素
|
表3-2 用于遍历XML文档的DOM元素方法
方法名
|
描述
|
getElementById(id) (document)
|
获取有指定惟一
ID
属性值文档中的元素
|
getElementsByTagName(name)
|
返回当前元素中有指定标记名的子元素的数组
|
hasChildNodes()
|
返回一个布尔值,指示元素是否有子元素
|
getAttribute(name)
|
返回元素的属性值,属性由
name
指定
|
有了W3C DOM,就能编写简单的跨浏览器脚本,从而充分利用XML的强大功能和灵活性,将XML作为浏览器和服务器之间的通信介质。
从下面的例子可以看到,使用遵循W3C DOM的JavaScript来读取XML文档是何等简单。代码清单3-3显示了服务器向浏览器返回的XML文档的内容。这是一个简单的美国州名列表,各个州按地区划分。
代码清单3-3
服务器返回的美国州名列表
<?
xml version="1.0" encoding="UTF-8"
?>
< states >
< north >
< state > Minnesota </ state >
< state > Iowa </ state >
< state > North Dakota </ state >
</ north >
< south >
< state > Texas </ state >
< state > Oklahoma </ state >
< state > Louisiana </ state >
</ south >
< east >
< state > New York </ state >
< state > North Carolina </ state >
< state > Massachusetts </ state >
</ east >
< west >
< state > California </ state >
< state > Oregon </ state >
< state > Nevada </ state >
</ west >
</ states >
< states >
< north >
< state > Minnesota </ state >
< state > Iowa </ state >
< state > North Dakota </ state >
</ north >
< south >
< state > Texas </ state >
< state > Oklahoma </ state >
< state > Louisiana </ state >
</ south >
< east >
< state > New York </ state >
< state > North Carolina </ state >
< state > Massachusetts </ state >
</ east >
< west >
< state > California </ state >
< state > Oregon </ state >
< state > Nevada </ state >
</ west >
</ states >
![](https://i-blog.csdnimg.cn/blog_migrate/eca6d29c7f82d3de6900276802470e9b.png)
图3-2
点击页面上的任何一个按钮都会从服务器加载XML文档,并在警告框中显示适当的结果
代码清单3-4显示了
parseXML.html。
代码清单
3-4
parseXML.html
<!
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > Parsing XML Responses with the W3C DOM </ title >
< script type ="text/javascript" >
var xmlHttp;
var requestType = "" ;
function createXMLHttpRequest() {
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject( " Microsoft.XMLHTTP " );
}
else if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
}
function startRequest(requestedList) {
requestType = requestedList;
createXMLHttpRequest();
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.open( " GET " , " parseXML.xml " , true );
xmlHttp.send( null );
}
function handleStateChange() {
if (xmlHttp.readyState == 4 ) {
if (xmlHttp.status == 200 ) {
if (requestType == " north " ) {
listNorthStates();
}
else if (requestType == " all " ) {
listAllStates();
}
}
}
}
function listNorthStates() {
var xmlDoc = xmlHttp.responseXML;
var northNode = xmlDoc.getElementsByTagName( " north " )[ 0 ];
var out = " Northern States " ;
var northStates = northNode.getElementsByTagName( " state " );
outputList( " Northern States " , northStates);
}
function listAllStates() {
var xmlDoc = xmlHttp.responseXML;
var allStates = xmlDoc.getElementsByTagName( " state " );
outputList( " All States in Document " , allStates);
}
function outputList(title, states) {
var out = title;
var currentState = null ;
for ( var i = 0 ; i < states.length; i ++ ) {
currentState = states[i];
out = out + " - " + currentState.childNodes[ 0 ].nodeValue;
}
alert(out);
}
</ script >
</ head >
< body >
< h1 > Process XML Document of U.S. States </ h1 >
< br />< br />
< form action ="#" >
< input type ="button" value ="View All Listed States"
onclick ="startRequest('all');" />
< br />< br />
< input type ="button" value ="View All Listed Northern States"
onclick ="startRequest('north');" />
</ form >
</ body >
</ html >
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > Parsing XML Responses with the W3C DOM </ title >
< script type ="text/javascript" >
var xmlHttp;
var requestType = "" ;
function createXMLHttpRequest() {
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject( " Microsoft.XMLHTTP " );
}
else if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
}
function startRequest(requestedList) {
requestType = requestedList;
createXMLHttpRequest();
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.open( " GET " , " parseXML.xml " , true );
xmlHttp.send( null );
}
function handleStateChange() {
if (xmlHttp.readyState == 4 ) {
if (xmlHttp.status == 200 ) {
if (requestType == " north " ) {
listNorthStates();
}
else if (requestType == " all " ) {
listAllStates();
}
}
}
}
function listNorthStates() {
var xmlDoc = xmlHttp.responseXML;
var northNode = xmlDoc.getElementsByTagName( " north " )[ 0 ];
var out = " Northern States " ;
var northStates = northNode.getElementsByTagName( " state " );
outputList( " Northern States " , northStates);
}
function listAllStates() {
var xmlDoc = xmlHttp.responseXML;
var allStates = xmlDoc.getElementsByTagName( " state " );
outputList( " All States in Document " , allStates);
}
function outputList(title, states) {
var out = title;
var currentState = null ;
for ( var i = 0 ; i < states.length; i ++ ) {
currentState = states[i];
out = out + " - " + currentState.childNodes[ 0 ].nodeValue;
}
alert(out);
}
</ script >
</ head >
< body >
< h1 > Process XML Document of U.S. States </ h1 >
< br />< br />
< form action ="#" >
< input type ="button" value ="View All Listed States"
onclick ="startRequest('all');" />
< br />< br />
< input type ="button" value ="View All Listed Northern States"
onclick ="startRequest('north');" />
</ form >
</ body >
</ html >
以上脚本从服务器获取XML文档并加以处理,它与前面看到的例子很相似,不过前面的例子只是将响应处理为简单文本。关键区别就在于
listNorthStates和
listAllStates函数。前面的例子从XMLHttpRequest对象获取服务器响应,并使用XMLHttpRequest对象的
responseText属性将响应获取为文本。
listNorthStates和
listAllStates函数则不同,它们使用了XMLHttpRequest对象的
responseXML属性,将结果获取为XML文档,这样一来,你就可以使用W3C DOM方法来遍历XML文档了。
仔细研究一下
listAllStates函数。它首先创建了一个局部变量,名为
xmlDoc,并将这个变量初始化设置为服务器返回的XML文档,这个XML文档是使用XMLHttpRequest对象的
responseXML属性得到的。利用XML文档的
getElementsByTagName方法可以获取文档中所有标记名为
state的元素。
getElementsByTagName方法返回了包含所有
state元素的数组,这个数组将赋给名为
allStates的局部变量。
从XML文档获取了所有
state元素之后,
listAllStates函数调用
outputList函数,并在警告框中显示这些
state元素。
listAllStates方法将迭代处理
state元素的数组,将各元素的相应州名逐个追加到一个串中,这个串最后将显示在警告框中。
有一点要特别注意,即
如何从
state元素获取州名。你可能认为,
state元素会简单地提供属性或方法来得到这个元素的文本,但并非如此。
表示州名的文本实际上是
state元素的子元素。在XML文档中,文本本身被认为是一个节点,而且必须是另外某个元素的子元素。由于表示州名的文本实际上是
state元素的子元素,所以必须先从
state元素获取文本元素,再从这个文本元素得到其文本内容。
outputList函数的工作就是如此。它迭代处理数组中的所有元素,将当前元素赋给
currentState变量。因为表示州名的文本元素总是
state元素的第一个子元素,所以可以使用
childNodes属性来得到文本元素。一旦有了具体的文本元素,就可以使用
nodeValue属性返回表示州名的文本内容。
listNorthStates函数与
listAllStates是类似的,只不过增加了一个小技巧。你只想得到北部地区的州,而不是所有州。为此,首先使用
getElementsByTagName方法获取
north标记,从而获得XML文档中的
north元素。因为文档只包含一个
north元素,而且
getElementsByTagName方法总是返回一个数组,所以要用
[0]记法来抽出
north元素。这是因为,在
getElementsByTagName方法返回的数组中,
north元素处在第一个位置上(也是惟一的位
置)。既然有了
north
元素,接下来调用
north
元素的
getElementsByTagName
方法,就可以得到
north
元素的
state
子元素。有了
north
元素所有
state
子元素的数组后,再使用
outputList方法在警告框中显示这些州名。