JavaScript高级程序设计 XML、Ajax 学习笔记(3)

②加载文档的方式也可以分为同步和异步两种。要指定加载文档的方式,可以设置async属性,true表示异步(默认),false表示同步。使用load(URI)方式加载。

③异步加载XML,需为XML DOM文档的onreadystatechange事件指定处理程序。有4个就绪状态(ready state)

□1:DOM正在加载数据。

□2:DOM已经加载完数据。

□3:DOM已经可以使用,但某些部分可能还无法访问。

□4:DOM已经完全可以使用。

□实际上,只需要关注状态4。通过XML文档的readyState属性可得其就绪状态。

var xmldom = createDocument();

xmldom.async = true;

xmldom.onreadystatechange = function(){

if(xmldom.readyState == 4){

if(xmldom.parseError != 0){

Alert("An error occurred");

}else{

//其他xmldom操作

}

}

}

xmldom.load("exmaple.xml");

注:

□onreadystatechange事件指定处理语句须在调用load()方法之前。

□在事件处理内部由于ActiveX控件为预防错误,不允许使用this。

1.6 跨浏览器处理XML

function parseXML(xml){

var xmldom = null;

if(typeof DOMParser != "undefined"){

xmldom = (new DOMParser()).parseFromString(xml,"text/xml");

var errors = xmldom.getElementsByTagName("parsererror");

if(errors.length){

throw new Error("XML parsing error:" + errors[0].textContent);

}

}else if(document.implementation.hasFeature("LS","3.0")){

var implementation = document.implementation;

var parser = implementation.createLSParser(implementation.MODE_SYNCHRONOUNS,null);

var input = implementation.createLSInput();

input.stringData = xml;

xmldom = parser.parse(input);

}else if(typeof ActiveXObject != "undefined"){

xmldom = createDocument();

xmldom.loadXML(xml);

if(xmldom.parseError != 0){

throw new Error("XML parsing error:" + xmldom.parseError.reason);

}

}else{

throw new Error("No XML parser available.");

}

return xmldom;

}

用此函数解析XML字符串时,应该放在try-catch语句中

var xmldom = null;

try{

xmldom = parseXml("<root><child/><root>");

}

catch(ex){

alert(ex.message);

}

■序列化XML兼容代码

function serializeXml(xmldom){

if(typeof XMLSerializer != "undefined"){

return(new XMLSerializer()).serializeToString(xmldom);

}else if(document.implementation.hasFeature("LS","3.0")){

var implementation = document.implementation;

var serializer = implemetation.createLSSerializer();

return serializer.writeToString(xmldom);

}else if(typeof xmldom.xml != "undefined"){

return xmldom.xml;

}else{

throw new Error("Could not serialize XMLDOM.");

}

}

2.浏览器对XPath的支持

2.1 DOM3级Xpath

①DOM3级支持XPath,检测浏览器支持:

Var supportsXPath = document.implementation.hasFeature("XPath","3.0");

②DOM3级XPath中最重要的两个类型:XPathEvaluator和XPathResult。

③XPathEvalutor用于特定的上下文中队XPath表达式求值。有3个方法:

□createExpression(expression,nsresolver):将XPath表达式及相应的命名空间信息转换成一个XPathExpression,这是查询的编译版。在多次使用一个查询时很有用。

□createNSResolver(node):根据node的命名空间信息创建一个新的XPathNSResolver对象。在基于使用命名空间的XML文档求值时,需要使用XPathNSResolver对象。

□evaluate(expression,context,nsresolver,type,result):在给定的上下文中,基于特定的命名空间信息来对XPath表达式求值。剩下的参数表示如何返回结果。

□在支持DOM3级的浏览器中,Document类型通常都是与XPathEvaluator接口一起实现的。

④上面3个方法中,evalute最常用。接受5个参数:

□XPath表达式

□上下文节点

□命名空间解析器(只在XML代码中使用了XML命名空间时有必要指定,否则为null)

□返回结果的类型(见书P415)

□保存结果的XPathResult对象(通常是null,因为结果也会以函数值形式返回)

■返回结果类型为以下的其中一个:

◇XPathResult.ANY_TYPE

◇XPathResult.NUMBER_TYPE

◇XPathResult.STRING_TYPE

◇XPathResult.BOULEAN_TYPE

◇XPathResult.UNORDER_NODE_ITERATOR_TYPE

◇XPathResult.ORDERED_NODE_SNAPSHOT_TYPE

◇XPathResult.ANY_UNORDERED_NODE_TYPE

◇XPathResult.FIRST_ORDERED_NODE_TYPE

1)指定的是迭代器结果,须用iterateNext()方法从节点中取得匹配节点,无则返回null。

var result = xmldom.evalute("employee/name",xmldom.document,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);

if(result !== null){

var node = result.iterateNext();

while(node){

alert(node.tagName);

node = node.iterateNext();

}

}

2)指定的是快照类型,就必须使用snapshotItem()和snapshotLength属性。

1.单节点结果

指定常量XPathResult.FIRST_ORDER_NODE.TYPE会返回第一个匹配节点,可通过singleNodeValue属性来访问该节点。

2.简单类型结果

booleanValue、numberValue和stringValue

3.默认类型结果

4.命名空间支持

□对于利用了命名空间的XML文档,XPathEvaluator必须知道命名信息,然后才能正确地进行求值。

□第一种方法是通过createNSResolver()来创建XPathNSResolver对象,这个方法接受一个参数,即文档中包含命名空间定义的节点。

Var nsresolver = xmldom.createNSResolver(xmldom.documentElement);

Var result = xmldom.evaluate("wrox:book/wrox:author",xmldom.document,nsresolver,XPathResult.ORDERED_NODESNAPSHOTTYPE,null);

