XML

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2020-04-28

一、 XML

1.1 什么是XML

  • 曾有一段时间,XML 是互联网上传输结构化数据的事实标准,突出的特点是服务器与服务器间通信。后来更多采用JSON来读写结构化数据。
  • XML 指可扩展标记语言(EXtensible Markup Language
  • XML 的设计宗旨是结构化、存储和传输数据,焦点是数据的内容;而非显示数据(HTML)。
  • XML 仅仅是纯文本而已,有能力处理纯文本的软件都可以处理XML
  • XML 没有预定义的标签,允许创作者自定义标签和文档结构。

1.2 XML用途

(1)XML 把数据从 HTML 分离:如果你需要在 HTML 文档中显示动态数据,那么每当数据改变时将花费大量的时间来编辑 HTML,通过 XML,数据能够存储在独立的 XML 文件中。通过使用几行 JavaScript,你就可以读取一个外部 XML文件,然后更新 HTML 中的数据内容。

(2)XML 简化数据共享:XML 数据以纯文本格式进行存储,因此提供了一种独立于软件和硬件的数据存储方法。这让创建不同应用程序可以共享的数据变得更加容易。

(3)XML 兼容性强:通过 XML,可以在不兼容的系统之间轻松地交换数据。不同的应用程序都能够访问您的数据,不仅仅在 HTML 页中,也可以从XML 数据源中进行访问。通过 XML,您的数据可供各种阅读设备使用(手持的计算机、语音设备、新闻阅读器等),还可以供盲人或其他残障人士使用。

1.3 XML结构

<?xml version="1.0" encoding="ISO-8859-1"?> 
// 第一行是 XML 声明。它定义 XML 的版本 (1.0) 和所使用的编码
<note> // 描述文档的根元素
    <to>George</to>
    <from>John</from>
    <heading>Reminder</heading>
    <body>Don't forget the meeting!</body> // 4个子元素
</note>  // 根元素结尾

1.4 XML语法

  • 所有 XML 元素都须有关闭标签。
  • XML 标签对大小写敏感。在 XML 中,标签 <Letter> 与标签 <letter> 是不同的。必须使用相同的大小写来编写打开标签和关闭标签。
  • XML必须正确地嵌套,且必须有根元素(必须有一个元素是所有其他元素的父元素)
  • XML 的属性值须加引号;<note date="08/08/2008">
  • 实体引用,&lt;&gt;&amp;&apos;&quot;来引用< > & ’ “。
  • 注释与HTML一样;<!-- -->
  • XML 中,空格会被保留。以 LF 存储换行,对应ASCII中转义字符\n

1.5 XML元素

  • 元素可包含其他元素、文本或者两者的混合物。元素也可以拥有属性。
  • 命名规则
    • 名称可以含字母、数字以及其他的字符,但不能以数字或者标点符号开始。
    • 名称不能以字符 “xml”(或者 XMLXml)开始,不能包含空格。
    • 建议是有下划线连接_,不建议是有-.:连接语义标签。会被一些软件误解析。

1.6 XML属性

  • 属性值必须被引号包围,单引号和双引号均可。
  • 如果属性值本身包含双引号,那么有必要使用单引号包围它
  • 如果信息感觉起来很像数据,应该尽量避免使用属性,改为使用子元素。元数据(有关数据的数据)应当存储为属性,而数据本身应当存储为元素。

二、 XLST

2.1 XLS

  • XSL 指扩展样式表语言(EXtensible Stylesheet )
  • XSL = XML 样式表。(亦同csshtml
  • XSL 包括三部分:
    • XSLT:一种用于转换 XML 文档的语言。
    • XPath:一种用于在 XML 文档中导航的语言。
    • XSL-FO:一种用于格式化 XML 文档的语言。

把文档声明为 XSL 样式表的根元素是 <xsl:stylesheet><xsl:transform>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
// 或者
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

如需访问 XSLT 的元素、属性以及特性,我们必须在文档顶端声明 XSLT 命名空间。例:xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

2.2 XLST简介

  • XSLTXSL 转换(XSL Transformations),可将一种 XML 文档转换为另外一种 XML 文档(或者说是可被浏览器识别的其他类型的文档)。使用 XPathXML 文档中进行导航。
  • 通过 XSLT,可以向或者从输出文件添加或移除元素和属性。您也可重新排列元素,执行测试并决定隐藏或显示哪个元素,等等。
  • 描述转化过程的一种通常的说法是,XSLTXML 源树转换为 XML 结果树。

2.3 XLST转换

例:我们现在要把下面这个 XML 文档("cdcatalog.xml")转换为 XHTML

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- 引入下面的xsl文件 -->
<?xml-stylesheet type="text/xsl" href="cdcatalog.xsl"?>
<catalog>
  <cd>
    <title>Empire Burlesque</title>
    <artist>Bob Dylan</artist>
    <country>USA</country>
    <company>Columbia</company>
    <price>10.90</price>
    <year>1985</year>
  </cd>
</catalog>

然后创建一个带有转换模板的 XSL 样式表("cdcatalog.xsl"

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <html>
  <body>
    <h2>My CD Collection</h2>
    <table border="1">
    <tr bgcolor="#9acd32">
      <th align="left">Title</th>
      <th align="left">Artist</th>
    </tr>
    <xsl:for-each select="catalog/cd">
    <tr>
      <td><xsl:value-of select="title"/></td>
      <td><xsl:value-of select="artist"/></td>
    </tr>
    </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>

2.5 XSLT <xsl:template> 元素

<xsl:template> 元素用于构建模板。match 属性用于关联 XML 元素和模板。match 属性也可用来为整个文档定义模板。match 属性的值是 XPath 表达式(举例,match="/" 定义整个文档)。元素内部的内容定义了写到输出结果的 HTML 代码。

<!-- 由于 XSL 样式表本身也是一个 XML 文档,因此它总是由 XML 声明起始: -->
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- 定义此文档是一个 XSLT 样式表文档(连同版本号和 XSLT 命名空间属性) -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- xsl:template 元素定义了一个模板。而 match="/" 属性则把此模板与 XML 源文档的根相联系。 -->
  <xsl:template match="/">
  ...
  ...
  ...
  </xsl:template>
</xsl:stylesheet>

2.6 XSLT <xsl:value-of> 元素

<xsl:value-of> 元素用于提取某个选定节点的值,并把值添加到转换的输出流中:

<tr>
  <td><xsl:value-of select="catalog/cd/title"/></td>
  <td><xsl:value-of select="catalog/cd/artist"/></td>
</tr>
<!-- 选定了XML中catalog/cd/title元素的值 输出在这个td中。 -->
<!-- 这里只捕获了一个匹配的元素 使用下面的for-each可以捕获全部 -->

2.7 XSLT <xsl:for-each> 元素

<xsl:for-each> 元素可用于选取指定的节点集中的每个 XML 元素。

<xsl:for-each select="catalog/cd">
  <!-- 在 xls:for-each 的select属性上定义需要循环的节点 -->
  <tr>
    <td><xsl:value-of select="title"/></td>
    <td><xsl:value-of select="artist"/></td>
  </tr>
</xsl:for-each>

结果过滤:

<xsl:for-each select="catalog/cd[artist='Bob Dylan']">

合法的过滤运算符有:= (等于), != (不等于), < (小于), > (大于)

2.8 XSLT <xsl:sort> 元素

如需对结果进行排序,只要简单地在 XSL 文件中的 <xsl:for-each> 元素内部添加一个 <xsl:sort>元素:

<xsl:for-each select="catalog/cd">
<xsl:sort select="artist"/>
  <!-- select 属性指示需要排序的 XML 元素。 -->
  <tr>
    <td><xsl:value-of select="title"/></td>
    <td><xsl:value-of select="artist"/></td>
  </tr>
</xsl:for-each>

2.9 XSLT <xsl:if> 元素

<xsl:if> 元素用于放置针对 XML 文件内容的条件测试。

<xsl:for-each select="catalog/cd">
  <xsl:if test="price > 10">
    <!-- 仅仅会输出价格高于 10 的 CD 的 title 和 artist 元素。 -->
    <tr>
      <td><xsl:value-of select="title"/></td>
      <td><xsl:value-of select="artist"/></td>
    </tr>
  </xsl:if>
</xsl:for-each>
2.10 XSLT <xsl:choose> 元素

XSLT <xsl:choose> 元素用于结合 <xsl:when><xsl:otherwise> 来表达多重条件测试。

<xsl:for-each select="catalog/cd">
<tr>
  <td><xsl:value-of select="title"/></td>
  <xsl:choose>
    <!-- 价格大于10的artist有背景 -->
    <xsl:when test="price >10">
      <td bgcolor="#ff00ff"><xsl:value-of select="artist"/></td>
    </xsl:when>

    <!-- 可以多个判断条件 价格大于9时小于10时 另外一种背景 -->
    <xsl:when test="price>9">
      <td bgcolor="#cccccc"> <xsl:value-of select="artist"/></td>
    </xsl:when>

    <xsl:otherwise>
      <td><xsl:value-of select="artist"/></td>
    </xsl:otherwise>

  </xsl:choose>
</tr>
</xsl:for-each>

2.11 XSLT <xsl:apply-templates> 元素

<xsl:apply-templates> 元素可把一个模板应用于当前的元素或者当前元素的子节点。

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2> 
  <!-- 在这里应用模板  -->
  <xsl:apply-templates/> 
</body>
</html>
</xsl:template>

<xsl:template match="cd">
<!-- 应用在哪些元素 -->
<p>
  <xsl:apply-templates select="title"/> 
  <xsl:apply-templates select="artist"/>
</p>
</xsl:template>

<!-- 怎么应用 -->
<xsl:template match="title">
Title: <span style="color:#ff0000"><xsl:value-of select="."/></span><br /> 
</xsl:template>

<xsl:template match="artist">
Artist: <span style="color:#00ff00"><xsl:value-of select="."/></span><br />
</xsl:template>

</xsl:stylesheet>

三、 XLST高级

之前讲到的是如何使用 XSLT 将某个 XML 文档转换为 XHTML。我们是通过以下途径完成这个工作的:向 XML 文件添加 XSL 样式表,并通过浏览器完成转换。但是在无法识别XSLT的浏览器这种方法就无法奏效,更通用的方法是使用 JavaScript 来完成转换。通过使用 JavaScript,我们可以进行浏览器确认测试并根据浏览器和使用者的需求来使用不同的样式表。

  • XSLT - 客户端

之前是在xml文件外联xsl文件然后由浏览器进行转换,现在可以使用JS直接完成加载与转换。

// Load XML 
var xml = new ActiveXObject("Microsoft.XMLDOM")
xml.async = false // 是否异步加载 默认为true
xml.load("cdcatalog.xml")

// Load XSL
var xsl = new ActiveXObject("Microsoft.XMLDOM")
xsl.async = false
xsl.load("cdcatalog.xsl")

// Transform
document.write(xml.transformNode(xsl))
  • XSLT - 在服务器上

JavaScript 解决方案无法工作于没有 XML解析器的浏览器。为了让 XML 数据适用于任何类型的浏览器,我们必须在服务器上对 XML 文档进行转换,然后将其作为 XHMTL 发送到浏览器。XSLT 的设计目标之一是使数据在服务器上从一种格式转换到另一种格式成为可能,并向所有类型的浏览器返回可读的数据。

<%
'Load XML
set xml = Server.CreateObject("Microsoft.XMLDOM")
xml.async = false
xml.load(Server.MapPath("cdcatalog.xml"))

'Load XSL
set xsl = Server.CreateObject("Microsoft.XMLDOM")
xsl.async = false
xsl.load(Server.MapPath("cdcatalog.xsl"))

'Transform file
Response.Write(xml.transformNode(xsl))
%>

// ASP写法

四、 XPath

XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档节点(或称为根节点)。

<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
<book>
  <title lang="eng">Harry Potter</title>
  <price>29.99</price>
</book>
<book>
  <title lang="eng">Learning XML</title>
  <price>39.95</price>
</book>
</bookstore>

其中<bookstore>(文档节点)<price>29.99</price> (元素节点)lang="eng"(属性节点),39.95"en"等属于基本值。

节点关系也存在与HTML一样的,父、子、同胞、先辈、后代。

4.1 语法

XPath 使用路径表达式来选取 XML 文档中的节点或节点集。

表达式 结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。以/开头,代表着是绝对路径。
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang 选取名为 lang 的所有属性。
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个book 元素。
/bookstore/book[position()<3] 选取最前面的两个(所在位置小于3)属于 bookstore 元素的子元素的 book元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang='eng'] 选取所有拥有值为 eng 的 lang 属性 title 元素
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素中 price > 35book元素
/bookstore/book[price>35.00]/title 选取 bookstore 元素的所有 book 元素中 price > 35book元素下的title元素。
/bookstore/* 选取 bookstore 元素的所有子元素
//* 选取文档中的所有元素。
//title[@*] 选取所有带有属性title 元素。
node() 匹配任何类型的节点。
@* 匹配任何属性节点。
//title | //price 选取文档中的所有 titleprice元素。

4.2 轴

轴可定义相对于当前节点的节点集。

轴名称 结果
ancestor 选取当前节点的所有先辈(父、祖父等)。
ancestor-or-self 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。
attribute 选取当前节点的所有属性。
child 选取当前节点的所有子元素。
descendant 选取当前节点的所有后代元素(子、孙等)。
descendant-or-self 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。
following 选取文档中当前节点的结束标签之后的所有节点。
namespace 选取当前节点的所有命名空间节点。
parent 选取当前节点的父节点。
preceding 选取文档中当前节点的开始标签之前的所有节点。
preceding-sibling 选取当前节点之前的所有同级节点。
self 选取当前节点。

4.3 步

每个步均根据当前节点集之中的节点来进行计算。语法:轴名称::节点测试[谓语]

例子 结果
child::book 选取所有属于当前节点的子元素的 book 节点。
attribute::lang 选取当前节点的 lang 属性。
child::* 选取当前节点的所有子元素。
attribute::* 选取当前节点的所有属性。
child::text() 选取当前节点的所有文本子节点。
child::node() 选取当前节点的所有子节点。
descendant::book 选取当前节点的所有 book 后代。
ancestor::book 选择当前节点的所有 book 先辈。
ancestor-or-self::book 选取当前节点的所有 book先辈以及当前节点(如果此节点是 book 节点)
child::*/child::price 选取当前节点的所有 price孙节点。

4.4 XPath 运算符

区别于常规运算符的有:

运算符 描述 实例 返回值
| 计算两个节点集 //book | //cd 返回所有拥有 book 和 cd 元素的节点集
div 除法 8 div 4 2
or price=9.80 or price=9.70 price等于9.80或9.70时返回true
and price>9.00 and price<9.90 price在9.00 - 9.90之间返回true
mod 求模 5 mod 2 1

4.5 加载 XML 文档

所有现代浏览器都支持使用 XMLHttpRequest 来加载 XML 文档的方法

var xhr = new XMLHttpRequest
// 针对IE 5 和 6
var xhr = new ActiveXObject("Microsoft.XMLHTTP")

4.6 选取节点

xmlDoc.evaluate(xpath, xmlDoc, null, XPathResult.ANY_TYPE,null);
// IE
xmlDoc.selectNodes(xpath);

五、 XML & JavaScript

5.1 XMLHttpRequest 对象

XMLHttpRequest 对象用于在后台与服务器交换数据。

  • 在不重新加载页面的情况下更新网页
  • 在页面已加载后从服务器请求数据
  • 在页面已加载后从服务器接收数据
  • 在后台向服务器发送数据

示例:

var xmlhttp;
function loadXMLDoc(url){
  xmlhttp=null;
  if (window.XMLHttpRequest){
    // code for all new browsers
    xmlhttp = new XMLHttpRequest();
  } else if (window.ActiveXObject){
    // code for IE5 and IE6
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  }
  if (xmlhttp != null) {
    xmlhttp.onreadystatechange=state_Change;
    xmlhttp.open("GET",url,true); // 第三个参数规定请求是否异步处理
    // true 表示脚本会在 send() 方法之后继续执行,而不等待来自服务器的响应。
    xmlhttp.send(null);
  } else {
    alert("Your browser does not support XMLHTTP.");
  }
}

function state_Change(){
  if (xmlhttp.readyState == 4) {
    // 4 = "loaded"
    if (xmlhttp.status == 200){
    // 200 = OK
    // ...our code here...
    } else {
      alert("Problem retrieving XML data");
    }
  }
}

5.2 加载并解析XML 文件

// 使用XMLHttpRequest 对象
xmlhttp.open("GET","/example/xmle/note.xml",false); // 加载
xmlhttp.send();
xmlDoc = xmlhttp.responseXML; // 获取

// IE
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.load("note.xml");

// Firefox 及 其他浏览器
var xmlDoc = document.implementation.createDocument("","",null);
xmlDoc.async="false";
xmlDoc.load("note.xml");

// 解析
var toDom = document.getElementById("to")
toDom.innerHTML = xmlDoc.getElementsByTagName("to")[0].childNodes[0].nodeValue;

5.3 加载并解析XML 字符串

// 使用浏览器提供的解析方法
var txt="<note>";
txt=txt+"<to>George</to>";
txt=txt+"<from>John</from>";
txt=txt+"<heading>Reminder</heading>";
txt=txt+"<body>Don't forget the meeting!</body>";
txt=txt+"</note>";

if (window.DOMParser) { // 现代浏览器
  parser=new DOMParser();
  xmlDoc=parser.parseFromString(txt,"text/xml");
} else { // Internet Explorer
  xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
  xmlDoc.async="false";
  xmlDoc.loadXML(txt);
}

// 解析
var toDom = document.getElementById("to")
toDom.innerHTML = xmlDoc.getElementsByTagName("to")[0].childNodes[0].nodeValue;

六、 XML DOM

6.1 XML DOM 常用属性

x 是一个节点对象

  • x.nodeName - x 的名称
  • x.nodeValue - x 的值
  • x.parentNode - x 的父节点
  • x.childNodes -x 的子节点
  • x.attributes - x 的属性节点

6.2 XML DOM 方法

  • x.getElementsByTagName(name) - 获取带有指定标签名称的所有元素
  • x.appendChild(node) - 向 x 插入子节点
  • x.removeChild(node) - 从 x 删除子节点

6.3 访问节点

可以通过三种方法来访问节点:

  • 通过使用 getElementsByTagName() 方法,返回的是一个NodeList

  • 通过循环(遍历)节点树

示例:

var x=xmlDoc.getElementsByTagName("title");
var y = x[2] 

for ( i=0; i<x.length; i++) { 
  document.write(x[i].childNodes[0].nodeValue);
  document.write("<br />");
}
// 通过nodelist的length属性遍历节点

for (i=0; i<x.length; i++) { 
  if (x[i].nodeType==1) {
    document.write(x[i].nodeName);
    document.write("<br />");
  } 
}
// 通过nodetType来遍历元素节点
  • 通过利用节点的关系在节点树中导航

示例:

x = xmlDoc.getElementsByTagName("book")[0].childNodes;
y = xmlDoc.getElementsByTagName("book")[0].firstChild;
z = y.nextSibling;

6.4 节点属性及操作

  • nodeName

    • nodeName 是只读的
    • 元素节点的 nodeName 与标签名相同
    • 属性节点的 nodeName 是属性的名称
    • 文本节点的 nodeName 永远是#text
    • 文档节点的 nodeName 永远是 #document
  • nodeValue

    • 元素节点的 nodeValueundefined
    • 文本节点的 nodeValue 是文本自身
    • 属性节点的 nodeValue 是属性的值
  • nodeType:元素为1,属性为2,文本为3,注释为8,文档为9。

  • 获取属性值 - getAttribute() ,也可以使用.nodeValue

// 获取第一个 <title> 元素的 "lang" 属性的属性值
var val = xmlDoc.getElementsByTagName("title")[0].getAttribute("lang");
  • 修改属性值 - setAttribute() ,也可以使用.nodeValue
  • 删除节点 - removeChild()
  • 删除节点属性 - removeAttribute(name)
  • 替换节点 - replaceChild()
  • 创建节点 - createElement()createAttribute()createTextNode() createComment()
  • 添加节点 - appendChild()insertBefore(newNode,refNode)
  • 向文本节点添加文本 - insertData(offset,string) (从何处开始插入,要插入的字符串)
  • 克隆节点 - newNode=oldNode.cloneNode(true); 参数代表是否克隆原节点的所有属性和子节点

6.5 定位节点

DOM一样,拥有一些定位关系节点的属性。parentNodechildNodesfirstChildlastChildnextSiblingpreviousSibling

七、 XML高级

7.1 命名空间

XML 中,元素名称是由开发者定义的,当两个不同的文档使用相同的元素名时,就会发生命名冲突。

1、使用前缀

<f:table>
  <f:name>African Coffee Table</f:name>
  <f:width>80</f:width>
  <f:length>120</f:length>
</f:table>

2、使用命名空间(Namespaces) : xmlns:namespace-prefix="namespaceURI"

<h:table xmlns:h="http://www.w3.org/TR/html4/">
  <h:tr>
    <h:td>Apples</h:td>
    <h:td>Bananas</h:td>
  </h:tr>
</h:table>

3、默认的命名空间(Default Namespaces

为元素定义默认的命名空间可以让我们省去在所有的子元素中使用前缀的工作。

<table xmlns="http://www.w3.org/TR/html4/">
  <tr>
    <td>Apples</td>
    <td>Bananas</td>
  </tr>
</table>

当开始使用 XSL 时,就会看到实际使用中的命名空间。XSL 样式表用于将XML文档转换为其他格式,会根据命名空间来对该命名空间的xml进行转换

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/TR/html4/">

7.2 CDATA

所有 XML文档中的文本均会被解析器解析。只有 CDATA 区段(CDATA section)中的文本会被解析器忽略。PCDATA 指的是被解析的字符数据(Parsed Character Data), 术语 CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data

XML 元素中,"<""&"是非法的。

  • "<" 会产生错误,因为解析器会把该字符解释为新元素的开始。
  • "&" 也会产生错误,因为解析器会把该字符解释为字符实体的开始。

但是有些文本,比如JavaScript代码,会包含的大量的这样的字符,为避免错误,可以讲脚本代码定义为CDATA来让浏览器来忽略解析。

CDATA 部分由 "<![CDATA[" 开始,由 "]]>" 结束:

<script>
<![CDATA[
function matchwo(a,b){
  if (a < b && a < 0) return 1;
  return 0;
}
]]>
</script>

CDATA 部分不能包含字符串 "]]>"。也不允许嵌套的 CDATA 部分,标记 CDATA 部分结尾的 "]]>" 不能包含空格或折行。

八、 XML DOM补充

8.1 关于创建 XML DOM

  • document.implementation.createDocument(namespaceUri, root, doctype);

在通过JavaScript 处理XML时,通常只使用参数root,因为这个参数指定的是XML DOM 文档元素的标签名。而namespaceUri 参数则很少用到,原因是在JavaScrip 中管理命名空间比较困难。最后,doctype(文档类型) 参数用得就更少。

var xmldom = document.implementation.createDocument('', "root", null);

8.2 关于解析和序列化

  • DOMParser类型:将XML解析为DOM

在解析XML之前,首先必须创建一个DOMParser 的实例,然后再调用parseFromString()方法。这个方法接受两个参数:要解析的XML字符串和内容类型(内容类型始终都应该是"text/xml"

var parser = new DOMParser();
var xmldom = parser.parseFromString("<root><child/></root>", "text/xml");

在发生解析错误时, 仍然会从parseFromString()中返回一个Document 对象, 但这个对象的文档元素是<parsererror>。通过getElementsByTagName()来查找文档中是否存在<parsererror>元素以判断是否解析错误。

try {
  xmldom = parser.parseFromString("<root>", "text/xml");
  errors = xmldom.getElementsByTagName("parsererror");
  if (errors.length > 0){
    throw new Error("Parsing error!");
  }
} catch (ex) {
  alert("Parsing error!");
}
  • XMLSerializer类型:将DOM文档序列化为XML字符串。

示例:

var serializer = new XMLSerializer();
var xml = serializer.serializeToString(xmldom);
alert(xml);

XMLSerializer 可以序列化任何有效的DOM 对象,不仅包括个别的节点,也包括HTML 文档。将HTML 文档传入serializeToString()以后,HTML 文档将被视为XML 文档,因此得到的代码也将是格式良好的。如果将非DOM 对象传入serializeToString(),会导致错误发生。

九、XPath补充

9.1 XPathEvaluator类型

用于在特定的上下文中对XPath表达式求值。

  • createExpression(expression, nsresolver):将XPath 表达式及相应的命名空间信息转换成一个XPathExpression,这是查询的编译版。在多次使用同一个查询时很有用。
  • createNSResolver(node):根据node的命名空间信息创建一个新的XPathNSResolver 对象。在基于使用命名空间的XML文档求值时,需要使用XPathNSResolver 对象。
  • evaluate(expression, context, nsresolver, type, result):在给定的上下文中,基于特定的命名空间信息来对XPath表达式求值。剩下的参数指定如何返回结果。

evaluate()是最常用的。这个方法接收5 个参数:XPath表达式、上下文节点、命名空间求解器、返回结果的类型和保存结果的XPathResult对象。

第三个参数只在XML代码中使用了XML命名空间时有必要指定,否则为null;第五个参数基本为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.ORDERED_NODE_SNAPSHOT_TYPE:返回节点集合的快照,后续操作不会影响到这个节点集合。次序一致。
  • XPathResult.ANY_UNORDERED_NODE_TYPE:返回匹配的节点集合,次序不一定与文档中的一致。
  • XPathResult.FIRST_ORDERED_NODE_TYPE:返回节点集合,只文档中第一个匹配的节点。

示例:

var result = xmldom.evaluate("bookstore/book", xmldom.documentElement, null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);

if (result !== null) {
  var node = result.iterateNext(); // 使用iterateNext()遍历dom节点集合
  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);
  }
}
  • 对命名空间的支持

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

通过createNSResolver()来创建XPathNSResolver 对象。这个方法接受一个参数,即文档中包含命名空间定义的节点。在evaluate()中使用返回的结果。

// 针对命名空间的XPath求值,需要先获取到evaluate函数需要使用的 第三个参数 命名空间求解器 nsresolver
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);

第二种方式是定义一个函数,让它接收一个命名空间前缀,返回关联的URI,然后将这个函数的返回值传给evaluate()函数

var nsresolver = function(prefix){
  switch(prefix){
    case "wrox": return "http://www.wrox.com/";
    //其他前缀
  }
};

十、 XSLT 补充

10.1 IE中的XLST转换

使用XSLT 样式表转换XML文档的最简单方式,就是将它们分别加到一个DOM 文档中,然后再使用transformNode()方法。这个方法存在于文档的所有节点中,它接受一个参数,即包含XSLT 样式表的文档。调用transformNode()方法会返回一个包含转换信息的字符串。

//加载XML 和XSLT(仅限于IE)
xmldom.load("employees.xml");
xsltdom.load("employees.xslt");
//转换
var result = xmldom.transformNode(xsltdom);

还有使用这种语言的更复杂的方式。为此,必须要使用XSL 模板XSL 处理器。第一步是要把XSLT 样式表加载到一个线程安全的XML文档中

//  线程安全的`XML`文档 尽量使用最新的版本
var xsltdom = new ActiveXObject("MSXML2.FreeThreadedDOMDocument.6.0");
//  XSL模板 尽量使用最新的版本  这个模板是用来创建XSL 处理器对象
var template = new ActiveXObject("MSXML2.XSLTemplate.6.0");
template.stylesheet = xsltdom;
var processor = template.createProcessor(); // 创建处理器
processor.input = xmldom;
processor.transform();
var result = processor.output;

在创建了XSL 处理器之后,必须将要转换的节点指定给input 属性。这个值可以是一个文档,也可以是文档中的任何节点。然后,调用transform()方法即可执行转换并将结果作为字符串保存在output 属性中。这些代码实现了与transformNode()相同的功能。

使用XSL 处理器可以对转换进行更多的控制,同时也支持更高级的XSLT 特性。例如,XSLT样式表可以接受传入的参数,并将其用作局部变量。

<p>Message: <xsl:value-of select="$message"/></p>

定义了一个名为message 的参数,然后将该参数输出到转换结果中。要设置message的值,可以在调用transform()之前使用addParameter()方法。

processor.input = xmldom.documentElement;
processor.addParameter("message", "Hello World!");
processor.transform();

XSL处理器的另一个高级特性,就是能够设置一种操作模式。在XSLT中,可以使用mode特性为模板定义一种模式。在定义了模式后,如果没有将<xsl:apply-templates>与匹配的mode特性一起使用,就不会运行该模板。

<xsl:template match="employee" mode="title-first">
    <li><em><xsl:value-of select="@title"/></em>,
     <xsl:value-of select="name"/></li>
</xsl:template>

这个样式表定义了一个模板,并将其mode特性设置为"title-first"(即“先显示title”)为了使用这个模板,必须要用JS的方式用setStartMode()方法将<xsl:apply-templates>元素的模式设置为"title-first"

processor.input = xmldom;
processor.addParameter("message", "Hello World!");
processor.setStartMode("title-first");// 必须在调用transform()之前进行。
processor.transform();

10.2 常规浏览器中的XLST转换

第一步也是加载两个DOM 文档,一个基于XML,另一个基于XSLT。然后,创建一个新XSLTProcessor 对象,并使用importStylesheet()方法为其指定一个XSLT。最后一步就是执行转换。这一步有两种不同的方式,如果想返回一个完整的DOM文档,可以调用transformToDocument()。而通过调用transformToFragment()则可以得到一个文档片段对象。一般来说,使用transformToFragment()的唯一理由,就是你还想把返回的结果添加到另一个DOM文档中。

var processor = new XSLTProcessor()
processor.importStylesheet(xsltdom);
processor.setParameter(null, "message", "Hello World! "); // 也可以在转换前设置参数

// 常用转换
var result = processor.transformToDocument(xmldom);
alert(serializeXml(result));

// 用`transformToFragment()`把返回的结果添加到另一个`DOM`文档中。
var fragment = processor.transformToDocument(xmldom, document);
var div = document.getElementById("divResult");
div.appendChild(fragment);

还有两个与参数有关的方法,getParameter()removeParameter(),分别用于取得和移除当前参数的值。这两个方法都要接受命名空间参数(同样,通常是null)和参数的内部名称。

alert(processor.getParameter(null, "message")); //输出"Hello World!"
processor.removeParameter(null, "message");

每个XSLTProcessor 的实例都可以重用,以便使用不同的XSLT 样式表执行不同的转换。重置处理器时要调用reset()方法,这个方法会从处理器中移除所有参数和样式表。然后,你就可以再次调用importStylesheet(),以加载不同的XSLT 样式表。

var processor = new XSLTProcessor()
processor.importStylesheet(xsltdom);
//执行转换 do something
processor.reset();
processor.importStylesheet(xsltdom2);
//再执行转换

10.3 跨浏览器使用XLST

跨浏览器兼容性最好的XSLT转换技术,只能是返回结果字符串,为此在IE 中只能在上下文节点上调用transformNode()而不是处理器对象的transform()

function transform(context, xslt){ // 接收两个参数:要执行转换的上下文节点和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") { // IE
    return context.transformNode(xslt);
  } else {
    throw new Error("No XSLT processor available.");
  }
}