《 JavaScript高级程序设计》第15章 javascript中的XML

呵呵,全是从读书频道中抄过来的,所以直接跳15章了
http://book.csdn.net/bookfiles/110/index.htm
 

15.1  浏览器中的XML DOM支持

仅有两个浏览器IEMozilla可以支持客户端的XML处理。

微软在JavaScript中引入了用于创建ActiveX对象的ActiveXObject类。ActiveXObject的构造函数只有一个参数——要进行实例化的ActiveX对象的字符串代号。例如,XML DOM对象的第一个版本称为Microsoft.XmlDom。所以,要创建这个对象的实例,使用以下代码:

执行这行代码后, oXmlDom 对象就同其他 DOM Document 的对象行为完全一样了

开发人员首次使用这个XML处理方法时,经常会出现问题,因为用户常常未安装MSXML。绝大多数情况,开发人员必须直接从微软下载这个库。不过,IE 5.0修复了这个问题,它直接搭载了MSXML,这就确保了用IE 5.0或更高版本的用户一定可以使用这个功能。

1DOM创建

对每个新版本的MSXML,都会创建出不同的XML DOM对象,而它们各自的名称也不相同。MSXML最新的版本是5.0,也就是说,存在以下XML DOM实现:

q  Microsoft.XmlDom(最原始的);

q  MSXML2.DOMDocument

q  MSXML2.DOMDocument.3.0

q  MSXML2.DOMDocument.4.0

q  MSXML2.DOMDocument.5.0

为确保使用了正确的XML DOM版本,也为避免任何其他错误,我们可以创建一个函数来测试每个XML DOM字符串,出现错误即捕获:

2.载入XML

现在已有个可用的XML DOM对象,就可以载入一些XML了。微软的XML DOM有两种载入XML的方法:loadXML()load()

loadXML()方法可直接向XML DOM输入XML字符串:

load()方法用于从服务器上载入XML文件。不过,load()方法只可以载入与包含JavaScript的页面存储于同一服务器上的文件,也就是说,不可以通过其他人的服务器载入XML文件。

还有两种载入文件的模式:同步和异步。以同步模式载入文件时,JavaScript代码会等待文件完全载入后才继续执行代码;而以异步模式载入时,不会等待,可以使用事件处理函数来判断文件是否完全载入了。

默认情况下,文件按照异步模式载入。要进行同步载入,只需设置async特性为false

然后使用load()方法,并给出要载入的文件名:

执行这一行代码后,oXmlDom会包含能表示XML文件结构的一个DOM文档,这样就可以使用DOM所有的特性和方法了:

异步载入文件时,要使用readyState特性和onreadystatechange事件处理函数:

readyState特性有五种可能的值:

q  0——DOM尚未初始化任何信息;

q  1——DOM正在载入数据;

q  2——DOM完成了数据载入;

q  3——DOM已经可用,不过某些部分可能还不能用;

q  4——DOM已经完全被载入,可以使用了。

一旦readyState特性的值发生变化,就会触发readystatechange事件。如果使用onreadystatechange事件处理函数,就可以在DOM完全载入时,发出通知:

必须在调用load()方法前分配好onreadystatechange事件处理函数,就像下面代码中那样:

无论同步或者异步地载入文件,load()方法都可以接受部分的、相对的或者完整的XML文件路径,如下:

3.获取XML

XML载入到DOM中后,肯定还需将XML取出来。微软为每个节点(包括文档节点)都添加了一个xml特性,使得这个操作十分方便,它会将XML表现形式作为字符串返回。所以要获取载入后的XML十分简单:

也可以仅获取某个特定节点的XML

4.解释错误

在尝试将XML载入到XML DOM对象中时,无论使用loadXML()方法还是load()方法,都有可能出现XML格式不正确的情况。为解决这个问题,微软的XML DOMparseError的特性包含了关于解析XML代码时所遇到的问题的所有信息。

parseError特性实际上是包含以下特性的对象:

