说明:参见《JavaScript高级程序设计》第15章"JavaScript中的XML "。
一.             浏览器中的XML DOM支持
 目前只有两种浏览器支持客户端的XML处理,分别是IE和Mozilla。
1. IE中的XML DOM支持
在为IE添加XML支持时,微软在JavaScript之外另寻了个方案:基于ActiveX的MSXML库。
1) DOM创建
对每个新版本的MSXML,都会创建出不同的XML DOM对象,而它们各自的名称也不相同,MSXML最新的版本是5.0。它存在如下几种XML DOM实现:
 i)Microsoft XmlDom(最原始的);
ii)MSXML2.DOMDocument;
iii)MSXML2.DOMDocument3.0;
iv)MSXML2.DOMDocument4.0;
v)MSXML2.DOMDocument5.0。
为确保使用了正确的XML DOM版本,也为避免任何其他错误,我们可以创建一个函数来测试每个XML DOM对象字符串,出现错误即捕获:
function createXMLDOM() {
    var arrSignatures = {"MSXML2.DOMDocument5.0", "MSXML2.DOMDocument4.0", "MSXML2.DOMDocument3.0", "MSXML2.DOMDocument", "Microsoft XmlDom"};
for (var i= 0; i < arrSignatures.length; i++) {
       try {
              var oXmlDom = new ActiveXObject(arrSignatures[i]);
              return oXmlDom;
} catch(oError) {
       //ignore
}
} 
throw new Error("SXML is not installed on your system.";
}

 
 
注意:这段在IE中创建XML DOM的代码在其他浏览器会出现错误。因此,必须在其之前先进行浏览器检测。
2) 载入XML
有了可用的XML DOM对象后,就可以载入XML了,微软的XML DOM提供两种方法,.即:loadXML()和load()。
loadXML()方法可直接向XML DOM输入XML字符串,eg.
var oXmlDom = createXMLDOM();
oXmlDom.loadXML(“<root><child/></root>”);
load()方法用于从服务器上载入XML文件,不过load()方法只可以载入与包含JavaScript的页面存储于同一个服务器上的文件,即:不可以通过其他人的服务器载入XML文件。
还有两种载入文件的模式:同步与异步。以同步模式载入时,JavaScript代码会等待文件完全载入后才继续执行代码;而以一步模式载入时,不会等待,可以使用事件处理函数来判断文件是否完全载入了。默认情况下,为异步载入。要进行同步载入,需设置async特性为false,如下:
oXmlDom. async = false;
然后使用load()方法,并给出要载入的文件名:
oXmlDom.load(“test.xml”);
异步载入文件时,要使用readyState特性和onreadystatechange事件处理函数:
readyState特性有五种可能的值:
     0——DOM尚未初始化任何信息;
     1——DOM尚未载入数据;
     2——DOM完成了数据载入;
     3——DOM已经可用,不过某些部分可能还不能用;
     4——DOM已经完全被载入,可以使用了。
一旦readyState的值发生变化,就会触发onreadystatechange事件。使用该函数,就可以在DOM完全载入时,发出通知:
oXmlDom.onreadystatechange = function() {
    if (oXmlDom.readyState == 4) {
       alert(“已完全载入!”);
}
}
必须在调用load()方法前分配好onreadystatechange事件处理函数,如下所示:
oXmlDom.onreadystatechange = function() {
    if (oXmlDom.readyState == 4) {
       alert(“已完全载入!”);
}
}
oXmlDom.load(“test.xml”);
注意:事件处理函数代码使用oXmlDom而不是this关键字,这是JavaScript中ActiveX对象的特殊之处。
load()方法可以接受部分的、相对的或者完整的XML文件路径。eg.
oXmlDom.load(“test.xml”);
oXmlDom.load(“../test.xml”);
oXmlDom.load(“http://www.amigo.com/test.xml”)。
3) 获取XML
把XML载入到DOM中后,还需将XML取出来,微软为每个节点(包括文档节点)都添加了一个xml特性,使得这个操作十分方便,它会将XML表现形式作为字符串返回。所以获取载入后的XML十分简单:
oXmlDom.load(“test.xml”);
alert(oXmlDom.xml);
也可以获取某个特定节点的XML:
var oNode = oXmlDom.documentElements.childNodes[1];
alert(oNode.xml);
xml特性是只读的,如果尝试直接对其进行赋值会产生错误。
4) 解释错误
微软的XML DOM的parseError的特性包含了关于解析XML代码时所遇到的问题的所有信息。
parseError特性实际上是包含以下特性的对象:
     errorCode——表示所发生的错误类型的数字代号(没有错误时为0);
     filePos——错误发生在文件中的位置;
     line——遇到错误的行号;
     linepos——在遇到错误的那一行上的字符的位置;
     reason——对错误的一个解释;
     srcText——造成错误的代码;
      url——造成错误的文件的URL(如果可用)。
