我参与了IE7的开发过程,看到了在IE浏览器中形形色色使用MSXML的方法。显然有一些东西困扰着开发者:MSXML“混乱”的版本以及如何创建“正确”的实例。下面是一段非常常见的代码:
if (Web.Application.get_type() == Web.ApplicationType.InternetExplorer) {
var progIDs = [ 'Msxml2.DOMDocument.6.0', 'Msxml2.DOMDocument.5.0', 'Msxml2.DOMDocument.4.0', 'Msxml2.DOMDocument.3.0', 'Msxml2.DOMDocument' ];
// MSXML5.0、MSXML4.0以及Msxml2.DOMDocument都存在问题
for (var i = 0; i < progIDs.length; i++) {
try {
var xmlDOM = new ActiveXObject(progIDs[i]);
return xmlDOM;
} catch (ex) {
}
}
return null;
}
以上代码遍历progIDs数组并且实例化客户端版本最高的MSXML DOM然后返回给调用者。这段代码暗含:
- 兼容性
我们尽力保持各个版本MSXML直接的兼容性,不过,他们之间仍然有不少差别。MSXML 3和MSXML 4是在XML拓荒期时实现的,从中我们学习到了许多经验。MSXML 5是为微软Office产品量身定做的。有时候我们不得不在不同版本上修改某些设计与实现。依次遍历不同的MSXML版本将更容易遇到不期而遇的由于版本行为差异引起的问题。
- 健壮性
由于资源有限,我们不可能修复每个版本中的每个缺陷,于是我们针对性地把资源集中于MSXML 6(最新版本)和MSXML 3(最广泛使用的版本)。
- 测试成本
依赖越多的MSXML版本意味着发布你的应用程序之前需要越多的测试。
在这篇文章中我将简要给出MSXML的历史、生命周期以及版本,通过一个例子提供网络中使用MSXML的最佳实践的细节,以及一些需要注意的地方。
如果你想阅读完整的故事,那么请继续阅读下文;否则,请参考下面四个条目以快速掌握梗概:
- 使用MSXML 6。它随着Vista发布,也提供在Win2k、XP和2003的安装包。它最安全、性能最好、可靠性最好、最符合W3C标准。
- MSXML 3是我们最推荐的替补——从Win2k SP4开始,你几乎可以在所有操作系统上找到它。你几乎不用考虑软件发布的问题。而且它经常随着操作系统升级。
- MSXML 4是七年前发布的,不过,现在已经被MSXML 6取代,应该仅仅用于支持旧版应用程序(legacy applications)。
- MSXML 5是为微软Office量身定做,并不是为普通的开发而设计的。Internet Explorer 7在Internet Zone默认不会直接运行MSXML5——当你尝试实例化MSXML5时IE会跳出提示栏。此外,只有安装了Office 2003及以上的系统会有MSXML5。总之,应该尽量避免在网络应用中使用MSXML5。
- 事实上,MSXML5 组件是默认关闭的。
MSXML生命周期和历史
说来话长,不如让我们回顾不同版本的MSXML、发布背景以及定位。
让我们的客户把他们的应用程序移植到MSXML6上去是我们的最终目标。说到发布,MSXML 6将随着操作系统一起发布,这样网页作者以及软件开发人员都可以方便地使用这个部件而不用考虑发布的问题。不过,由于客户需要在所有微软支持的操作系统上使用同样的XML API,我们仍然需要一种方法使得新的XML技术可以应用到较低版本的操作系统(Win2k、Win XP和Win2k3)中。
MSXML 6已经随着Vista一起发布,不过对于以前的操作系统,则需要单独安装发行包。我们希望MSXML6与较低版本的操作系统的下一个Service Pack一起发布,但是我们需要足够的商业需求才可以这样做。所以,我们的近期和中期计划是仍然保持发布一个可以安装在较低版本操作系统上的MSXML6 可再发行组件包(Redistributable Package)。在以后的博文中,我们会详细讲述迁移到MSXML6的好处。
虽然我们希望今天每个人都在使用MSXML6,但仍然清醒地意识到迁移需要相当的时间。所以我们将继续在MSXML3上投入资源以支持现有的应用程序以及满足那些需要零发布需求。虽然MSXML3并不具有MSXML6的新特性,不过MSXML3仍然不失为一个稳定而强健的XML平台。MSXML3已经随着Win2000 SP4以及以上的操作系统一起发布,对于应用程序而言可以说无需考虑发布的问题。以后,MSXML3的更新将会随着每种操作系统的Service Pack一起发布。 MSXML3 SP7 是最后一个以可再发行组件包形式发布的MSXML3 Service Pack。以后,我们的合作伙伴和客户将不会有使用MSXML3更新的可再发行组件包的需求。
MSXML4是MSXML6的前身,不过并不曾随着操作系统发布。就稳定性、安全性、W3C标准以及与System.Xml的兼容性而言,MSXML6是一个巨大的进步。此外,MSXML6还提供64位版本。目前,我们主要在MSXML6和MSXML3上投入精力,所以我们希望用户尽可能迁移到MSXML6,或者根据需要迁移到MSXML3。
最后,如果不是针对Microsoft Office 2003或者Microsoft Office 2007编写程序却使用MSXML5的开发者,应该尽快迁移到MSXML6。
详述
如何有效地选用一个合适的MSXML的版本呢?从ProgIDs可以看出, MSXML的版本是以并列模式(side-by-side)发布的。这意味着两点:
- 版本是隔离的
比如,如果你已经在你的机器上安装了MSXML3(msxml3.dll),然后你又安装了MSXML6(msxml6.dll)。在System32目录中,它将会与MSXML3并存。如果你有任何需要使用MSXML3的应用程序,这次安装将不会对这个应用程序的执行产生任何影响。
- ProgIDs锁定版本
如果你的应用程序需要使用MSXML6的新特性,那么你应该通过MSXML6的ProgIDs来实例化MSXML对象:
var xmlDOM = new ActiveXObject('Msxml2.DOMDocument.3.0') //uses MSXML 3.0
var xmlDOM = new ActiveXObject('Msxml2.DOMDocument.6.0') //uses MSXML 6.0
需要注意的是,对某个特定版本的MSXML来说,Service Pack并不是并列模式安装的,它会升级原来的MSXML到Service Pack的版本。比如,如果你的机器中正在运行MSXML3 SP5,然后你安装了MSXML3 SP7,那么所有使用MSXML3的应用程序将会自动地运行MSXML3 SP7。
理想情况下,用户应该针对MSXML6对应用程序进行标准化。但是正如上文中提到的,在不久的将来,旧版应用程序和需要零部署的应用程序可能会对完全迁移到MSXML6产生阻碍。既然这样,就有两个因素需要平衡:功能和测试代价。于是,本质上我们有两种选择:
- 尝试MSXML6并且以MSXML3做为备用
MSXML6不仅有一些MSXML3没有的功能(比如支持XSD架构),而且提升了稳定性、性能和安全性。所以你的应用程序应该尝试使用MSXML6,如果出现问题也应该能够用MSXML3来替代。如果你不想在你的应用程序发布前出意外的话,请记住要对你的应用程序分别使用MSXML6和MSXML3进行测试。下面是简单的示例:
if (Web.Application.get_type() == Web.ApplicationType.InternetExplorer) {
var progIDs = [ 'Msxml2.DOMDocument.6.0', 'Msxml2.DOMDocument.3.0'];
for (var i = 0; i < progIDs.length; i++) {
try {
var xmlDOM = new ActiveXObject(progIDs[i]);
return xmlDOM;
} catch (ex) {
}
}
return null;
}
- 针对MSXML3进行标准化并为在将来使用MSXML6做准备
这么做会在降低测试代价的同时把应用程序的功能局限在MSXML3上。我会试着在以后的博文中写一些关于MSXML3的应用程序如何迁移到MSXML6(或更高的版本)上。
一些需要注意的事情
- MSXML6中对安全敏感的特性是默认关闭(off-by-default)的
然而,为了向下兼容和避免一些问题,MSXML3中一些对安全敏感的特性是默认打开(on-by-default)的。请查阅SDK以了解更详细的信息。
- 使用XSD架构语言
MSXML3并不支持Xml Schema(XSD 1.0)。所以依赖XSD的应用程序应该直接使用MSXML6。MSXML6在XSD的实现上和MSXML4以及MSXML5上有些不同。MSXML6更加符合W3C标准,对.Net2.0中的System.XML更加兼容。所以在有些应用程序升级的时候可能有些工作要做。请查阅SDK以了解更详细的信息。
- 默认查询语言
当你使用DOM中的SelectNodes或SelectSingleNode进行查询的时候,在MSXML6中默认的选择语言是XPath,而在MSXML3中则是XSL模式。可以像这样xmlDoc.setProperty("SelectionLanguage", "XPath"); 通过设置DOM的二级属性“选择语言”把MSXML3的查询语言设置成标准XPath 1.0。请查阅SDK以了解更详细的信息。
- 不指定版本(version-independent)的ProgIDs
在MSXML中,有关于“不指定版本”的ProgID的问题总是让人产生混淆。不指定版本的ProgID总是绑定到MSXML3(与许多人认为的绑定到系统中最高版本的MSXML不同)。这就意味着无论指定或不指定版本“3.0”,ProgID将返回同一个对象。比如,下面两行代码都会返回一个MSXML3 DOMDocument对象:
var xmlDOM = new ActiveXObject('Msxml2.DOMDocument.3.0');
和
var xmlDOM = new ActiveXObject('Msxml2.DOMDocument');
- 较老版本的ProgIDs
远离那些比3.0还低的ProgIDs的版本。在某些特定的操作系统中,仍然会带有MSXML 2.6。然而在最近的MS06-061安全补丁中,这些较古老版本的已经被禁用(kill-bitted)了。
- MSXML2 vs. Microsoft命名空间
我见到过许多代码把ActiveX对象Microsoft.XMLHTTP实例化,而不是MSXML2.XMLHTTP.3.0或MSXML2.XMLHTTP.6.0(如果使用6.0)。Microsoft命名空间事实上已经过时了,而且它是用MSXML3实现的,仅仅是为了支持旧版的应用程序。不幸的是,我们对老版本支持使用了一个好听的名字(Microsoft)。但请在实例化对象的时候坚持使用MSXML2命名空间。
一如往常,如果你有任何的问题、建议或想法,欢迎在这里发表或是直接给我发email。我将会非常乐意看到这些反馈信息。
Adam Wiener
Lead Program Manager
Data Programmability/XML Technologies