javascript XML详解

要检测浏览器是否支持DOM2级的XML,可以使用以下的代码:
var hasXmlDom=document.implementation.hasFeature("XML","2.0");

DOMParser类型
var parser=new DOMParser();
var xmldoc=parser.parseFormString("<root><child/></root>","text/html");
xmldoc.documentElement.tagName;//root
xmldoc.documentElement.firstChild.tagName;//child
var children=xmldoc.getElementsByTagName("child");
DOMParser只能解析格式良好的XML文档,因此解析的文档要有一定的要求。因此在解析文档时用try-catch进行处理

XMLSerializer类型
将DOM文档序列化为XML字符串。
var serializer=new XMLSerializer();
var xml=serializer.serializeToString(xmldom);
序列化后的字符串并不适合打印,但是它可以序列化任何有效地DOM对象,也包括HTML文档。序列化后的文档是格式良好的。

IE创建XML解析对象
function createDocument(){
if(typeof arguemnts.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]);
arguments.callee.activeXString=versions[i];
break;
}catch(ex){  }
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
解析XML文档的方法是loadXML()方法。解析过程出错,可以查看parseError属性,在其中找到错误信息。可以通过下面的代码找到错误:
if(xmldom.parseError!=0){
  // 添加处理错误的代码
}
应该在调用了loadXML之后,查询XML文档之前检查是否发生了解析错误。
IE将序列化XML的能力内置在了DOM文档中,每个DOM节点都内置了一个xml属性,保存着该节点的XML字符串。
IE中的XML文档对象也可以加载来自服务器的文件。要加载的XML文档必须与页面中运行的js代码来自同一台服务器。加载文档的方式分为两种,同步和异步,设置async属性为true时,表示异步,false时表示同步。在确定了文档的加载方式后,调用load()可以启动下载过程。这个方法接收一个参数,即要加载的XML文档的URL。在同步方式下,调用load()之后可以立即检测解析错误并执行相关的XML处理。
var xmldoc=createDocument();
xmldoc.async=false;
xmldoc.load("example.xml");

if(xmldoc.parseError!=0){
    //处理错误
}else{
alert(xmldoc.xml);
}
虽然同步加载的方式比较简便,但是时间过长。因此在加载过程中,多采用异步加载的方式。
var xmldoc=createDocument();
xmldoc.async=true;

xmldoc.onreadystatechange=function(){
if(xmldoc.readyState==4){
 if(xmldoc.parseError!=0){
//处理错误
}else{
alert(xmldoc.xml);
}
}
};
xmldoc.load("example.xml");
ActiveX控件为了预防安全问题,不允许使用this对象。

跨浏览器处理XML
解析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(typeof ActiveXObject!="undefined"){
  xmldom=createDocument();
  xmldom.load(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的字符串,返回DOM结构的XML。
对于序列化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的支持
XPath是设计用来在DOM文档中查找节点的一种手段,因而对XML的处理也很重要。很多浏览器实现了这个标准,IE有自己的实现方式。

DOM3级XPath
下面的代码是用来检测浏览器是否支持DOM3级的XPath:
var supportsXPath=document.implementation.hasFeature("XPath","3.0");
在DOM3级的XPath规范定义的类型中,最重要的两个类型是XPathEvaluator和XPathResult 。XPathEvaluator用在特定的上下文中对XPath表达式的求值。这个类型由三个方法:
createExpression(expression,nsresolver):将XPath表达式及相应的命名空间信息转化成一个XPathExpression,这是查询的编译版。在多次使用同一个查询时很有用。
createNSResolver(node):根据node的命名空间信息创建一个新的XPathNSResolver对象。在基于使用命名空间的XML文档求值时,需要使用XPathNSResolver对象。
evaluate(expression.context,nsresolver,type,result):在给定的上下文中基于特定的命名空间信息来对XPath求值,剩下的参数指定如何返回结果。
这几个方法中,evaluate方法最常用。这个方法接收5个参数:XPath表达式,上下文节点,命名空间求解器,返回结果的类型和保存结果的XPathResult对象(通常是null,因为结果会以函数值的形式返回)。第三个参数宅在XML代码中使用了XML命名空间时有必要指定,如果没使用,设置为null。第四个参数的的取值范围是下列的常量之一:
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.ORDERD_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();
   }
}
如果指定的是快照结果类型,就必须使用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); 
 }
}
单节点的结果可以通过singleNodeValue属性来访问该节点。
简单类型的结果分别会通过booleanValue,numberValue,stringValue来访问。
对使用命名空间的XML求值的方法:
1.通过createNSResolver(node)方法来创建XPathNSResolver对象,然后再使用evaluate()方法来获取结果
var nsresolver=xmldom.createNSResolver(xmldom.documentElement);
var result=xmldom.evaluate("wrox:book/wrox:author",xmldom.documentElement,nsresolver,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);
alert(result.snapshotLength);
2.定义一个函数,让它接收一个命名空间前缀,返回关联的URI
var neresolver=function(prefix){
    switch(prefix){
  case "wrox": return "http://www.wrox.com/";
  //其他前缀
}
}
var result=xmldom.evaluate("count(wrox:book/wrox/author)",xmldom.documentElement,nsresolver,XPathResult.NUMBER_TYPE,null);
alert(result.numberValue);