q  errorCode——表示所发生的错误类型的数字代号(当没有错误时为0);

q  filePos——错误发生在文件中的位置;

q  line——遇到错误的行号;

q  linepos——在遇到错误的那一行上的字符的位置;

q  reason——对错误的一个解释;

q  srcText——造成错误的代码;

q  url——造成错误的文件的URL(如果可用)。

当直接对parseError自身取值,它会返回errorCode的值,也就是说可以这样进行检查:

检查时应该检查错误代码是否不等于0,因为错误代码可能为正也可能为负。

可以使用parseError对象来创建自己的错误对话框:

另一个选项是抛出自己的错误:

不管最终如何显示错误,最好在XML DOM载入完毕后就立即检查错误。


Mozilla其他方面一样,它提供的XML DOM版本要比IE的更加标准。以下既是在Mozilla如何使用XML

1.创建DOM

DOM标准指出,document.implementation对象有个可用的createDocument()方法。Mozilla严格遵循了这个标准,可以这样创建XML DOM

createDocument()的三个参数分别是文档的命名空间URL,文档元素的标签名以及一个文档类型对象(总是为null,因为在Mozilla中还没有对文档类型对象的支持)。前面这行代码创建一个空的XML DOM。要创建包含一个文档元素的XML DOM,只需将标签名作为第二个参数:

这行代码创建了代表XML代码<root/>XML DOM。如果在第一个参数中指定了命名空间URL,可进一步定义文档元素:

2.载入XML

Mozilla只支持一个载入数据的方法:load()Mozilla中的load()方法和IE中的load()工作方式一样。只要指定要载入的XML文件,以及同步还是异步(默认)载入。

如果同步载入XML文件,代码基本上IE差不多:

进行异步载入,情况就有些不同了。

MozillaXML DOM并不支持微软的readyState特性(实际上,readyState并非Mozilla的实现所遵循的DOM Level 3载入和保存规范的一部份)。相反,MozillaXML DOM 会在文件完全载入后触发load事件,也就是说必须使用onload事件处理函数来判断DOM何时可用:

MozillaXML DOM不支持loadXML()方法。要将XML字符串解析为DOM,必须使用DOMParser对象:

这段代码创建了代表 <root/> XML DOM 。第一行创建 DOMParser 对象,第二行用它唯一的方法 parseFromString() 来创建 XML DOM 。这个方法接受两个参数,要解析的 XML 字符串以及字符串的内容类型。要解析 XML 代码,内容类型可以是 " text/xml " 或者 " application/ xml " ;任何其他内容类型都被忽略

因为XML DOM只是MozillaJavaScript实现的一部分,所以它可自己添加loadXML()方法。XML DOM实际的类称为Document,所以添加新方法同使用prototype对象一样容易:

然后,用DOMParser创建新的XML DOM

下面,原来的文档必须清空其内容。可用while循环来删除所有的文档的子节点:

记住,因为这个函数是一个方法,所以this关键词指向XML DOM对象。在删除所有的子节点后,所有的oXmlDom的子节点必须导入到文档中(使用importNode()方法)并作为子节点添加(使用appendChild()):

只需包含这段代码,在Mozilla中就可以与在IE中一样地使用loadXML()方法了。

3.获取XML

Mozilla提供了XMLSerializer对象:

这段简单的代码段用XMLSerializer唯一的方法——serializeTostring()oXmlDom创建了XML代码。serializeTostring()接受要进行序列化的节点和内容类型作为参数。这次,内容类型可以是"text/xml"或者"application/xml"。使用这个对象,就可以自己为Mozilla合成xml特性,只需使用defineGetter()方法。

defineGetter()方法只存在于Mozilla中,用于为某个特性定义获取函数,也就是说,读取特性时,就会调用这个函数并返回它的结果。例如:

