javascript和XML
一,浏览器对XML DOM的支持
1,DOM2级核心
var xmldom = document.implementation.createDocument("","root",null);(命名空间,元素标签,文档类型)
var child = xmldom.createElement("child");
xmldom.documentElement.appendChild(child);
检测浏览器支持情况
var hasXmlDom = document.implementation.hasFeature("XML","2.0")
2,DOMParser类型
解析XML之前,创建一个DOMParser类型,调用parserFormString(要解析的XML字符串,内容类型text/xml)方法
解析发生错误时,parseFromString()返回一个document对象,这个对象的文档元素是<parsererror>
var parser = new DOMParser(),xmldom,errors; try{ xmldom = parser.parseFormString("<root>","text/xml"); errors = xmldom.getElementsByTagName("parsererror"); if(errors.length > 0){ throw new Error("Parsing errot!"); } }catch(ex){ alert("Parsing error!"); }
3,XMLSerializer类型
XMLSerializer类型,将DOM文档序列化为XML字符串
首先创建一个XMLSerializer实例,然后将文档传人其serializerToString()方法
var serializer = new XMLSerializer();
var xml = serializer.serializerToString(xmldom);
4,IE8及之前版本中的XML、
IE是第一个支持XML的浏览器,通过ActiveX对象实现
为了便于桌面应用程序开发人员处理XML,微软创建了MSXML库
ActiveXObject类型,可以通过它创建ActiveX对象的实例,要创建一个XML文档的类型,要使用ActiveXObject构造函数,传人一个表示XML文档版本的字符串
有六种不同的XML文档版本可以供选择
Microsoft.XmlDom:最初随同IE发布,不建议使用
MSXML2.DOMDocument:为方便脚本处理更新的版本,建议在特殊情况下作为后备版本
MSXML2.DOMDocument.3.0:在Javascript中使用,是最低的建议版本
MSXML2.DOMDocument.4.0:通过脚本处理时不可靠,可能导致安全警告
MSXML2.DOMDocument.5.0:通过脚本处理时不可靠,可能导致安全警告
MSXML2.DOMDocument.6.0:通过脚本能够可靠处理的最新版本
function createDocument(){ if(typeof argument.callee.activeXString != "String"){ var versions = ["MSXML2.DOMDocument.6.0","MSXML2.DOMDocument.3.0","MSXML2.DOMDocument"],i,len; for(i=0,len=versions.length;i<len;i++){ try{ new ActiveXObject(versions[i]); argument.callee.activeXString = versions[i]; }catch(ex){ //跳过 } } } return new ActiveXObject(argument.callee.activeXString); }
要解析XML字符串,首先创建一个DOM文档,然后调用loadXML()方法,新创建的XML文档为空,不能操作,
为loadXML()方法传人XML字符串解析之后会被填充到DOM文档中,
var xmldom = createDocument();
xmldom.loadXML("<root><child /></root>");
如果解析过程出错,在parseError属性中找到错误消息,属性本身包含多个属性对象,如下
errorCode:错误类型的数值编码,没有错误时为0,值可以为正负
filePos:文件中导致错误发生的位置
line:发生错误的行
linepos:发生错误的行中的字符
reason:对错误的文本解释
srcText:导致错误的代码
url:导致错误的文件的URL
parseError的valueOf()返回errorCode的值
在调用loadXML()之后,查询XML文档之前,检测是否发生了错误
1,序列化XML
每个DOM节点都有一个xml属性,保存着表示该节点的XML字符串
2,加载XML文件
IE中的XML文档对象也可以加载来自服务器的文件,指定加载文档的方式,asyns属性,true表示异步加载,false表示同步加载
var xmldom = createDocument();
xmldom.async = false;
加载了XML文档之后,调用load()可以启动下载过程,接收一个参数即要加载的XML文件的URL,同步方式下,调用load后立即检测解析错误并执行相关XML处理
var xmldoe = createDocument();
xmldom.async = false;
xmldom.load("example.xml");
if(xmldom.parseError != 0){
//处理错误
}else{
//处理xml外部文档
}
异步加载XML文件情况下,为XML DOM文档的onreadystatechange事件指定处理程序,4个就绪状态
1,DOM正在加载数据,2DOM已经加载完数据,3DOM可以使用,但某些部分还无法访问,4DOM完全可以使用
var xmldom = createDocument(); xmldom.asyns = true; xmldom.onreadystatechange = function(){ if(xmldom.readyState == 4){ if(xmldom.parseError != 0 ){ //处理xmldom文档中错误 }else{ //处理xmldom文档 } } }; xmldom.onload("example.xml");
5,跨浏览器处理XML
解析XML而言
function parseXml(xml){ var xmldom = null; if(typeof DOMParser != "undefined"){ xmldom = (new DOMParser()).parseFormString(xml,"text/xml"); var errors = xmldom.getElementsByTagName("parsererror"); if(errors.length){ throw new Error("XML parseing error:" + errors[0].textContent); } }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(typeof xmldom.xml != "undefined"){ return xmldom.xml; }else{ throw new Error("Could not serialize XML DOM."); } }
二,浏览器对XPath的支持
1,DOM3级XPath
XPath是设计用来在DOM文档中查找节点的一种手段
DOM3定义了在DOM中对XPath表达式求值的接口
var supportsXPath = document.implementation.hasFeature("XPath","3.0");
XPathEvaluator类型,用于特定的上下文中对XPath表达式求值,有3个方法
createExpression(expression,nsresolver)将XPath表达式及相应的命名空间信息转换成一个XPathExpression,多次使用同一个查询时有用
createNSResolver(node),根据node的命名空间信息创建一个新的XPathNSResolver对象,基于使用命名空间XML文档求值时,需要使用 XPathNSResolver对象
evaluate(expression,context,nsresolver,type,result),给定的上下文中,基于特定的命名空间信息对XPath表达式求值,剩下的参数指定如何返回结果
expression为XPath表达式,contenxt为上下文节点,nsresolver为命名空间求解器只在XML代码中使用了XML命名空间时有必要指定,没有命名空间 时指定为null,type为结果类型取值如下
XPathResult.ANY_TYPE:返回与XPath表达式匹配的数据类型
XPathResult.NUMBER_TYPE:返回数值
XPathResult.STRING_TYPE:返回字符串值
XPathResult.BOOLEAN_TYPE:返回布尔值
XPathResult.UNORDERED_NODE_ITERATOR_TYPE:返回匹配的节点集合,但集合中节点的次序不一定与文档中一致
XPathResult.ORDERED_NODE_ITERATOR_TYPE:返回匹配的节点集合,次序与文档中一致
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:返回节点集合的快照,在文档外部捕获节点,对文档的后续操作不会影响这个节点集合, 集合的节点次序与文档中不一定一致
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:返回节点集合的快照,次序一致,其余同上
XPathResult.ANY_UNORDERED_NODE_TYPE:返回匹配的节点集合,集合节点中的次序不一定与他们在文档中一致
XPathResult.FIRST_ORDERED_NODE_TYPE:返回只包含一个节点的节点集合,包含的这个节点就是文档中第一个匹配的节点
var result = xmldom.evaluate("employee/name",xmldom.documentELement,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null); if(result != null){ var node = result.iterateNext(); while(node){ alert(node.tagName); node = node.iterateNext(); } }
返回结果为XPathResult.ORDERED_NODE_ITERATOR_TYPE,是常用的返回类型,没有节点匹配XPath表达式,返回null,否则返回XPathResult对象
返回的XPathResult对象带有属性和方法,如果节点时节点迭代器与次序无关,要使用iterateNext()从节点中取得匹配的节点,没有更多的匹配节点时,返回null
如果指定的快照结果类型,使用snapshotItem()方法(快照中给定位置的节点)和snapshotLength属性(快照中节点的数量)
var result = xmldom.evaluate("employee/name",xmldom.documentElement,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE.null);
if(result != null){
for(var i=0,len=result.snapshotLength;i<len;i++){
alert(result.snapshotItem(i).tagName);
}
}
1)单节点结果
指定常量XPathResult.FIRST_ORDERED_NODE_TYPE:返回匹配的第一个节点
通过singleNodeValue属性来访问该节点
var result = xmldom.evaluate("employee/name",xmldom.documentElement,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null);
if(result != null){
alert(result.singliNodeValue.tagName);
}
2)简单类型结果
通过XPathResult的布尔值,数值,和字符串值可以取得简单的非节点的数据类型
对于XPathResult.BOOLEAN_TYPE,有返回值为true,无返回值为false
对于XPathResult.NUMBER_TYPE,必须在XPath表达式参数的位置上指定一个能够返回数值的XPath函数,没有匹配返回NaN
var Result = xmldom.evaluate("count(employee/name)",xmldom.documentElement,null,XPathResult.NUMBER_TYPE,null);
对于字符串类型,查找与XPath表达式匹配的第一个节点,返回第一个子节点的值,没有匹配返回空字符串
3)默认类型结果
使用XPathResult.ANY_TYPE会自动返回结果的类型,确定返回的是什么结果,通过检测resultType属性
4)命名空间支持
对于利用了命名空间的XML,XPathEvaluator必须知道命名空间的信息
处理命名空间的一种方法是通过createNSResolver()创建XPathNSResolver对象,接收一个参数就是包含命名空间定义的节点,传人到evaluate方法中
处理命名空间的另一种方法是定义一个函数,让它接收一个命名空间前缀,返回关联的URL
var nsresolver = function(prefix){
switch(prefix){
case "wrox":return "http://www.wrox.com/"
}
};
传人evaluate方法中
2,IE中的XPath
IE对XPath的支持是内置在基于ActiveX的XMLDOM文档对象中的,没有使用DOMParser返回的DOM对象
使用XPath必须基于ActiveX的实现,这个接口在每个节点上额外定义了两个方法
selectSingleNode(),接受一个XPath模式,在找到匹配节点时返回第一个匹配的节点,没有匹配返回null
selectNodes(),接受一个XPath模式,返回与模式匹配的所有节点的NodeList,没有匹配,返回包含零项的NodeList
IE中处理包含命名空间的XPath表达式,必须知道自己使用的命名空间,按照下列格式创建一个字符串
"xmlns:prefix1='uri1' xmlns='uri2' xmlns='uri3'"
将这个字符串传人到XMLDOM文档对象的特殊方法setProperty(属性名,属性值)中,属性名为SelectionNamespaces,属性值就是按照前面格式创建的字符串
xmldom.setProperty("SelectionNamespaces","xmlns:wrox='http://www.wrox.com/'");
var result = xmldom.documentElement.selectNodes("wrox:book/www:author");
3,跨浏览器使用XPath
selectSingleNode(上下文节点,XPath表达式,命名空间对象)
function selectSingNode(context,expression,namespaces){ var doc = (context.nodeType != 9 ?context.ownerDocument:context); if(typeof doc.evaluate != "undefined"){ var nsresolver = null; if(namespaces instanceof Object){ nsresolver = function(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.hasOwnerProperty(prefix)){ ns += "xmlns:" + prefix + "= '" + namespaces[prefix] + "' "; } } doc.serProperty("SelectionNamespaces",ns); } return context.selectSingleNode(expression); }else{ throw new Error("No XPath engine found."); } }
selectNodes()函数,
function selectNodes(context,expression,namespaces){ var doc = (context.nodeType != 9? context.ownerDocument: context) if(typeof doc.evaluate != "undefined"){ var nsresolver = null; if(namespaces instanceof Object){ nsresolver = function(prefix){ return namespaces[prefix]; }; } var result = doc.evaluate(expression,context,nsresolver,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); var nodes = new Array(); if(result !== null){ for(var i=0,len=result.snapshotLength;i<len;i++){ nodes.push(result.snapshotItem(i)); } } return nodes; }else if(typeof context.selectNodes != "undefined"){ if(namespaces instanceof Object){ var ns = ""; for(var prefix in namespace){ if(namespace.hasOwnProperty(prefix)){ ns += "xmlns:" + prefix + "=' + namespaces[prefix] + '" "; } } doc.serProperty("SelectionNamespaces",ns); } var result = context.selectNodes(expression); var nodes = new Array(); for(var i=0,len=result.length;i<len;i++){ nodes.push(result[i]); } return nodes; }else{ throw new Error("no Xpath engine found."); } }
三,浏览器对XSLT的支持
1,IE中的XSLT
1)简单的XSLT转换
使用XSLT样式表转化XML文档的最简单的方法,是将他们分别放在一个DOM文档中,然后使用transformNode()方法
这个方法存在于所有节点中,接收一个参数,包含XSLT样式表的文档,返回一个包含转换信息的字符串
xmldom.load("employees.xml");
xsltdom.load("employees.xslt");
var result = xmldom.transformNode(xsltdom);
可以在文档的任何级别上进行转换
2)复杂的XSLT转换
使用XSL模板和XML处理器,第一步是把XSLT样式表加载到一个线程安全的XML文档中,通过使用ActiveX对象MSXML2.FreeThreadedDOMDocument来做
创建线程安全的XML DOM,即ActiveX对象,与常规的DOM支持相同的接口
function createThreadSafeDocument(){ if(typeof argument.callee.activeXString != "string"){ var verions = ["MSXML2.FreeThreadedDOMDocument.6.0","MSXML2.FreeThreadedDOMDocument.3.0","MSXML2.FreeThreadedDOMDocument"],i,len; for(i=0,len=versions.length;i<len;i++){ try{ new ActiveXObject(versions[i]); argument.callee.activeXString = versions[i]; break; }catch(ex){ //跳过 } } } return new ActiveXObject(arguments.callee.activeXString); } var xsltdom = createThreadSafeDocument(); xsltdom.async = false; xsltdom.load("employee.xslt");
创建并加载了自由线程的DOM之后,必须将它指定给一个XSL模板,这也是一个ActiveX对象,这个模板用来创建XSL处理对象的,后者用来转换XML文档
function createXSLTemplate(){ if(typeof argument.callee.activeXString != "string"){ var versions = ["MSXML2.XSLTemplate.6.0","MSXML2.XSLTemplate.3.0","MSXML2.XSLTemplate"],i,len; for(i=0,len=versions.length;i<len;i++){ try{ new ActiveXObject(versions[i]); argument.callee.activeXString = version[i]; break; }catch(ex){ //跳过 } } } return new ActiveXObject(arguments.callee.activeXString); } var template = createXSLTemplate(); template.stylesheet = xsltdom; var proccessor = template.createProcessor(); processor.input = xmldom; processor.transform(); var result = processor.output;
transform方法可执行转换并将结果作为字符串保存在output属性中
XSLT样式表可以接受传人的参数,并将其用作局部变量
processor.input = xmldom.documentElement;
processor.addParameter("message","hello");
processor.transform();
XSL处理器能够设置一种操作模式,可是使用mode特性为模板定义一种模式,
processor.input = xmldom;
processor.addParameter("message","hellp");
processor.setStartMode("title-first");
processor.transform();
如果打算使用同一样式表进行多次转换,可以在转换之后重置处理器,调用reset()方法
会清除原先的输入和输出属性,启动模式以及其他指定的参数,
2,XSLTProcessor类型
可以通过XSLTProcessor类型,使用XSLT转换XML文档
与IE类似,第一步加载两个DOM文档,一个基于XML,一个基于XSLT,然后创建XSLTProcessor对象,
指定importStyleSheet()方法为其指定一个XSLT,
var processor = new XSLTProcessor();
processpr.importStyleSheet(xsltdom);
最后一步执行转换,想返回完整的DOM文档,使用transformToDocument(),想返回一个文档对象片段,使用transformToFragment(),将返回的结果添加 到另一个DOM文档中
XSLT样式表在输出格式为XML或HTML时,没有问题,当格式为text时,浏览器支持情况不同,这时使用transformToFragment()
var fragment = processpr.transformToFragment(xmldom,document);
var text = fragment.firstChild.nodeValue;
alert(text);
1)使用参数
XSLTProcessor类型通过serParameter()设置XSLT的参数,命名空间URL,参数内部名称,要设置的值
要在调用transformToDocument(),transformToFragment()之前调用
var processor = new XSLTProcessor();
processor.importStyleSheet(xsltdom);
processor.setParameter(null,"message",null);
var result = processor.transformToDocument(xmldom);
getParameter()取得当前参数的值,(命名空间(一般为null),参数的名称)
removeParameter()移除当前参数的值(命名空间(一般为null),参数的名称)
2)重置处理器
processor.reset()
移除所有参数和样式,可以再次调用importStyleSheet()
3,跨浏览器使用XSLT
function transform(context,xslt){ if(typeof XSLTProcessor != "undefined"){ var processor = new XSLTProcessor(); processor.importStylesheet(xslt); var result = processor.transformToDocument(context); return (new XMLSerializer()).serializeToString(result); }else if(typeof context.transformNode != "undefined"){ return context.transformNode(xslt); }else{ throw new Error("No XSLT processor available"); } } var result = transform(xmldom,xsltdom);