Alert(result.snapshotlength);

□第二种方法是定义一个函数,让它接受一个命名空间前缀,返回关联的URI。

Var nsresolver = function(prefix){

Switch(prefix){

Case "wrox" : return "http://www.wrox.com/";

//其他前缀

}

};

Var result = xmldom.evaluate("count(wrox:book/wrox:author)",xmldom.document,nsresolver,XPathResult.NUMBER_TYPE,null);

2.2 IE中的XPath

①IE对XPath的支持是内置在XML DOM文档对象中的。含有两个方法。

□selectSingleNode()方法接受一个XPath模式,在找到匹配节点时返回第一个匹配的节点。

var element = xmldom.documentElement.selectSingleNode("employee/name");

□selectNodes(),接受一个XPath模式作参数,返回与模式匹配的所有节点的NodeList(如果没有匹配的节点,则返回一个包含零项的NoedList)。

Var elements = xmldom.documentElement.selectNodes("employee/name");

Alert(elements.length);

②IE对命名空间的支持

□必须知道自己使用的命名空间,并按格式创建一个字符串:

"xmlns:prefix1 = 'uri1' xmlns:prefixf2 = 'uri2' xmlns:prefix3:'uri3' "

□将上述格式字符串传入到XML DOM文档对象的特殊方法setProperty()中。

□setProperty()接受两个参数:要设置的属性名和属性值。这里属性名应为"SelectionNameSpaces",属性值是前面格式的字符串。

xmldom.setProperty("selectionNameSpaces","xmlns:wrox = ");

var result = xmldom.documentElement.selectNodes("wrox:book/wrox:author");

2.3 跨浏览器使用XPath

□selectSingleNode()函数兼容代码

function selectSingleNode(context,expression,namespace){

var doc = (context.nodeType != 9 ? context.ownerDocument : context);

if(typeof doc.evaluate != "undefined"){

var nsresolver = null;

if(namespace instanceof Object){

nsresolver = fucntion(prefix){

return namespaces[prefix];

};

}

var result = doc.evaluate(expression,context,nsresolver,XPathResult.FIRST_ORDERED_NODE_TYPE,null);

return(result !== null ? Result.singleNodeValue : null);

}else if(typeof context.selectSingleNode != "undefined"){

//创建命名空间字符串

if(namespaces instanceof Object){

var ns = "";

for(var prefix in namespaces){

if(namespaces.hasOwnproperty(prefix)){

ns += "xmlns:" + prefix + "='" + namespaces[prefix] + "' ";

}

}

doc.setProperty("SelectionNamespaces",ns);

}

return context.selectSingleNode(expression);

}else{

throw new Error("No Xpath engine found.");

}

}

□selectNodes()函数兼容代码

P420略

3.函数对XSLT的支持

XSLT是与XML相关的一种技术,它利用XPath将文档从一种表现形式转换成另一种表现形式。

3.1 IE中的XSLT转换

1.简单的XSLT转换

□最简单方法:XSLT、XML分别加载到一个DOM文档中,再使用transformNode()方法。

□transformNode()方法:只有一个参数——包含XSLT样式表的文档。返回一个包含转换信息的字符串。

□可在xmldom各个节点机型转换。

//加载xmldom各个节点进行转换

xmldom.load("employees.xml");

xsltdom.load("employees.xslt");

//转换

var result = xmldom.transformNode(xsltdom);

2.复杂的XSLT转换

①基本原理:

a.将xml加载到“线程安全的XML DOM”中。

b.将XSLT加载到“XSL模板”中

c.使用“XSL处理器”进行转换。

□自由线程DOM:MSXML2.FreeThreadedDOMDocument

□XSL模板:MSXML2.XSLTemplate

□XSL处理器:调用XSL模板的createProcessor()创建XSL处理器。

②把XSLT样式表加载到一个线程安全的XML文档中。

function createThreadSafeDocument(){

if(typeof arguments.callee.activeXString != "string"){

var versions = ["MSXML2.FreeThreadedDOMDocument.6.0","MSXML2.FreeThreadedDOMDocument.3.0","MSXML2.FreeThreadedDOMDocument\"];

for(var i=0,len = version.length; i<len; i++){

try{

var xmldom = new ActiveXObject(versions[i]);

arguments.callee.activeXString = versions[i];

return xmldom;

}catch(ex){

// 跳过

}

}

}

return new ActiveXObject(arguments.callee.activeXString);

}

□线程安全的XML DOM与常规XML DOM使用方式一致。

var xsltdom = createThreadSafeDocument();

xsltdom.async = fasle;

xsltdom.load("employee.xslt");

③为自由线程DOM指定XSL模板

fucntion createXSLTemplate(){

if(typeof arugments.callee.activeXString != "string"){

var versions = ["MSXML2.XSLTemplate.6.0","MSXML2.XSLTemplate.3.0","MSXML2.XSLTemplate"];

for(var i=0,len=versions.length;i<len;i++){

try{

var template = new ActiveXObject(versions[i]);

arguments.callee.activeXString = version[i];

return template;

}catch(ex){

//跳过

}

}

}

return new ActiveXObject(arguments.callee.activeXString);

}

□使用createXSLTemplate()函数创建用法:

var template = createXSLTemplate();

template.stylesheet = xsltdom;

var processor = template.createProcessor();

processor.input = xmldom;

processor.transform();

var result = processor.output;

④创建XSL处理器之后,须将要转换的节点指定给input属性。然后,调用transform()方法执行转换并将结果左字符串保存在output属性中。

⑤使用XSL处理器可以对转换进行更多的控制,同时也支持更高级的XSLT特性。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdjpwj.html