第一行代码读取nodeValue特性,即解释器读取特性的值。如果定义了获取函数,就会运行这个函数并将函数值作为特性的值返回。第二行代码对nodeValue特性进行设置,即为其赋值。如果定义设置函数(与获取函数相对),则调用这个函数,并以New value作为参数值。当然,还有个defineSetter()方法,但在这里用不到。

方法defineGetter()是按照JavaScript对于私有特性和方法的标准隐藏的——在名字前后加上两个下划线:

可以看见,defineGetter()需要两个参数:特性的名称和要调用的函数。指定的特性名不能再用作一般的特性名。例如,不能这样:

一般获取函数和设置函数是成对定义的,但是也可以只分配一个获取函数来创建只读特性。这样就可创建xml特性了。

因为文档中每种类型的节点都有xml特性。所以最好将其添加到Node类中(其他的节点类型都是继承Node的):

分配给xml特性的函数十分简单,对前面的例子的唯一改变是thisserializeToString()方法的第一个参数(在此上下文中,this指向节点自身)。如果将这段代码包含在页面中,就可以与使用微软的xml特性方式一样地使用自定义的xml特性:

4.解析错误

XML文件的解析过程中发生错误时,XML DOM会创建文档来解释这个错误。假设运行以下代码:

尽管未抛出任何错误,但是oXmlDom会显示出错误。在此例子中,它会呈现出这段代码:

所以要判断是否在XML代码的解析过程中有错误,必须测试文档元素的标签名:

可惜,唯一能获取确切的错误信息的方法是,解析错误信息文本。最简单的方法是使用正则表达式:

这段正则表达式抓取了所有XML代码中潜在的信息。第一个捕获性分组获取错误信息,第二个获取文件名,第三个获取行号,第四个获取列号,第五个获取造成错误的源代码(不包含最后的横线和脱字符号)。只需使用test()方法就可创建错误信息了:


 

通用接口

有了跨浏览器的解决方案时,使用XML DOM进行开发才真正有用。IEMozilla的实现之间有着十分明显的区别,开发时会造成很严重的问题。所以必须找出一套能在两种浏览器中都可使用XML DOM的通用办法。

1.修改DOM创建

第一步是创建IEMozilla通用的创建XML DOM对象的方法。最简单的方法是创建伪类,使之可以这样创建XML DOM

当然,在XmlDom构造函数中必须进行浏览器检测:

这段代码使用了对象/特性检测法来判断要走哪条路。因为Windows上的IE是唯一支持ActiveXObject类的浏览器,所以这样测试IE是可以的。第二种测试比较通用,用于判断浏览器是否支持DOM标准的createDocument()方法。虽然目前只有Mozilla浏览器支持这个方法,但可以预见将来会有其他的浏览器采纳这个功能,所以这样测试确保了代码是经得起未来考验的。

2IE分支

对于构造函数的IE部分,只需把本书前面的createXMLDOM()函数中的代码插进来即可:

这就是你要对IE所做的。对Mozilla则要做较复杂的事情。

3Mozilla分支

Mozilla分支的第一步是,用createDocument()方法创建XML DOM对象。

下面的任务是让Mozilla支持readyState特性以及onreadystatechange事件处理函数。这要求必须对Document类再进行一些修改。

首先,添加readyState特性,并初始化为0

下面,创建onreadystatechange特性,并初始化为null

一旦readyState特性发生变化,必须调用onreadystatechange函数。为达到这个目的,最好创建一个方法:

这个方法将新状态作为参数并将其分配给readyState特性。注意调用前要先检测onreadystatechange确实是个函数(否则会出现错误)。因为这个方法不能在Document对象外调用,所以使用了JavaScript对于私有方法的标记(前后加上两个下划线)。

IEXML DOM支持有五种状态,但不可能每种都能在Mozilla中进行模拟。其实,readyState唯一重要的值是4,它表示XML DOM已完全载入并可使用了。这个值可通过onload事件处理函数来模拟。模拟readyState 1也很容易,它表示XML DOM即将开始载入。其他状态不是特别重要,且模拟起来比较困难。

