一、 XML
1.1 什么是XML
- 曾有一段时间,
XML
是互联网上传输结构化数据的事实标准,突出的特点是服务器与服务器间通信。后来更多采用JSON
来读写结构化数据。 -
XML
指可扩展标记语言(EXtensible Markup Language
) -
XML
的设计宗旨是结构化、存储和传输数据,焦点是数据的内容;而非显示数据(HTML
)。 -
XML
仅仅是纯文本而已,有能力处理纯文本的软件都可以处理XML
。 -
XML
没有预定义的标签,允许创作者自定义标签和文档结构。
1.2 XML
用途
-
XML
把数据从HTML
分离
如果你需要在 HTML
文档中显示动态数据,那么每当数据改变时将花费大量的时间来编辑 HTML
,通过 XML
,数据能够存储在独立的 XML
文件中。通过使用几行 JavaScript
,你就可以读取一个外部 XML
文件,然后更新 HTML
中的数据内容。
-
XML
简化数据共享
XML
数据以纯文本格式进行存储,因此提供了一种独立于软件和硬件的数据存储方法。这让创建不同应用程序可以共享的数据变得更加容易。
-
XML
兼容性强
通过 XML
,可以在不兼容的系统之间轻松地交换数据。不同的应用程序都能够访问您的数据,不仅仅在 HTML
页中,也可以从XML
数据源中进行访问。通过 XML
,您的数据可供各种阅读设备使用(手持的计算机、语音设备、新闻阅读器等),还可以供盲人或其他残障人士使用。
1.3 XML
结构
// 第一行是 XML 声明。它定义 XML 的版本 (1.0) 和所使用的编码
// 描述文档的根元素
George
John
Reminder
Don't forget the meeting! // 4个子元素
// 根元素结尾
1.4 XML
语法
- 所有
XML
元素都须有关闭标签。 -
XML
标签对大小写敏感。在XML
中,标签
与标签
是不同的。必须使用相同的大小写来编写打开标签和关闭标签。 -
XML
必须正确地嵌套,且必须有根元素(必须有一个元素是所有其他元素的父元素) -
XML
的属性值须加引号; - 实体引用,
<
、>
、&
、'
、"
来引用< > & ' "。 - 注释与
HTML
一样;<!-- -->
- 在
XML
中,空格会被保留。以LF
存储换行,对应ASCII
中转义字符\n
。
1.5 XML
元素
- 元素可包含其他元素、文本或者两者的混合物。元素也可以拥有属性。
- 命名规则
- 名称可以含字母、数字以及其他的字符,但不能以数字或者标点符号开始。
- 名称不能以字符
“xml”
(或者XML
、Xml
)开始,不能包含空格。 - 建议是有下划线连接
_
,不建议是有-
、.
、:
连接语义标签。会被一些软件误解析。
1.6 XML
属性
- 属性值必须被引号包围,单引号和双引号均可。
- 如果属性值本身包含双引号,那么有必要使用单引号包围它
- 如果信息感觉起来很像数据,应该尽量避免使用属性,改为使用子元素。元数据(有关数据的数据)应当存储为属性,而数据本身应当存储为元素。
二、 XLST
2.1 XLS
-
XSL
指扩展样式表语言(EXtensible Stylesheet
) -
XSL
=XML
样式表。(亦同css
和html
) -
XSL
包括三部分:-
XSLT
:一种用于转换XML
文档的语言。 -
XPath
:一种用于在XML
文档中导航的语言。 -
XSL-FO
:一种用于格式化XML
文档的语言。
-
// 外链XSL文件
Belgian Waffles
$5.95
two of our famous Belgian Waffles
650
把文档声明为 XSL
样式表的根元素是
或
// 或者
如需访问 XSLT
的元素、属性以及特性,我们必须在文档顶端声明 XSLT
命名空间。例:xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
2.2 XLST
简介
-
XSLT
指XSL
转换(XSL Transformations
),可将一种XML
文档转换为另外一种XML
文档(或者说是可被浏览器识别的其他类型的文档)。使用XPath
在XML
文档中进行导航。 - 通过
XSLT
,可以向或者从输出文件添加或移除元素和属性。您也可重新排列元素,执行测试并决定隐藏或显示哪个元素,等等。 - 描述转化过程的一种通常的说法是,
XSLT
把XML
源树转换为XML
结果树。
2.3 XLST
转换
例:我们现在要把下面这个 XML
文档("cdcatalog.xml"
)转换为 XHTML
。
Empire Burlesque
Bob Dylan
USA
Columbia
10.90
1985
...
...
...
然后创建一个带有转换模板的 XSL
样式表("cdcatalog.xsl"
)
My CD Collection
Title
Artist
向 XML
文档("cdcatalog.xml"
)添加XSL
样式表引用,如果您使用的浏览器兼容 XSLT
,它会很顺利地把 XML
转换为 XHTML
。
Empire Burlesque
Bob Dylan
USA
Columbia
10.90
1985
2.5 XSLT 元素
元素用于构建模板。match
属性用于关联 XML
元素和模板。match
属性也可用来为整个文档定义模板。match
属性的值是 XPath
表达式(举例,match="/"
定义整个文档)。元素内部的内容定义了写到输出结果的 HTML
代码。
// 由于 XSL 样式表本身也是一个 XML 文档,因此它总是由 XML 声明起始:
// 定义此文档是一个 XSLT 样式表文档(连同版本号和 XSLT 命名空间属性)
// xsl:template 元素定义了一个模板。而 match="/" 属性则把此模板与 XML 源文档的根相联系。
...
...
...
2.6 XSLT 元素
元素用于提取某个选定节点的值,并把值添加到转换的输出流中:
// 选定了XML中catalog/cd/title元素的值 输出在这个td中。
// 这里只捕获了一个匹配的元素 使用下面的for-each可以捕获全部
2.7 XSLT 元素
元素可用于选取指定的节点集中的每个 XML
元素。
// 在 xls:for-each 的select属性上定义需要循环的节点
- 结果过滤
- 合法的过滤运算符:= (等于) != (不等于) < (小于) > (大于)
2.8 XSLT 元素
如需对结果进行排序,只要简单地在 XSL
文件中的
元素内部添加一个
元素:
// select 属性指示需要排序的 XML 元素。
2.9 XSLT 元素
元素用于放置针对 XML
文件内容的条件测试。
// 仅仅会输出价格高于 10 的 CD 的 title 和 artist 元素。
2.10 XSLT 元素
XSLT
元素用于结合
和
来表达多重条件测试。
// 价格大于10的artist有背景
// 可以多个判断条件 价格大于9时小于10时 另外一种背景
2.11 XSLT 元素
元素可把一个模板应用于当前的元素或者当前元素的子节点。
My CD Collection
//在这里应用模板
// 应用在哪些元素
Title:
// 怎么应用
Artist:
三、 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
中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档节点(或称为根节点)。
Harry Potter
29.99
Learning XML
39.95
其中
(文档节点)
(元素节点)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 > 35 的book 元素 |
/bookstore/book[price>35.00]/title |
选取 bookstore 元素的所有 book 元素中 price > 35 的book 元素下的title 元素。 |
/bookstore/* |
选取 bookstore 元素的所有子元素 |
//* |
选取文档中的所有元素。 |
//title[@*] |
选取所有带有属性的 title 元素。 |
node() |
匹配任何类型的节点。 |
@* |
匹配任何属性节点。 |
//title | //price |
选取文档中的所有 title 和 price 元素。 |
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
对象用于在后台与服务器交换数据。创建XMLHttpRequest
对象的语法见4.5
- 在不重新加载页面的情况下更新网页
- 在页面已加载后从服务器请求数据
- 在页面已加载后从服务器接收数据
- 在后台向服务器发送数据
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");
// 解析
document.getElementById("to").innerHTML=
xmlDoc.getElementsByTagName("to")[0].childNodes[0].nodeValue;
5.3 加载并解析XML 字符串
// 使用浏览器提供的解析方法
var txt="";
txt=txt+"George ";
txt=txt+"John ";
txt=txt+"Reminder ";
txt=txt+"Don't forget the meeting!";
txt=txt+" ";
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);
}
// 解析
document.getElementById("to").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 删除子节点
xmlDoc
- 由解析器创建的 XML DOM
也能调用这些方法。
// 从 元素获取文本的 JavaScript 代码:
txt=xmlDoc.getElementsByTagName("title")[0].childNodes[0].nodeValue
6.3 访问节点
可以通过三种方法来访问节点:
- 通过使用
getElementsByTagName()
方法,返回的是一个NodeList
// 返回 x 元素下的所有 元素:
x.getElementsByTagName("title");
// 返回 XML 文档中的所有 元素
xmlDoc.getElementsByTagName("title");
- 通过循环(遍历)节点树
var x=xmlDoc.getElementsByTagName("title");
// 此时的x是一个节点列表 (node list)
var y = x[2]
// 通过下标获取单个节点
for (i=0;i ");
}
// 通过nodelist的length属性遍历节点
for (i=0;i ");
}
}
// 通过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
- 元素节点的
nodeValue
是undefined
- 文本节点的
nodeValue
是文本自身 - 属性节点的
nodeValue
是属性的值
- 元素节点的
nodeType
元素为1,属性为2,文本为3,注释为8,文档为9。
- 获取属性值 -
getAttribute()
,也可以使用.nodeValue
// 获取第一个 元素的 "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
一样,拥有一些定位关系节点的属性。parentNode
、childNodes
、firstChild
、lastChild
、nextSibling
、previousSibling
七、 XML
高级
7.1 命名空间
在 XML
中,元素名称是由开发者定义的,当两个不同的文档使用相同的元素名时,就会发生命名冲突。
- 使用前缀
African Coffee Table
80
120
- 使用命名空间(
Namespaces
) :xmlns:namespace-prefix="namespaceURI"
```xml
Apples
Bananas
- 默认的命名空间(
Default Namespaces
)
为元素定义默认的命名空间可以让我们省去在所有的子元素中使用前缀的工作。
Apples
Bananas
当开始使用 XSL
时,就会看到实际使用中的命名空间。XSL
样式表用于将XML
文档转换为其他格式,会根据命名空间来对该命名空间的xml
进行转换
7.2 CDATA
所有 XML
文档中的文本均会被解析器解析。只有 CDATA
区段(CDATA section
)中的文本会被解析器忽略。PCDATA
指的是被解析的字符数据(Parsed Character Data
), 术语 CDATA
指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data
)
在 XML
元素中,"<"
和 "&"
是非法的。
-
"<"
会产生错误,因为解析器会把该字符解释为新元素的开始。 -
"&"
也会产生错误,因为解析器会把该字符解释为字符实体的开始。
但是有些文本,比如JavaScript
代码,会包含的大量的这样的字符,为避免错误,可以讲脚本代码定义为CDATA
来让浏览器来忽略解析。
CDATA
部分由 " 开始,由
"]]>"
结束:
CDATA
部分不能包含字符串 "]]>"
。也不允许嵌套的 CDATA
部分,标记 CDATA
部分结尾的 "]]>"
不能包含空格或折行。
关于数据存储可看w3school - 把数据存储到 XML 文件
八、 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(" ", "text/xml");
在发生解析错误时, 仍然会从parseFromString()
中返回一个Document
对象, 但这个对象的文档元素是
。通过getElementsByTagName()
来查找文档中是否存在
元素以判断是否解析错误。
try {
xmldom = parser.parseFromString("", "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()
,会导致错误发生。
8.3 关于IE8及之前版本的XML DOM创建 及解析与序列化
- 8.3.1 创建
XML DOM
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
- 8.3.2 将
XML
解析为DOM
xmlDoc.async="false";
xmlDoc.load("note.xml");
xmldom.loadXML(" "); // 将xml字符串解析为dom
如果解析过程中出错,可以在parseError
属性中找到错误消息。
-
errorCode
:错误类型的数值编码;在没有发生错误时值为0。 -
filePos
:文件中导致错误发生的位置。 -
line
:发生错误的行。 -
linepos
:发生错误的行中的字符。 -
reason
:对错误的文本解释。 -
srcText
:导致错误的代码。 -
url
:导致错误的文件的URL
(如果有这个文件的话)。
另外,parseError
的valueOf()
方法直接返回errorCode
的值,因此可以通过下列代码检测是否发生了解析错误。
if (xmldom.parseError != 0){
alert("Parsing error occurred.");
}
- 8.3.3 将
DOM
文档序列化为XML
字符串。
IE
将序列化XML
的能力内置在了DOM
文档中。每个DOM
节点都有一个xml
属性,其中保存着表示该节点的XML
字符串。
alert(xmldom.xml);
九、 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);
}
}
- 对于布尔值类型,如果至少有一个节点与
XPath
表达式匹配,则求值结果返回true
,否则返回false
。result.booleanValue
- 对于数值类型,必须在
XPath
表达式参数的位置上指定一个能够返回数值的XPath
函数,例如计算与给定模式匹配的所有节点数量的count()
;"count(employee/name)"
result.numberValue
;没有指定类似的XPath
函数,那么numberValue
的值将等于NaN
。 - 对于字符串类型,
evaluate()
方法会查找与XPath
表达式匹配的第一个节点,然后返回其第一个子节点的值(实际上是假设第一个子节点为文本节点)。如果没有匹配的节点,结果就是一个空字符串。result.stringValue
要确定返回的是什么结果类型,可以检测结果的resultType
属性。
- 对命名空间的支持
通过createNSResolver()
来创建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);
第二种方式是定义一个函数,让它接收一个命名空间前缀,返回关联的URI,然后将这个函数的返回值传给evaluate()
函数
var nsresolver = function(prefix){
switch(prefix){
case "wrox": return "http://www.wrox.com/";
//其他前缀
}
};
9.2 IE中的XPath
-
selectSingleNode()
和selectNodes()
selectSingleNode()
方法接受一个XPath
模式,在找到匹配节点时返回第一个匹配的节点,如果没有找到匹配的节点就返回null
。
selectNodes()
也接收一个XPath
模式作为参数,但它返回与模式匹配的所有节点的NodeList
(如果没有匹配的节点,则返回一个包含零项的NodeList
)
var element = xmldom.documentElement.selectSingleNode("employee/name");
var elements = xmldom.documentElement.selectNodes("employee/name");
- IE对命名空间的支持
要在IE
中处理包含命名空间的XPath
表达式,你必须知道自己使用的命名空间,并按照格式创建一个字符串。
setProperty()
接收两个参数:要设置的属性名和属性值。在这里,属性名应是"SelectionNamespaces"
,属性值就是按照前面格式创建的字符串。
字符串格式:"xmlns:prefix1='uri1' xmlns:prefix2='uri2'
xmldom.setProperty("SelectionNamespaces", "xmlns:wrox=’http://www.wrox.com/’");
var result = xmldom.documentElement.selectNodes("wrox:book/wrox:author");
alert(result.length);
十、 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
样式表可以接受传入的参数,并将其用作局部变量。
Message:
定义了一个名为message
的参数,然后将该参数输出到转换结果中。要设置message
的值,可以在调用transform()
之前使用addParameter()
方法。
processor.input = xmldom.documentElement;
processor.addParameter("message", "Hello World!");
processor.transform();
XSL
处理器的另一个高级特性,就是能够设置一种操作模式。在XSLT
中,可以使用mode
特性为模板定义一种模式。在定义了模式后,如果没有将
与匹配的mode
特性一起使用,就不会运行该模板。
,
这个样式表定义了一个模板,并将其mode
特性设置为"title-first"
(即“先显示title”
)为了使用这个模板,必须要用JS
的方式用setStartMode()
方法将
元素的模式设置为"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.");
}
}