zoukankan      html  css  js  c++  java
  • XML之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 :
      gkt1980@gmail.com
      111@gmail.com
      333@gmail.com

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

      我们可以看出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() 逻辑非
    = 等于
    != 不等于
    特殊比较运算符
    < 或者 <
    <= 或者 <=
    > 或者 >
    >= 或者 >=
    需要转义的时候必须使用转义的形式,如在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节点定义了命名空间.若写成//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中的应用
    DOM
    http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    http://www.w3.org/1999/xhtml">
     
     例如:
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <catalog>
     <cd country="USA">
      <title>Empire Burlesque</title>
      <artist>Bob Dylan</artist>
      <price>10.90</price>
     </cd>
     <cd country="UK">
      <title>Hide your heart</title>
      <artist>Bonnie Tyler</artist>
      <price>9.90</price>
     </cd>
     <cd country="USA">
      <title>Greatest Hits</title>
      <artist>Dolly Parton</artist>
      <price>9.90</price>
     </cd>
    </catalog>
     
    以下语法选择catalog中的第一个cd元素
    /catalog/cd[1]
     
    以下语法选择catalog中的最后一个cd元素:(XPathj并没有定义 first() 这种函式喔,用上例的 [1]就可以取出第一个元素。
    /catalog/cd[last()]
     
    以下语法选出含有price子元素的所有/catalog/cd元素。
    /catalog/cd[price]
     
    以下语法选出price元素的值等于10.90的所有/catalog/cd元素
    /catalog/cd[price=10.90]
     
    以下语法选出price元素的值等于10.90的所有/catalog/cd元素 的price元素
    /catalog/cd[price=10.90]/price
     
    选择所有title以及artist元素
    //title | //artist
     
    选择所有title以及artist以及price元素
    //title | //artist | //price
      
    选择所有含有country这个属性的cd元素:
    //cd[@country]
     
    以下语法选择出含有属性的所有cd元素
    //cd[@*]
     
    以下语法选择出country属性值为UK的cd元素
    //cd[@country='UK']
     
    只要掌握了xpath语法,理论上你就可以访问xml文件中的任意节点和任意值
    XmlNode xmlnode = xmldoc.SelectSingleNode("//document/section[@id='pla-01']/data[@id='fou_scc_code']");
     

    注意的是:数组下标从0开始(我们知道在XPath查询表达式中数组下标是从1开始的),并且不支持XPath查询表达式中使用XPath函数

     

  • 相关阅读:
    博客搬到blog.csgrandeur.com
    CSGrandeur的WebGL学习——WebGL教程
    hihoCoder 1160 攻城略地
    HDU 5212 Code
    Ubuntu 14.04 MySQL同步
    Ubuntu 用vsftpd 配置FTP服务器
    Ubuntu14.04 Server amd64 配置 Apache+MySQL+Django
    LeetCode OJ 题解
    MFC+Android模拟器 实现 自动玩“天天爱消除”
    湖南2013第九届省赛解题报告(长期拖延更新中。。。)
  • 原文地址:https://www.cnblogs.com/fuland/p/3754148.html
Copyright © 2011-2022 走看看