影响到readyState特性的两个方法是,loadXML()load()loadXML()方法比较容易更新,因为这是自己创建的方法。只需添加两行代码:

更新后的loadXML()方法最初将readyState设置为1,结束时将其设置为4

要更新load()方法,首先要创建指向原来方法的引用:

下面,定义新的load()方法,它先将readyState特性设置为1,然后调用原来的load()方法:

要使用onload事件处理函数适时地将readyState设置为4。因为只能在XML DOM对象被实例化之后才能分配事件处理函数,所以必须放在XmlDom构造函数中:

现在,MozillaXML DOM就能较好地支持readyState特性(仅对值014),onreadystatechange事件处理函数,loadXML()方法以及xml特性了。下面的例子可以在IEMozilla中使用:

其实,两种XML DOM处理错误的方式才是主要的区别。不过这个也可以处理好。

4.错误处理

最后一步是为Mozilla创建parseError对象。不过这次在Mozilla解析器中依然不能模拟所有的IE特性,但是却有足够的信息来解析XML以模拟大部分的IE特性。

首先,必须在XmlDom构造函数中创建这个对象并初始化所有的值:

这段代码使用对象字面量记号来创建parseError对象,节省了空间。并定义valueOf()方法返回errorCode特性,这与IE的实现一样;toString()方法也返回errorCode特性,不过是以字符串形式。initError()方法初始化所有parseError对象的特性。代码如下:

下一步是检测解析错误。必须在load()loadXML()方法中完成,因为解析错误可能发生在其中任何一个中。因为在两处重复相同的代码是种不好的编码实践,最好创建函数来处理解析错误:

注意,不管发生什么错误,errorCode都设为-999999。映射微软所有的错误代码是一项繁琐的任务,且没有什么必要。大部分情况下,只需要检查parseError是否为0,而不是某个特定的值。

下面,load()loadXML()方法必须进行更新以使用initError()(进行解析前清除所有的错误值)和checkForErrors()(解析完毕时检测有没有解析错误):

注意,initError()必须在readyState设为1之前调用。类似的,checkForErrors()也必须在readyState设为4(这就是必须在onload事件处理函数中调用的原因)之前调用。这些方法必须按顺序调用,因为每次readyState更改时都要调用onreadystatechange。如果在parseError对象中存在旧的数据,必须在调用onreadystatechange前重置,否则可能会造成混淆。在同一行上,parseError对象必须在readyState变成4后包含正确的数据,因为那时所有的处理都应该已完成了。

加入这段代码后,就可以写一段完整的可以同时在IEMozilla中处理解析错误的代码了:

这个例子载入了有错误的XML文件。readyState特性设成4时(文件载入并进行了解析)。检验parseError的值是否等于0 (代表是否有错误)。如果发生了错误,出现一个警告框,显示错误代码、行号、行位置(列号)以及错误原因。

5.完整的代码

在这一章中,开发代码时,我跳过了许多内容。下面看一下完整的代码(注意它使用了本书前面创建的浏览器检测代码):

15.2浏览器中对xpath的支持


因为XML用于处理多种数据,所以必须有一种可以在XML代码中定位数据的方式。这个问题的答案就是XPath,它是专门用于定位匹配模式的一个或多个节点的小语言。(不再细述)


15.3浏览器中对XSLT的支持

XSLT(可扩展样式表语言转换)可以对XML进行操作,将其转换成任何基于文本的形式。目前,很多开发人员都用XSLTXML转换成HTML,当然,这只是其中一种用途(见图15-1)。

XSLT文件称为样式表,由一些模板组成。模板属于XML的某个特性的一部分(使用XPath指定),它可以决定为这一部分输出什么文本。通过为不同的元素和条件定义模板,XSLT样式表变成了一种XML 解析器。例如,考虑前面用过的XML

现在假设你想将这个雇员列表按照以下的HTML格式显示:

