<?xml version="1.0" encoding="UTF-8"?>
<!-- edited with XMLSpy v2008 rel. 2 sp2 (http://www.altova.com) by Administrator -->
<?xml-stylesheet type="text/xsl" href="messages.xsl"?>
<messages>
<message id="1">
<sender>gukaitong@gmail.com</sender>
<to>anonymous@gmail.com
<group name="IT">
<address>111@gmail.com</address>
<address>222@gmail.com</address>
<address>aaa@gmail.com</address>
<address>bbb@gmail.com</address>
<address>ccc@gmail.com</address>
</group>
</to>
<subject>This is a sample</subject>
<datetime date="2008-12-11" time="12:00:00" formatted="12/11/2008 12:00AM">2008-12-11T12:00:00Z</datetime>
<body>
Are you interested in?
<attachments>
<attachment id="1">
<message id="0">
<sender>anonymous@gmail.com</sender>
<to>gukaitong@gmail.com</to>
<body>
We strongly recommend the following books
<books xmlns:amazon="http://www.amazon.com/books/schema">
<amazon:book>
<name>Professional C# 2008 </name>
<country>USA</country>
<price>37.79</price>
<year>2007</year>
</amazon:book>
<amazon:book>
<name>Microsoft Visual C# 2008 Step by Step </name>
<country>USA</country>
<price>26.39 </price>
<year>2008</year>
</amazon:book>
<amazon:book>
<name>C# in Depth</name>
<country>USA</country>
<price>29.69 </price>
<year>2006</year>
</amazon:book>
<amazon:book>
<name>Thinking in Java</name>
<country>USA</country>
<price>23.69 </price>
<year>2004</year>
</amazon:book>
</books>
</body>
</message>
</attachment>
</attachments>
</body>
</message>
<message id="2">
<sender>333@gmail.com</sender>
<to>444@gmail.com</to>
<subject>No title</subject>
<body/>
</message>
</messages>

XPath简介

XPath是W3C的一个标准。它最主要的目的是为了在XML1.0或XML1.1文档节点树中定位节点所设计。目前有XPath1.0和XPath2.0两个版本。其中Xpath1.0是1999年成为W3C标准,而XPath2.0标准的确立是在2007年。W3C关于XPath的英文详细文档请见:http://www.w3.org/TR/xpath20/ 。

XPath是一种表达式语言,它的返回值可能是节点,节点集合,原子值,以及节点和原子值的混合等。XPath2.0是XPath1.0的超集。它是对XPath1.0的扩展,它可以支持更加丰富的数据类型,并且XPath2.0保持了对XPath1.0的相对很好的向后兼容性,几乎所有的XPath2.0的返回结果都可以和XPath1.0保持一样。另外XPath2.0也是XSLT2.0和XQuery1.0的用于查询定位节点的主表达式语言。XQuery1.0是对XPath2.0的扩展。关于在XSLT和XQuery中使用XPath表达式定位节点的知识在后面的实例中会有所介绍。

在学习XPath之前你应该对XML的节点,元素,属性,原子值(文本),处理指令,注释,根节点(文档节点),命名空间以及对节点间的关系如:父(Parent),子(Children),兄弟(Sibling),先辈(Ancestor),后代(Descendant)等概念有所了解。这里不在说明。

XPath路径表达式

在本小节下面的内容中你将可以学习到:

  • 路径表达式语法
  • 相对/绝对路径
  • 表达式上下文
  • 谓词(筛选表达式)及轴的概念
  • 运算符及特殊字符
  • 常用表达式实例
  • 函数及说明

这里给出一个实例Xml文件。下面的说明及实例都是基于该XML文件。

路径表达式语法:

  1. 路径 = 相对路径 | 绝对路径
  2. XPath路径表达式 = 步进表达式 | 相对路径 "/"步进表达式。
  3. 步进表达式=轴 节点测试 谓词

说明:

  1. 其中轴表示步进表达式选择的节点和当前上下文节点间的树状关系(层次关系),节点测试指定步进表达式选择的节点名称扩展名,谓词即相当于过滤表达式以进一步过滤细化节点集。
  2. 谓词可以是0个或多个。多个多个谓词用逻辑操作符and, or连接。取逻辑非用not()函数。
请看一个典型的XPath查询表达式:/messages/message//child::node()[@id=0],其中/messages/message是路径(绝对路径以"/"开始),child::是轴表示在子节点下选择,node()是节点测试表示选择所有的节点。[@id=0]是谓词,表示选择所有有属性id并且值为0的节点。
 
相对路径与绝对路径:
如果"/"处在XPath表达式开头则表示文档根元素,(表达式中间作为分隔符用以分割每一个步进表达式)如:/messages/message/subject是一种绝对路径表示法,它表明是从文档根开始查找节点。假设当前节点是在第一个message节点【/messages/message[1]】,则路径表达式subject(路径前没有"/")这种表示法称为相对路径,表明从当前节点开始查找。具体请见下面所述的"表达式上下文"。
表达式上下文(Context):
上下文其实表示一种环境。以明确当前XPath路径表达式处在什么样的环境下执行。例如同样一个路径表达式处在对根节点操作的环境和处在对某一个特定子节点操作的环境下执行所获得的结果可能是完全不一样的。也就是说XPath路径表达式计算结果取决于它所处的上下文。
XPath上下文基本有以下几种
  • 当前节点(./): 
    如./sender表示选择当前节点下的sender节点集合(等同于下面所讲的"特定元素",如:sender)
  • 父节点(../): 
    如../sender表示选择当前节点的父节点下的sender节点集合
  • 根元素(/): 
    如/messages表示选择从文档根节点下的messages节点集合.
  • 根节点(/*): 
    这里的*是代表所有节点,但是根元素只有一个,所以这里表示根节点。/*的返回结果和/messages返回的结果一样都是messages节点。
  • 递归下降(//): 
    如当前上下文是messages节点。则//sender将返回以下结果: 
    /messages//sender : 
    <sender>gkt1980@gmail.com</sender> 
    <sender>111@gmail.com</sender> 
    <sender>333@gmail.com</sender>

    /messages/message[1]//sender: 
    <sender>gkt1980@gmail.com</sender> 
    <sender>111@gmail.com</sender>

    我们可以看出XPath表达式返回的结果是:从当前节点开始递归步进搜索当前节点下的所有子节点找到满足条件的节点集。

  • 特定元素 
    如sender:表示选择当前节点下的sender节点集合,等同于(./sender)
注意:在执行XPath时一定要注意上下文。即当前是在哪个节点下执行XPath表达式。这在XMLDOM中很重要。如:在XMLDOM中的selectNodes,selectSingleNode方法的参数都是一个XPath表达式,此时这个XPath表达式的执行上下文就是调用这个方法的节点及它所在的环境。更多信息请参见:http://www.w3.org/TR/xpath20/
谓词(筛选表达式)及轴的概念
XPath的谓词即筛选表达式,类似于SQL的where子句.
轴名称
结果
ancestor
选取当前节点的所有先辈(父、祖父等)
ancestor-or-self
选取当前节点的所有先辈(父、祖父等)以及当前节点本身
attribute
选取当前节点的所有属性
child
选取当前节点的所有子元素。
descendant
选取当前节点的所有后代元素(子、孙等)。
descendant-or-self
选取当前节点的所有后代元素(子、孙等)以及当前节点本身。
following
选取文档中当前节点的结束标签之后的所有节点。
namespace
选取当前节点的所有命名空间节点
parent
选取当前节点的父节点。
preceding
直到所有这个节点的父辈节点,顺序选择每个父辈节点前的所有同级节点
preceding-sibling
选取当前节点之前的所有同级节点。
self
选取当前节点。
运算符及特殊字符:
运算符/特殊字符
说明
/
此路径运算符出现在模式开头时,表示应从根节点选择。
//
从当前节点开始递归下降,此路径运算符出现在模式开头时,表示应从根节点递归下降。
.
当前上下文。
..
当前上下文节点父级。
*
通配符;选择所有元素节点与元素名无关。(不包括文本,注释,指令等节点,如果也要包含这些节点请用node()函数)
@
属性名的前缀。
@*
选择所有属性,与名称无关。
:
命名空间分隔符;将命名空间前缀与元素名或属性名分隔。
( )
括号运算符(优先级最高),强制运算优先级。
[ ]
应用筛选模式(即谓词,包括"过滤表达式"和"轴(向前/向后)")。
[ ]
下标运算符;用于在集合中编制索引。
|
两个节点集合的联合,如://messages/message/to | //messages/message/cc
-
减法。
div,
浮点除法。
and, or
逻辑运算。
mod
求余。
not()
逻辑非
=
等于
!=
不等于
特殊比较运算符
< 或者 &lt;
<= 或者 &lt;=
> 或者 &gt;
>= 或者 &gt;=
需要转义的时候必须使用转义的形式,如在XSLT中,而在XMLDOM的scripting中不需要转义。
常用表达式实例:
/
Document Root文档根.
/*
选择文档根下面的所有元素节点,即根节点(XML文档只有一个根节点)
/node()
根元素下所有的节点(包括文本节点,注释节点等)
/text()
查找文档根节点下的所有文本节点
/messages/message
messages节点下的所有message节点
/messages/message[1]
messages节点下的第一个message节点
/messages/message[1]/self::node()
第一个message节点(self轴表示自身,node()表示选择所有节点)
/messages/message[1]/node()
第一个message节点下的所有子节点
/messages/message[1]/*[last()]
第一个message节点的最后一个子节点
/messages/message[1]/[last()]
Error,谓词前必须是节点或节点集
/messages/message[1]/node()[last()]
第一个message节点的最后一个子节点
/messages/message[1]/text()
第一个message节点的所有子节点
/messages/message[1]//text()
第一个message节点下递归下降查找所有的文本节点(无限深度)
/messages/message[1] /child::node()
/messages/message[1] /node()
/messages/message[position()=1]/node()
//message[@id=1] /node()
第一个message节点下的所有子节点
//message[@id=1] //child::node()
递归所有子节点(无限深度)
//message[position()=1]/node()
选择id=1的message节点以及id=0的message节点
/messages/message[1] /parent::*
Messages节点
/messages/message[1]/body/attachments/parent::node()
/messages/message[1]/body/attachments/parent::* /messages/message[1]/body/attachments/..
attachments节点的父节点。父节点只有一个,所以node()和* 返回结果一样。
(..也表示父节点. 表示自身节点)
//message[@id=0]/ancestor::*
Ancestor轴表示所有的祖辈,父,祖父等。
向上递归
//message[@id=0]/ancestor-or-self::*
向上递归,包含自身
//message[@id=0]/ancestor::node()
对比使用*,多一个文档根元素(Document root)
/messages/message[1]/descendant::node()
//messages/message[1]//node()
递归下降查找message节点的所有节点
/messages/message[1]/sender/following::*
查找第一个message节点的sender节点后的所有同级节点,并对每一个同级节点递归向下查找。
//message[@id=1]/sender/following-sibling::*
查找id=1的message节点的sender节点的所有后续的同级节点。
//message[@id=1]/datetime/@date
查找id=1的message节点的datetime节点的date属性
//message[@id=1]/datetime[@date]
//message/datetime[attribute::date]
查找id=1的message节点的所有含有date属性的datetime节点
//message[datetime]
查找所有含有datetime节点的message节点
//message/datetime/attribute::*
//message/datetime/attribute::node()
//message/datetime/@*
返回message节点下datetime节点的所有属性节点
//message/datetime[attribute::*]
//message/datetime[attribute::node()]
//message/datetime[@*]
//message/datetime[@node()]
选择所有含有属性的datetime节点
//attribute::*
选择根节点下的所有属性节点
//message[@id=0]/body/preceding::node()
顺序选择body节点所在节点前的所有同级节点。(查找顺序为:先找到body节点的顶级节点(根节点),得到根节点标签前的所有同级节点,执行完成后继续向下一级,顺序得到该节点标签前的所有同级节点,依次类推。)
注意:查找同级节点是顺序查找,而不是递归查找。
//message[@id=0]/body/preceding-sibling::node()
顺序查找body标签前的所有同级节点。(和上例一个最大的区别是:不从最顶层开始到body节点逐层查找。我们可以理解成少了一个循环,而只查找当前节点前的同级节点)
//message[@id=1]//*[namespace::amazon]
查找id=1的所有message节点下的所有命名空间为amazon的节点。
//namespace::*
文档中的所有的命名空间节点。(包括默认命名空间xmlns:xml)
//message[@id=0]//books/*[local-name()='book']
选择books下的所有的book节点,
注意:由于book节点定义了命名空间<amazone:book>.若写成//message[@id=0]//books/book则查找不出任何节点。
//message[@id=0]//books/*[local-name()='book' and namespace-uri()='http://www.amazon.com/books/schema']
选择books下的所有的book节点,(节点名和命名空间都匹配)
//message[@id=0]//books/*[local-name()='book'][year>2006]
选择year节点值>2006的book节点
//message[@id=0]//books/*[local-name()='book'][1]/year>2006
指示第一个book节点的year节点值是否大于2006.
返回xs:boolean: true
函数及说明: 
值得欣喜的是XPath函数和XSLT,XQuery等共享函数库,函数库为我们提供了功能丰富的各种函数的调用,我们也可以自定义自己的函数。这里不再对每个函数的用法逐一说明,英文好点的朋友直接去看看w3关于XPath函数的介绍吧:http://www.w3.org/TR/xquery-operators 。中文的可以参考这个网站, http://www.w3school.com.cn/xpath/xpath_functions.asp
 
XPath在DOM,XSLT及XQuery中的应用

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title>XPath Test</title> 
</head> 
<body>

<script language="javascript" type="text/javascript"> 
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); 
xmlDoc.async="false"; 
xmlDoc.load("messages.xml"); 
xmlDoc.setProperty("SelectionLanguage", "XPath"); 
    var sPath = "/messages/message[1]//books/*[local-name()='book']"; 
var bookNodes = xmlDoc.selectNodes(sPath);

document.write("<ul>"); 
for ( var i = 0; i < bookNodes.length; i++) { 
document.write("<li>" + bookNodes[i].childNodes[0].text + "</li>"); 

document.write("</ul>"); 
</script>

</body> 
</html>

注意
我们若使用new ActiveXObject("Microsoft.XMLDOM")则需要注意的是:因为早期的XMLDOM的SelectionLanguage属性默认是正则表达式,不是XPath语言。所以需要指定这样一条语句xmlDoc.setProperty("SelectionLanguage", "XPath"); 以支持XPath查询表达式。.
若没有指定SelectionLanguage属性值为XPath则要注意以下情况:
  1. 数组下标从0开始(我们知道在XPath查询表达式中数组下标是从1开始的)
  2. 不支持在XPath查询表达式中使用XPath函数。
XSLT: 
见:我的另外一篇关于如何使用XSLT的一个小示范http://www.cnblogs.com/ktgu/archive/2008/12/14/1354890.html
XQuery: 

xquery version "1.0";

<ul> 

let $i := 0 
for $x in doc("C:\Users\Administrator\Desktop\messages.xml")//message[@id=0]//books/*[local-name()='book'] 
where $x/year>2006 
order by $x/year descending 
return <li>{ data($x/name) } </li> 

</ul>

返回结果

<ul> 
    <li>Microsoft Visual C# 2008 Step by Step </li> 
    <li>Professional C# 2008 </li> 
</ul>

XPath总结(转)的更多相关文章

  1. xpath提取多个标签下的text

    title: xpath提取多个标签下的text author: 青南 date: 2015-01-17 16:01:07 categories: [Python] tags: [xpath,Pyth ...

  2. C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子)

    第一次接触HtmlAgilityPack是在5年前,一些意外,让我从技术部门临时调到销售部门,负责建立一些流程和寻找潜在客户,最后在阿里巴巴找到了很多客户信息,非常全面,刚开始是手动复制到Excel, ...

  3. 在Java中使用xpath对xml解析

    xpath是一门在xml文档中查找信息的语言.xpath用于在XML文档中通过元素和属性进行导航.它的返回值可能是节点,节点集合,文本,以及节点和文本的混合等.在学习本文档之前应该对XML的节点,元素 ...

  4. XPath 学习二: 语法

    XPath 使用路径表达式来选取 XML 文档中的节点或节点集.节点是通过沿着路径 (path) 或者步 (steps) 来选取的. 下面列出了最有用的路径表达式: 表达式 描述 nodename 选 ...

  5. xpath 学习一: 节点

    xpath 中,有七种类型的节点: 元素.属性.文本.命名空间.处理指令.注释.以及根节点 树的根成为文档节点或者根节点. 节点关系: Parent, Children, sibling(同胞), A ...

  6. Python爬虫利器三之Xpath语法与lxml库的用法

    前面我们介绍了 BeautifulSoup 的用法,这个已经是非常强大的库了,不过还有一些比较流行的解析库,例如 lxml,使用的是 Xpath 语法,同样是效率比较高的解析方法.如果大家对 Beau ...

  7. 使用python+xpath 获取https://pypi.python.org/pypi/lxml/2.3/的下载链接

    使用python+xpath 获取https://pypi.python.org/pypi/lxml/2.3/的下载链接: 使用requests获取html后,分析html中的标签发现所需要的链接在& ...

  8. 关于robotframework,app,appium的xpath定位问题及常用方法

    关于类似的帖子好像很多,但是没有找到具体能帮我解决问题的办法.还是自己深究了好久才基本知道app上面的xpath定位和web上的不同点: 先放一个图: A,先说说不用xpath的场景,一般是用于存在i ...

  9. Selenium Xpath Tutorials - Identifying xpath for element with examples to use in selenium

    Xpath in selenium is close to must required. XPath is element locator and you need to provide xpath ...

  10. xpath定位中starts-with、contains和text()的用法

    starts-with 顾名思义,匹配一个属性开始位置的关键字 contains 匹配一个属性值中包含的字符串 text() 匹配的是显示文本信息,此处也可以用来做定位用 eg //input[sta ...

随机推荐

  1. SQL中使用的一些函数问题

    abs()取绝对值ceil()上取整floor()下取整initcap()使串中的所有单词的首字母变为大写substr()取子串 这些函数都是oracle的sql内置函数.

  2. maven+jetty项目在tomcat部署

    步骤1:项目打包 clean install 步骤二:拷贝war 包到tomcat下 步骤三:修改server.xml文件的端口 步骤四:启动tomcat,注意jetty的项目是不需要带项目名的,To ...

  3. Extjs 4学习2

    主要学习采自:http://www.ishowshao.com/blog/2012/06/19/extjs-4-getting-started/ 用的sdk为extjs4.2.1 根据其中的提示装了一 ...

  4. 《find技巧》-“linux命令五分系列”之一

    一天一个命令,做个记录, 我要成大神,哈哈哈 本原创文章属于<Linux大棚>博客. 博客地址为http://roclinux.cn. 文章作者为roc 希望您能通过捐款的方式支持Linu ...

  5. 字体圆润属性的使用-webkit-font-smoothing: antialiased

    字体渲染和抗锯齿技术 据称该属性在window下不起作用,不知win10如何,但是在OS和ios中会有不同的展示效果,主要也是展示在webkit内核中,以及android和ios中 大概是说字体渲染的 ...

  6. php基于数组的分页实现

    关于数组的分页函数,用数组进行分页的好处是可以方便的进行联合多表查询,只需要将查询的结果放在数组中就可以了以下是数组分页的函数,函数page_array用于数组的分页,函数show_array用于分页 ...

  7. coreseek(sphinx)错误:WARNING: attribute 'id' not found - IGNORING

    coreseek(sphinx)错误:WARNING: attribute 'id' not found - IGNORING原因及解决方法 coreseek(sphinx)建立索引时提示错误: WA ...

  8. 解决xp共享的批处理文件

    在空白地方点右键选择新建一个文本文档,将默认的“新建 文本文档.txt”文件名改名为以下红色加粗字体内容,再复制红色内容以下的黑字部分到改名后的文档.其他文件生成的方法相同.完成后根据需要双击CMD扩 ...

  9. Python 的“+”和append在添加字符串时候的区别

    对于一个空的Python列表,往后添加内容有很多种,其中两种一个是用“+”直接添加内容,另外一种是Listname.append(x)来添加内容 其中,如果处理字符串 在使用“+”的时候,会将字符串拆 ...

  10. iOS9 未受信任的企业级开发者

    升级iOS9,app打不开怎么办?6个步骤让你应对“未受信任的企业及开发者账号” 点开App,弹出未受信任的开发者,记住弹框中冒号后面的大写字母.关闭,进入设置. 进入通用 进入描述文件 找到所对应的 ...