第四章路径定位语言XPath一.XPath基本概念二.基本表达式三.较详细的语法一、XPath基本概念1.XPath的作用2.XPath依据的数据模型3.树结点关系和文档次序4.表达式的上下文和运算结果1.XPath的作用•XPath是W3C的一个技术规范,这个规范的目的是为XML数据的寻址、定位制定一套表达式及其语法语义。•XPath只规定语法语义,其中主要是规定定位表达式和一些函数的语法及其功能,至于如何实现这些表达式和函数的功能,则是软件开发商的事情。如果一个软件实现了XPath的功能,则称该软件支持XPath。•XPath在XSLT、XPointer中都有重要作用,对于XML数据库的研究,XPath也非常重要,它是XML数据库的查询语言XQuery的重要组成部分。XQuery的作用相当于SQL对于关系数据库的作用。•XPath当前的最新版本是XPath2.0,本章只介绍1999年11月公布的XPath1.0。2.XPath依据的数据模型booksbookbookbookISBNdatePub-lisherpricetext1text2text3text4text6text7categorylangcntext5rootPItitleauthorsauthorauthor共有7种类型的结点:•文档根结点,每个XML文档对应一个文档根结点。•元素结点,文档中每个元素对应一个元素结点。•属性结点,元素的每一个属性对应一个属性结点。•命名空间结点。XPath用结点表示命名空间,但并不是整个文档涉及到几个命名空间就用几个结点表示,而是将每个元素所涉及的命名空间各用若干个结点表示。所谓元素涉及的命名空间,是指那些作用域包含这个元素的命名空间。•处理指令结点,若文档中出现处理指令,则指令本身也是一个结点。•注释结点,文档中的注释也是结点。•文本结点,包含在元素中的文本视为一个结点。•XPath的数据模型与XSLT的数据模型是一样的,只不过XSLT不处理命名空间,而XPath可以通过表达式访问命名空间结点。•命名空间结点从属于元素,每个元素总有一个以上的命名空间结点,其中有一个是默认的,其命名空间URI是•例如,对于如下元素:p:axmlns:p==:a•元素p:a将拥有两个命名空间结点,元素q:b将拥有三个命名空间结点。•元素不包括前缀xmlns对应的命名空间,因为应用程序永远不会遇到前缀为xmlns的元素名称和属性名称。•对于没有命名空间前缀的元素名称,有两种情况,一种是没有指定命名空间的名称,另一种是默认命名空间的名称。•例如:a/bxmlns=.树结点关系和文档顺序•如果在树结构图中,沿着树根向树叶的方向,结点B紧随在结点A的后面,则称A为B的父结点。•如果B不是属性结点或命名空间结点,则B称为A的子结点,但如果B是属性结点或命名空间结点,则A为B的父结点,但B不是A的子结点。•结点A的父结点以及父结点的父结点,…,总之沿着结点A向树根方向上溯到根结点所遇到的所有结点称为A的祖先结点。•结点A的所有子结点,以及子结点的子结点,…,依此类推的所有结点称为A的后裔结点。•如果结点A和B是同一个结点的子结点,则称A、B为兄弟结点。•兄弟结点之间存在次序,这种次序就是文档次序,在文档中先出现的结点称为兄结点,后出现的称为弟结点。•属性结点和命名空间结点没有兄弟结点。4.表达式的上下文和运算结果•XPath用一种类似于磁盘文件路径的方式来定位树中的结点。例如,/books/book/title。•对于磁盘文件,同一个目录下不能有同名的子目录或文件,但XML文档树中,经常出现同名的子结点,因此表达式指定的将是一个结点集而非单个结点。•一般情况下,视所使用的表达式而定,XPath表达式运算的结果将是一个结点集、一串字符、一个数字或一个布尔值。•使用XPath表达式涉及到使用的上下文。例如,当我们定位结点A的子结点时,这时所谓“子结点”是相对于结点A而言的,我们称A为“当前结点”。•当前结点一般由应用XPath的程序决定。二、基本表达式1.选择结点集2.谓词3.选择未知结点4.多重路径选择1.选择结点集•XPath用所谓“定位路径”来选择(定位)一个或多个结点,在这种路径表达式中,经常使用下列符号:–“/”:选择根结点–“//”:选择当前结点所有后裔结点–“.”:选择当前结点–“..”:选择当前结点的父结点–“@”:选择属性结点例如:•publisher:选择当前结点的子结点中名为publisher的结点。•/:选择根结点•/books:选择根结点下所有子结点中名为books的结点。•/books/book:选择根结点下books结点的所有子结点book。•/books/book/@category:对于根结点下books的所有子结点book,选择其属性category。•authors/author:在当前结点下寻找子结点authors,然后选择其子结点author。•//title:从根结点出发,选择所有的后裔结点title。•books//price:选择books的所有后裔结点price。•//@lang:选择根结点的所有后裔结点中的属性lang。2.谓词•如果需要从路径表达式选择出来的结点集中进行筛选,就要使用谓词(predicate)。谓词是包含在一对方括号中的表达式,这种表达式可以是布尔表达式,也可以是常数、数值表达式或函数。例如:–/books/book[1]。在文档中最先出现的book结点。–//book[@category=’TP312’]。从book结点集中筛选出属性category等于TB312的结点。–/books/book[position()=3],选择兄弟结点的前3个。–函数last()返回最后一个兄弟结点的序号,因此,/books/book[last()]得到的就是最后一个book结点。–position()和last()得到的是兄弟结点之间的序号,而不是当前结点在整个文档中的序号,因此,//author[1]将得到每族兄弟结点的第一个,也就是说,每本书的第一作者。–//title[@lang]将选择所有具有属性lang的结点。–//book[price30]选择这样的book结点,其price子结点的文本内容转换为数字之后大于30。3.选择未知结点•可以使用通配符“*”表示选择所有的东西。典型的用法有:*:匹配所有的元素结点。@*:匹配所有的属性结点。•例如:/books/*:选择books的所有元素子结点。/*:选择根结点下所有元素子结点。//*:选择文档中所有的元素结点。//book[@*]:选择所有具有属性(不管是什么属性)的book结点。//@*:选择文档中所有的属性,无论是什么属性,属于哪个元素。4.多重路径选择•可以同时指定多条路径,彼此用“|”隔开,即:路径1|路径2|….|路径n•符号“|”在此处的含义是“并”,即,n条路径都可以选,结果是n条路径各自选择结果的并集。•例如,//book/title|//book/price选择所有的book子结点title和price。//@category|//@lang选择文档中所有的category属性和lang属性三、较详细的语法1.定位路径2.定位步骤3.定位轴4.结点测试5.缩写语法6.谓词7.核心函数1.定位路径•XPath定位路径(locationpath)由若干个定位步骤所组成,定位步骤彼此之间用“/”隔开。例如,/books/book/title[@lang=’cn’]由三个定位步骤books、book和title[@lang=’cn’]所组成。•每一定位步骤指定一个结点集,后继步骤以这个结点集中的每一结点为当前结点进行运算,所有的运算结果合并起来作为后继步骤的结果。•定位路径分为绝对路径和相对路径两种。绝对路径以“/”开头,绝对路径以文档根结点为当前结点,依次处理每个定位步骤。相对路径开头没有“/”,从当前结点开始依次处理每个定位步骤,当前结点由应用XPath的程序决定。•例如,XSLT的一个模板:xsl:templatematch=“/books”!--绝对路径--xsl:for-eachselect=“book”!--相对路径--xsl:value-ofselect=“title”/!--相对路径--/xsl:for-each/xsl:template2.定位步骤•每一定位步骤(locationstep)由三部分组成:1.轴(axis)。轴指出定位寻址的方向,XPath总共定义了13条轴,大致上可以分为3类,一类是树结构中祖先、后裔关系的轴向,另一类是文档顺序先后关系的轴向,还有一类是属性和命名空间这两条特殊轴。2.结点测试(Nodetest)。结点测试指出要定位的结点,例如,用结点名称、属性名称指出要定位的结点。如果要定位的结点是注释、处理指令、文本或命名空间,这些结点没有名称,必须用特殊的语法。3.谓词(predicate)。谓词可有可无,也可以同时使用多个谓词。例如,book[last()][@lang=’en’]同时使用了两个谓词,其语义是先按照第一个谓词,挑选出最后一个book结点,然后再按照第二个谓词,在挑出来的结点中选择@lang=’en’的结点。•轴有指定的名称,但我们一般使用缩写,例如:/books/book/title[@lang=’cn’],每一定位步骤中都省略了轴的名称child,如果写完整,应该是:/child::books/child::book/child::title[@lang=’cn’]•XPath规定,child是默认轴,因此可以省略。•在定位步骤中,如果使用完整的轴名而不是缩写符号,则轴名和结点测试之间用两个冒号“::”连接。3.定位轴•XPath定义的13条轴的完整名称和含义:–Ancestor:当前结点的所有祖先。–Ancestor-or-self:当前结点自己及其所有祖先。–Attribute:当前结点的所有属性结点。–Child:当前结点的所有子结点。–Descendant:当前结点的所有后裔。–descendant-or-self:当前结点自己及其所有后裔。–Following:当前结点按文档顺序的所有后继结点,即在当前结点结束标记之后出现的结点。不包括当前结点的后裔结点,也不包括属性结点和命名空间结点。–following-sibling:当前结点的所有弟结点。–Namespace:当前结点的命名空间结点。–Parent:当前结点的父结点。–Preceding:当前结点按文档顺序的所有先前结点,即在当前结点起始标记之前出现的结点,但不包括当前结点的祖先结点,也不包括属性结点和命名空间结点。–preceding-sibling:当前结点的所有兄结点。–Self:当前结点自己。以附录1文档为例:•/books/book[1]/title/ancestor::book将得到book[1]。•/books/book[1]/descendant::*将得到book[1]的所有子结点和两个孙结点author。•/books/book[1]/following::*将得到book[2]、book[3]、book[4]、book[5]以及这些结点的所有子孙结点。•/books/book[1]/following-sibling::*将只得到第二到第五个book结点。•attribute指向属性结点,可用@表示。•namespace指向命名空间结点。每个元素所涉及的命名空间各自被视为一个结点,元素结点是这些结点的父结点,但命名空间结点不是元素结点的子结点。因此,要访问命名空间结点不能用child轴,只能用专用的轴namespace。