其实,就是从内容中拉出<name/>元素的内容,然后将其放入一个无序列表中。然如要将<employee/>title特性取出,并放在<em/>元素内的名字旁边,则可以创建一个XSLT样式表:

可以看到,XSLT其实就是另一个基于XML的语言。文档元素是<xsl:stylesheet/>,它还指定了XSLT使用的版本(1.0)以及命名空间URL。缺少这个信息,XSLT处理器则无法正确使用样式表。

下面一行包含<xsl:output/>元素,它指定了输出处理的规则。对于method特性,有三种可能的值:htmlxmltext。使用html时,解析器将输出作为HTML对待,也就是说不会应用严格的XML规则;xml强制对输出应用所有的XML规则,同时text只输出包含在元素之外的内容。

下面讨论模板。第一个模板匹配了文档元素,由match= "/".;制定;/ XPath表达式总是指向文档元素。在模板中还有HTML代码,直到<xsl:apply-templates/>元素,让解析器为子节点(这是匹配所有子节点的XPath表达式)应用任何匹配模板。因为已定义了匹配这个模式的模板,所以处理继续进行。

在第二个模板中,注意<li>元素。后面紧跟着<xsl:value-of/>元素,它用于从源XML中输出一个值。select特性是另一个XPath表达式——name,指示输出<name/>元素的值(包含其中的文本)。然后,是一个逗号,然后是起始<em>标签,后面是另一个<xsl:value-of/>元素。这次,select特性指向<employee/>title特性,这样转换器就输出了title特性值。

XSLT样式表应用于XML文件时,就可以出现前面的HTML结果。尽管例子很简单,不过还是显示了XSLT的一些独特能力。

如果想学习XSLT,请参阅XSLT 2.0: Programmer’s Reference, 3rd EditionWiley 出版社ISBN 0-7645-6909-0)。

15.3.1  IE中的XSLT支持

MSXML 3.0开始,IE就完全支持XSLT 1.0了。如果你还在使用IE 5.0或者5.5,必须手工安装新版的MSXML;如果在使用IE 6.0,那么就表示你至少已经有了MSXML 3.0

最简单的进行XSLT转换的方法是,分别将XML源代码和XSLT文件载入各自的DOM,并使用特有的transformNode()方法:

这个例子中的一个DOM载入了XML,而另一个DOM载入了XSLT样式表(注意XSLT也可以载入XML DOM因为它也是一种XML格式)。然后,第三行调用文档的transformNode()方法,并将包含XSLT代码的DOM作为唯一的参数传给它。然后在变量sResult中放入转换后的文本结果。

你无需从文档层次开始转换;每一个节点都有个transformNode()方法。下面的均有效:

如果在非文档元素中调用transformNode(),则从这个点开始转换,但是XSLT样式表能访问包含这个节点的整个XML文档。

IE中使用XSLT的另外一个比较复杂的方法是,使用XSL模板和处理器。这种方法必须使用MSXML的其他几个ActiveX控件。首先,XSLT文件必须载入到一个自由线程DOM文档中(行为和普通DOM一样,但是线程是安全的)。

自由线程DOM文档建立并加载好后,必须将其分配到XSL模板中,这是另一个ActiveX对象:

然后,可以用XSL模板来创建一个XSL处理器(当然也是另一个ActiveX对象):

创建处理器后,将input特性设置为要进行转换的XML DOM节点,然后调用transform()方法:

然后从output特性中访问结果字符串:

这些代码模仿了transformNode()的功能。你肯定在想,如果两种方法都一样,为什么会有人使用XSL模板/处理器的方法。答案是处理器允许你更多地控制XSLT

例如,XSLT样式表可以接受传入的参数,并将其用作局部变量。考虑下面的样式表:

这个样式表添加了两行代码。第一行是<xsl:param/>元素,它定义了message的参数。第二行通过<xsl:value-of/>元素输出message(美元符号表示这个是局部变量,而不是特性)。