可直接对parseError自身取值,它会返回errorCode的值。Eg.
if (oXmlDom. parseError != 0) {
    //…
}
可以使用parseError对象来创建自己的错误对话框:
if (oXmlDom. parseError != 0) {
    var oError = oXmlDom. parseError;
    alert(“错误发生!\nerrorCode: ” + oError. errorCode 
+ “\nLine:” + oError.line + “\nLine Pos: ” + oError. linepos 
+ “\nReason: ” + oError. reason);
}
 
2. Mozilla中的XML DOM支持
 略。
 
3. 通用接口
   有了跨浏览器的解决方案时,使用XML DOM进行开发才真正有用。IE和Mozilla的实现之间有着很明显的区别,开发时会造成很严重的问题。需要找出一套能在两种浏览器中都可以使用XML DOM的通用方法。
1) 修改DOM创建
最简单方法是创建伪类,使其通过var oXmlDom = new XmlDom ();来创建XML DOM。在其构造函数中进行浏览器检测,eg.
function XmlDom() {
       if (window.ActiveObject) {
       //IE-specific code
} else if (document.implementation && document.implementation.createDocument) {
       //DOM-specific code
} else {
       throw new Error(“你的浏览器不支持XML DOM对象”);
}
}
2) IE分支
将上节的IE中创建DOM的代码转贴到上述代码中。
3) Mozilla分支
略。
4) 完整代码
完整代码如下所示:
 
function XmlDom() {
if (window.ActiveXObjext) {
var arrSignatures = {"MSXML2.DOMDocument5.0", "MSXML2.DOMDocument4.0", "MSXML2.DOMDocument3.0", "MSXML2.DOMDocument", "Microsoft XmlDom"};
for (var i= 0; i < arrSignatures.length; i++) {
                     try {
                            var oXmlDom = new ActiveXObject(arrSignatures[i]);
                            return oXmlDom;
} catch(oError) {
                     //ignore
}
}
throw new Error("MSXML is not installed on your system.");
} else if (document.implementation && document.implementation.createDocument) {
       var oXmlDom = document.implementation.createDocument("", "", null);
       oXmlDom.parseError = {
              valueOf: function() {return this.errorCode;},
        toString: function() {return this.errorCode.toString()};
}
oXmlDom.addEventListener("load", function()) {
       this.__checkForErrors__();
       this.__changeReadyState__(4);
}, false);
return oXmlDom;
} else {
       throw new Error("你的浏览器不支持XML DOM对象");
}
}

if (isMoz) {
Document.prototype.readyState = 0;
 Document.prototype.onreadystatechange = null;
 Document. prototype.__changeReadyState__ = function(iReadyState) {
     this.readyState = iReadyState;
     if (typeof this.onreadystatechange == “function”) {
       this.onreadystatechange();
}
};

Document.prototype.__initError__ = function() {
     this.parseError.errorCode = 0;
     this.parseError..filepos = -1;
     this.parseError..line = -1;
     this.parseError..lineppos = -1;
     this.parseError..reason = null;
     this.parseError.srcText = null;
     this.parseError..url = null;
};

Document.prototype.__checkForErrors__ = function() {
     if (this.documentElement.tagName == “parseError”) {
       var reError = />([\s\S]*?)Location:([\s\S]*?)Line Number (\d+), Column (\d+):<sourcetext>([\s\S]*?)(?:\-*\^)/;
       reError.text(this.xml);
       this.parseError..errorCode = -999999;
       this.parseError..reason = RegExp.$1p;
       this.parseError..url = this.parseError..$2;
       this.parseError..line = pauseInt(RegExp.$3);
       this.parseError..linepos = parseInt(RegExp.$4);
       this.parseError..srcText = RegExp.$5;
}
};

Document.prototype.loadXML = function(sXml) {
     this.__initError__();
     this.__changeReadyState__(1);
     var oParser = new DomParser();
     var oXmlDom = oParser.parseFromString(sXml, "text/xml");
     while (this.firstChild) {
       this.removeChild(this.firstChild);
}

for (var = 0; I < oXmlDom.childNodes.length; i++) {
       var oNewNode = this.importNode(oXmlDom.childNodes[i], true);
       this.appendChild(oNewNode);
}

this.__checkForErrors__();
this.__changeReadyState__(4);
};

Document.prototype.__load__ = Document.prototype.load;
Document.prototype.load = function(sURL) {
     this.__initError__();
     this.__changeReadyState__(1);
     this.__load__(sURL)L
};

Node.prototype.__defineGetter__("xml", function()) {
     var oSerializer = new XMLSerializer();
     return oSerializer.serializeToString(this. "text/xml");
});
} 
 