IE中的XPath
IE对XPath的支持是内置在基于ActiveX的XML DOM文档对象中的。在这个操作XPath的接口中有两个方法:selectSingleNode()和selectNodes()。其中selectSingleNode()方法接收一个XPath模式,在找到的匹配中返回第一个匹配节点,如果没有返回null。
var element=xmldom.documentElement.selectSingleNode("employee/name");
if(element!=null){
   alert(element.xml);
}
另一个方法selectNodes()也接收一个XPath模式,但是它返回与模式匹配的所有节点的NodeList。如果没找到匹配的,返回一个包含零项的NodeList.
var elements=xmldom.documentElement.selectNodes("employee/name");
alert(elements.length);

IE对命名空间的支持
下面是对要操作的XML DOM设置命名空间的方法:
xmldom.setproperty("SelectionNamespaces","xmlns='http://www.wrox.com/'");
var result=xmldom.documentElement.selectNodes("wrox:book/wrox:author");
alert(result.length);

跨浏览器使用XPath
第一个跨浏览器的方法是selectSingleNode(),接收三个参数:上下文节点,XPath表达式,可选的命名空间
function selectSingleNode(context,expression,namespace){
   var doc=(context.nodeType!=9?context.ownerDocument:context);
   if(typeof doc.evaluate!="umdefined"){
  var nsresolver=null;
  if(namespace instanceof Object){
 nsresolver=function(prefix){
    return namespace[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(namespace instanceof Object){
var ns="";
for(var prefix in namespace){
   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");   
   }
}
下面是这个函数的使用示例:
var result=selectSingleNode(xmldom.documentElement,"wrox:book/wrox:author",{wrox:"http://www.wrox.com/"});
alert(serializeXml(result));

下面的函数是跨浏览器封装的selectNodes()函数,这个函数接收与上一个函数有相同的三个参数。
function selectNodes(context,expression,namespace){
   var doc=(context.nodeType!=9?context.ownerDocument:context);
   if(typeof doc.evaluate!="umdefined"){
  var nsresolver=null;
  if(namespace instanceof Object){
 nsresolver=function(prefix){
    return namespace[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.selectSingleNode!="undefined"){
  if(namespace instanceof Object){
var ns="";
for(var prefix in namespace){
   if(namespace.hasOwnProperty(prefix)){
  ns+="xmlns:"+prefix+"='"+namespaces[prefix]+"' ";   
   }
    }
doc.setProperty("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");   
   }
}
下面是selectNodes()方法的使用示例:
var result=selectNodes(xmldom.documentElement,"wrox:book/wrox:author",{wrox:"http://www.wrox.com/"});
alert(result.length);

浏览器对XSTL的支持
它不是一种正式的规范,,是XPath的另一表现形式。IE是第一个支持它的。
简单的XSTL转换XML文档的方式就是将它们分别加到一个DOM文档中,然后使用transformNode()方法。这个方法接收一个参数,即包含XSTL样式表的文档。调用这个方法之后会返回一个包含转换信息的字符串。
xmldom.load("employees.xml");
xstldom.load("employees.xstl");

var result=xmldom.transformNodes(xstldom);
这个transformNode的参数可以是XML文档的DOM节点。如果不是在文档元素上调用transformNode,那么转换就会从调用节点上开始。
复杂的XSTL转换
要使用复杂的XSTL转换,必须使用XSL模板和XSL处理器。先要把XSTL样式表加载到一个线程安全的XML文档中。
function createThreadSafeDocument(){
    if(typeof arguments.callee.activeXString!="string"){
   var versions=["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]);
  arguments.callee.activeXString=versions[i];
  break;
   }catch(ex){
 //skip   
   }   
   }
}
return new ActiveXObject(arguments.callee.activeXString);
}
创建XSTL模板:
function createXSTLTemplate(){
    if(typeof arguments.callee.activeXString!="string"){
    var versions=["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]);
  arguments.callee.activeXString=versions[i];
  break;
  }catch(ex){
//skip   
  }
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
下面是使用示例:
var xsltdom=createThreadSafeDocument();
xstldom.async=false;
xsltdom.load("employees.xslt");

var template=createXSTLTemplate();
template.stylesheet=xstldom;

var processor=tempalte.createProcessor();
processor.input=xmldom;
processor.transform();
var result=processor.output;
在创建了XSL处理器之后,必须将要转换的节点指定给input属性。这个值可以是一个文档,也可以是文档的任何节点。然后调用transform方法即可执行转换并将结果作为字符串保存在output属性中。这些代码实现了transformNode相同的功能。使用XSL处理器可以对转换进行更多的控制,同时也支持更高级的XSTL特性。
要将样式表中的参数进行赋值处理,可以使用addParaneter()方法,它接收两个参数:要设置的参数名称和要指定的值。
processor.input=xmldom.documentElement;
processor.addParameter("message","Hello wrold!");
processor.transform();
XSL处理器的另一个高级特性是能够设置一种操作模式。在XSTL中,可以使用mode特性为模板定义一种模式在定义了模式之后,如果没有将<xsl:apply-tempaltes>与匹配的mode特性一起使用,就不会运行该模板。如果在<xsl:apply-tempaltes>元素的模式设置为“title-first”,那么在javascript使用时就需要像下面这样进行设置:
processor.input=xmldom;
processor.addParameter("message","Hello wrold!");
processor.setStartMode("title-first");
processor.transform();
如果打算用一个XSTL样式表进行多次转换,可以在每次转换之后调用reset()方法重置处理器。
processor.reset();
因为处理器已经编译了XSTL样式表,与transformNode()相比,这样的转换速度会更快一些

XSLTProcessor类型
Mozilla通过火狐创建新类型,其他非IE浏览器借鉴了它,也实现了这个类型。主要的功能是用来将XSLT转换为XML文档。
第一步加载DOM文档,一个基于XML,另一个基于XSLT。然后创建一个新XSLTProceesor对象,并使用importStylesheet()方法为其指定一个XSLT。示例:
var processor=new XSLTProcessor();
processor.importStylesheet(xsltdom);
最后一步是执行转换。这一步有两种不同的方式:如果想返回一个完整的DOM文档,可以调用transformToDocument();如果想返回一个文档片段,可以使用transformToFragment()。transformToDocument()的参数是一个XML DOM。transformToFragment()的参数有两个,第一个是XML DOM,第二个是拥有该文档片段的文档。
setParameter()方法可以用来设置XSLT的参数,该方法接收三个参数:命名空间URI,参数的内部名称和要设置的值。这个方法必须在进行最后一步转化之前调用。
getParameter()方法用于取得当前参数的值,参数为命名空间URI和参数的内部名称。
removeParameter()方法用于移除当前参数的值,参数为命名空间URI和参数的内部名称。
后面两个方法并不常用,提供他们只是为了方便。
重置处理器的方法是reset()方法。

跨浏览器使用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 caontext.transformNode(xslt);
}else{
   throw new Error("No XSLT processor available.");
}
}
这个函数接收两个参数:要执行转换的上下文节点和XSLT文档对象。返回序列化之后的字符串。
var result=transform(xmldom,xsltdom);






你可能感兴趣的:(javascript XML详解)