要设置message的值,可在调用transform()前使用addParameter()方法。AddParameter ()方法有两个参数,要设置的参数的名称(与<xsl:param/>中指定的一样)以及分配给它的值(一般是字符串,不过也可以是数字或者是布尔值):

为参数设置一个值后,输出就变成这样了:

可以看到,通过JavaScript传入的值正确地输出了HTML结果。这样,就可以通过加入基于参数的不同行为使样式表更加有弹性。

另一个XSL处理器的高级特性是,设置操作的模式的能力。在XSLT中,可以定义模板的模式。定义mode后,除非<xsl:apply-template />指定按照mode特性进行调用,否则模板不会运行。例如:

这个样式表定义了mode特性为"position-first"的模板(注意可以任意地命名;无任何预定义的模式)。在这个模板中,首先输出雇员的位置,然后输出雇员的名称。为使用这个模板,<xsl:apply-templates/>元素必须也将其mode设置为"position-first"。如果使用这个样式表,它的输出也与前面一样,首先显示雇员名称,然后显示位置。但是,如果用这个样式表,并使用JavaScript将模式设置为"position-first",则先输出雇员的位置:

setStartMode()方法只接受一个参数,要设置的模式。与addParameter()一样,必须在transform()之前调用.

如果要使用同一个样式表进行多次转换,则可在每次转换后重置处理器。调用reset()方法,输入和输出特性则会被清除,处理器又可以使用了。

因为处理器已经编译过XSLT样式表,这要比重复调用transformNode()快得多。

MSXML只支持XSLT 1.0MSXML的开发自从转到.NET Framework后就停止了。可能,在未来的某天,JavaScript会允许访问XMLXSL.NET对象。

15.3.2  MozillaXSLT支持

Mozilla 1.2开始,JavaScript开发人员就可用XSLTProcessor对象来进行客户端的XSLT转换了。这个对象使用Mozilla内置的XSLT处理器——Transformiix

转换过程的第一步是将XMLXSLT载入DOM

然后,创建XSLTProcessor并使用importStylesheet()方法来分配XSLT DOM

最后一步是调用transformToDocument()或者transformToFragment(),并以XML DOM为参数,最后返回结果。transformToDocument()返回的是新的DOM文档,transformTo Fragement()返回新的文档碎片,一般来说,应该使用transformToDocument()除非你想直接将结果添加到某个已经存在的文档中,后一种情况才使用transformToFragement()

使用transformToFragment(),仅传入XML DOM并将结果作为另一个完整不同的DOM

使用transformToFragment(),传入XML DOM和要添加到结果的文档。这确保了新的文档碎片在目标文档中是有效的。

在前面的例子中,处理器创建了由document对象所有的碎片。这使得碎片添加到了页面中的<div/>元素中。

XSLT的输出方法是HTML或者XML时,这些当然很有意义,但如果输出的是文本方式呢?要解决这个问题,Mozilla创建了单个元素的XML文档<transformiix:result/>,包含了所有输出的文本。所以,从XSLT文件中使用文本输出也产生有效的文档或者文档碎片。

记住这一点,就可为Mozilla创建transformNode()方法了:

这个方法是用给定的XML DOM创建结果文档。然后使用xml特性(本章前面定义的)将结果XML代码存储到sResult。然后检查代码是否包含<transformiix:result/>。如果有,则XML部分被去除(只要取出第一个大于号和最后一个小于号之间的文本)。最后,返回sResult。用这个方法,你可以创建在MozillaIE中都能使用的代码:

也可以为Mozilla中的XSLTProcessor设置XSLT参数。setParameter()方法接受三个参数:命名空间URI,参数本地名称及要设置的值。一般来说,命名空间URInull,本地名称就是参数的名称,这个方法必须在transformToDocument()或者transformToFragment()方法之前调用。

还有另外两个方法与参数有关,getParameter()removeParameter(),分别用于获取某个参数当前的值和删除参数值。它们都以一个命名空间URI(也可以为null)和参数的本地名称为参数:

这些方法不常用,主要是为了方便才提供的。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值