二.             浏览器对XPath的支持
 XPath是一种可以在XML代码中定位数据的方式。
1.       简介
每个XPath表达式有两部分:一个上下文节点和一个节点模式。前者提供了节点模式起始的位置。节点模式是由一个或多个节点选择器组成的字符串。
Eg. 
<?xml version=”1.0”?>
    <employees>
           <employee title=”软件工程师”>
                  <name>阿蜜果</name>
           </employee>
           <employee title=”测试工程师”>
                  <name>amigo</name>
           </employee>
       </employees> 
若XPath表达式employee/name,匹配的是<name>阿蜜果</name>和<name>amigo</name>,若要选择<employee/>元素的第一个<name/>元素,可用employee[position() == 1]/name。在XPath中,方框记号用于为某个节点提供更加确切的信息,position()用于返回元素在父节点下的位置。
 除了未知和名称外,还可以使用不同的方法来匹配元素,若要选择所有title特性为“软件工程师”的<employee/>元素,对应的表达式为:
 employee[@title = “软件工程师”]
 其中@是attribute的缩写。
2. IE中XPath的支持
每个节点的都有两个可用于获取匹配XPath模式的节点的方法:
selectNodes():用于匹配某个模式的节点的集合;
selectSingleNode():用于返回匹配给定模式的第一个节点。
 eg. varlstNodes = oXmlDom.documentElement.selectNodes(“employee/name”);
 返回包含所有匹配给定模式的节点的NodeList,可以通过如下方式迭代所有的元素:
 for (var i = 0; i < varlstNodes.length; i++) {
    alert(varlstNodes[i]);
}
如果没有匹配的节点,返回的NodeList的length为0。
3. Mozilla中XPath的支持
略。
三.             浏览器的XSLT支持
 XSLT:可扩展样式表语言转换,可由一些模板组成。模板属于XML的某个特性的一部分(使用XPath指定),它可以决定为这一部分输出什么文本。通过为不同的元素和条件定义模板,XSLT样式表变成了一种XML的解析器。
1. IE对XSLT的支持
从MSXML3.0开始,IE就完全支持XSLT1.0了。对于在IE6.0以前的版本,还需要安装新版的MSXML。
最简单的XSLT转换的方法是:分别将XML源代码和XSLT文件载入各自的DOM,并使用特有的transformNode方法:
 oXmlDom.load(“employees.xml”);
 oXslDom.load(“employees.xslt”);
 var sResult = oXmlDom. transformNode(oXslDom);
 其实,也可以不从文档层次转换,而从节点层次转换,如果从某个节点调用transformNode(),则从这个点开始转换,但是XSLT能访问包含这个节点的整个XML文档。
 在IE中使用XSLT的另外一个比较复杂的方法是,使用XSL模板和处理器。这种方法必须使用MSXML的其他几个ActiveX控件。首先XSLT文件必须载入到一个自由线程DOM文档中,代码如下:
 var oXslDom = new ActiveXObject(“MSXML2.FreeThreadedDOMDocumnet”);
 oXslDom.asyn = false;
 oXslDom.load(“employees.xml”);
 自由线程DOM文档建立并加载好后,必须将其分配到XSL模板中,这是另一个ActiveX对象:
 var oTemplate = new ActiveXObject(“:MSXML2.XSLTemplate”);
 oTemplate.stylesheet = oXslDom;
 然后,可以用XSL模板来创建一个XSL处理器:
 var oProcessor = oTemplate.createProcessor();
 创建处理器后,将input特性设置为要进行转换的XML DOM节点,然后调用transform()方法:
 oProcessor.input = oXmlDom;
 oProcessor.transform();
 然后将从output特性中访问结果字符串:
 var sResult = oProcessor.output;
 这个复杂的方法模仿了transformNode()的功能,但该方法允许更多地控制XSLT。
 注意:MSXML只支持XSLT1.0。MSXML的开发自从转到.NET Framework后就停止了。可能在未来的某天,JavaScript会允许访问XML和XSL的.NET对象。
2. Mozilla中XSLT的支持
略。
	posted on 2007-08-13 13:19 
阿蜜果 阅读(2842) 
评论(6)  编辑  收藏  所属分类: 
Javascript