XML - 数据交换管理/XPath
上一章 | 下一章 |
← XHTML | XLink → |
学习目标
|
在前面的章节中,您已经学习了 XSL 的基本概念,以及在执行 XSL 转换时必须如何引用 XML 文档中的节点。到目前为止,您一直在使用一种简单的语法来引用 XML 文档中的节点。虽然您迄今为止使用的语法一直是 XPath,但您将在本章中学习更多功能和功能。当您开始理解路径语言如何用于引用 XML 文档中的节点时,您对 XML 作为树形结构的理解将开始就位。本章包含演示 XPath 许多常见用法的示例,但有关完整的 XPath 规范,请参阅标准的最新版本:
XSL 大量使用 XPath。
当您在命令提示符下复制文件或“cd”到目录时,您通常会键入类似“/home/darnell/”的内容来引用文件夹。这使您能够在整个计算机的文件系统中更改或引用文件夹。XML 具有类似的方式来引用 XML 文档中的元素。这种特殊的语法称为 XPath,它是 XML 路径语言的缩写。
XPath 是一种用于在 XML 文档中查找信息的语言。XPath 用于在 XML 文档中遍历元素和属性。
XPath 虽然用于引用 XML 树中的节点,但它本身不是用 XML 编写的。这是 W3C 明智的选择,因为试图在 XML 中指定路径信息将是一项非常繁琐的任务。任何构成 XML 语法的字符都需要转义,以便在处理时不会与 XML 混淆。XPath 也很简洁,允许您以非常高的特异性调用 XML 树中的节点,而不会显得过于冗长。
XML 的一大好处是文档本身描述了数据的结构。如果您中的任何人都研究过您的家族史,您可能已经遇到过家谱。树的顶部是某个早期的祖先,而树的底部是最近的孩子。
通过树形结构,您可以看到哪些孩子属于哪些父母,哪些孙子属于哪些祖父母等等。
XML 的妙处在于它也很适合这种树形结构,通常被称为 XML 树。
我们将使用以下示例来演示不同的节点关系。
<bookstore>
<book>
<title>Less Than Zero</title>
<author>Bret Easton Ellis</author>
<year>1985</year>
<price>13.95</price>
</book>
</bookstore>
- 父节点
- 每个元素和属性都有一个父节点。
- book 元素是 title、author、year 和 price 的父节点
- 子节点
- 元素节点可以有零个、一个或多个子节点。
- title、author、year 和 price 元素都是 book 元素的子节点
- 兄弟姐妹
- 具有相同父节点的节点。
- title、author、year 和 price 元素都是兄弟姐妹
- 祖先
- 节点的父节点、父节点的父节点等等。
- title 元素的祖先是 book 元素和 bookstore 元素
- 后代
- 节点的子节点、子节点的子节点等等。
- bookstore 元素的后代是 book、title、author、year 和 price 元素
此外,将 XML 文件同时视为序列化文件(例如,您在 XML 编辑器中看到的)在某些方面仍然有用。这样您就可以理解前一个节点和后一个节点的概念。如果原始节点在文档顺序中位于另一个节点之前,则该节点被认为在另一个节点之前。同样,如果一个节点在另一个节点之后出现在文档顺序中,则它在该节点之后。祖先和后代不被认为是前一个或后一个节点。这个概念在稍后讨论轴的概念时会派上用场。
XPath 的创建是为了简洁地引用节点,同时保留搜索多种选项的能力。XPath 的大多数用法将涉及搜索特定节点的子节点、父节点或属性节点。由于这些用法非常普遍,因此可以使用简写语法来引用这些常用的节点。以下是模拟树(有叶子和树枝的树)的 XML 文档。它将用于演示不同类型的语法。
<?xml version="1.0" encoding="UTF-8"?>
<trunk name="the_trunk">
<bigBranch name="bb1" thickness="thick">
<smallBranch name="sb1">
<leaf name="leaf1" color="brown" />
<leaf name="leaf2" weight="50" />
<leaf name="leaf3" />
</smallBranch>
<smallBranch name="sb2">
<leaf name="leaf4" weight="90" />
<leaf name="leaf5" color="purple" />
</smallBranch>
</bigBranch>
<bigBranch name="bb2">
<smallBranch name="sb3">
<leaf name="leaf6" />
</smallBranch>
<smallBranch name="sb4">
<leaf name="leaf7" />
<leaf name="leaf8" />
<leaf name="leaf9" color="black" />
<leaf name="leaf10" weight="100" />
</smallBranch>
</bigBranch>
</trunk>
示例 9.2:tree. xml – 示例 XML 页面
以下是一些 XPath 位置路径的示例,分别用英语、简写 XPath 和非简写 XPath 表示。
选择 1
英语:此文档中所有是 trunk 的子节点的 bigBranch 的子节点的 smallBranch 的子节点的 leaf 元素,trunk 是 root 的子节点。
简写:/trunk/bigBranch/smallBranch/leaf
非简写:/child::trunk/child::bigBranch/child::smallBranch/child::leaf
选择 2
英语:具有“name”属性等于“bb3”的 bigBranch 元素,它们是 trunk 元素的子节点,trunk 元素是 root 的子节点。
简写:/trunk/bigBranch[@name=’bb3’]
非简写:/child::trunk/child::bigBranch[attribute::name=’bb3’]
请注意,在前面的示例中,我们如何使用谓词来指定要哪些 bigBranch 对象。这将搜索范围缩小到仅满足谓词的 bigBranch 节点。谓词是 XPath 语句中位于方括号内的部分。在本例中,谓词要求“name”属性设置为“bb3”的 bigBranch 节点。
最后两个示例假设我们想要指定从根节点开始的路径。现在让我们假设我们正在指定从 <smallBranch> 节点开始的路径。
选择 3
英语:当前 <smallBranch> 的父节点。(请注意,此选择相对于 <smallBranch>)
简写 ..
非简写:parent::node()
当使用非简写语法时,您可能会注意到您正在调用一个父节点或子节点,后面跟着两个冒号(::)。每个冒号都称为一个轴。您将在稍后了解有关轴的更多信息。
此外,现在可能是解释位置路径概念的好时机。位置路径是到达所选节点的一系列位置步骤。位置步骤是 XPath 语句中以“/”字符分隔的部分。它们是找到要选择的节点的路径上的一个步骤。
位置步骤由三个部分组成:轴(子节点、父节点、后代节点等)、节点测试(节点名称或检索一个或多个节点的函数)以及一系列谓词(对检索到的节点的测试,以缩小结果范围,排除不通过谓词测试的节点)。
因此,在位置路径中,它的每个位置步骤都会返回一个节点列表。如果在某个位置步骤之后,路径上还有其他步骤,则下一个步骤将在该步骤返回的所有节点上执行。
相对路径与绝对路径
[edit | edit source]在使用 XPath 指定路径时,有时您已经在某个节点“内”。但其他时候,您可能希望从根节点开始选择节点。XPath 允许您同时执行这两种操作。如果您曾经使用过 HTML 中的网站,它的工作原理与在 HTML 超链接中引用其他文件相同。在 HTML 中,您可以为超链接指定绝对路径,在 URL 中描述另一个页面位于服务器名称、文件夹和文件名中的位置。或者,如果您引用同一站点上的另一个文件,则无需输入服务器名称或所有路径信息。这称为相对路径。该概念可以在 XPath 中以类似的方式应用。
您可以通过 XPath 表达式开头是否有“/”字符来判断两者之间的区别。如果有,则路径是从根节点指定的,这使其成为绝对路径。但如果路径开头没有“/”,则您正在指定一个相对路径,该路径描述了其他节点相对于上下文节点(或正在执行下一步的节点)的位置。
以下是用于我们上面树状 .xml 文件(示例 9.2)的 XSL 样式表(示例 9.3)。
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<!-- Example of an absolute link. The element '/child::trunk'
is being specified from the root element. -->
<xsl:template match="/child::trunk">
<html>
<head>
<title>XPath Tree Tests</title>
</head>
<body>
<!-- Example of a relative link. The <for-each> xsl statement will
execute for every <bigBranch> node in the
‘current’ node, which is the <trunk>node. -->
<xsl:for-each select="child::bigBranch">
<xsl:call-template name="print_out" />
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template name="print_out">
<xsl:value-of select="attribute::name" /> <br />
</xsl:template>
</xsl:stylesheet>
示例 9.3:xsl_tree.xsl – 相对路径和绝对路径的示例
四种 XPath 位置路径
[edit | edit source]在最后两节中,您了解了区分不同位置路径的两种不同区别:非缩写与缩写,相对路径与绝对路径。结合这两个概念可能有助于谈论 XPath 位置路径。更不用说,当您说以下内容时,它可以让您在朋友面前显得非常聪明
- 缩写相对位置路径 - 在指定相对路径时使用缩写语法。
- 缩写绝对位置路径 - 在指定绝对路径时使用缩写语法。
- 非缩写相对位置路径 - 在指定相对路径时使用非缩写语法。
- 非缩写绝对位置路径 - 在指定绝对路径时使用非缩写语法。
我只在现在提到这种四路区分,因为它在阅读规范或其他关于该主题的文本时可能会有所帮助。
XPath 轴
[edit | edit source]在 XPath 中,某些节点选择需要非缩写语法才能提高性能。在这种情况下,您将使用轴来指定在位置路径中通过的每个位置步骤。
从树中的任何节点,您都可以沿 13 个轴进行操作。它们如下所示
轴 | 含义 |
---|---|
ancestor: | 从当前节点到根节点的父节点 |
ancestor-or-self: | 从当前节点到根节点的父节点以及当前节点 |
attribute: | 当前节点的属性 |
child: | 当前节点的直接子节点 |
descendant: | 当前节点的子节点(包括子节点的子节点) |
descendant-or-self: | 当前节点的子节点(包括子节点的子节点)以及当前节点 |
following: | 当前节点之后的节点(不包括子节点) |
following-sibling: | 当前节点之后的节点(不包括子节点)处于同一级别 |
namespace: | XML namespace of the current node |
parent: | 当前节点的直接父节点 |
preceding: | 当前节点之前的节点(不包括子节点) |
preceding-sibling: | 当前节点之前的节点(不包括子节点)处于同一级别 |
self: | 当前节点 |
XPath 谓词和函数
[edit | edit source]有时,您可能希望在 XPath 位置路径中使用谓词来进一步过滤您的选择。通常,您会从位置路径中获得一组节点。谓词是一个小的表达式,它会针对一组节点中的每个节点进行评估。如果表达式评估为“false”,则该节点不会包含在选择中。以下是一个示例
//p[@class=‘alert’]
在前面的示例中,文档中的每个 <p> 标签都将被检查,以查看其“class”属性是否设置为“alert”。只有那些“class”属性值为“alert”的 <p> 标签才会包含在此位置路径的节点集中。
以下示例使用一个函数,该函数可以在谓词中使用,以获取有关上下文节点的信息。
/book/chapter[position()=3]
前面的示例仅选择第 3 位的书籍章节。因此,为了返回某些内容,当前 <book> 元素必须至少有 3 个 <chapter> 元素。
还要注意,position 函数返回一个整数。XPath 规范中有许多函数。有关完整列表,请参阅 W3C 规范 http://www.w3.org/TR/xpath#corelib
以下是一些可能会有所帮助的其他函数
number last() – 当前节点集中的最后一个节点
number position() – 正在测试的上下文节点的位置
number count(node-set) – 节点集中节点的数量
boolean starts-with(string, string) – 如果第一个参数以第二个参数开头,则返回 true
boolean contains(string, string) – 如果第一个参数包含第二个参数,则返回 true
number sum(node-set) – 节点集中节点的数值之和
number floor(number) – 数值,向下舍入到最接近的整数
number ceiling(number) – 数值,向上舍入到最接近的整数
number round(number) – 数值,舍入到最接近的整数
示例
[edit | edit source]以下 XML 文档、XSD 架构和 XSL 样式表示例旨在帮助您将本章中学习的所有内容结合使用真实数据。在学习此示例时,您会注意到如何使用 XPath 在样式表中调用和修改从文档中提取的特定信息的输出。
以下是一个 XML 文档(示例 9.4)
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="movies.xsl" type="text/xsl" media="screen"?>
<movieCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="movies.xsd">
<movie>
<movieTitle>Meet the Parents</movieTitle>
<movieSynopsis>
Greg Focker is head over heels in love with his girlfriend Pam, and is ready to
pop the big question. When his attempt to propose is thwarted by a phone call
with the news that Pam's younger sister is getting married, Greg realizes that
the key to Pam's hand in marriage lies with her formidable father.
</movieSynopsis>
<role>
<roleIDREF>bs1</roleIDREF>
<roleType>Lead Actor</roleType>
</role>
<role>
<roleIDREF>tp1</roleIDREF>
<roleType>Lead Actress</roleType>
</role>
<role>
<roleIDREF>rd1</roleIDREF>
<roleType>Lead Actor</roleType>
</role>
<role>
<roleIDREF>bd1</roleIDREF>
<roleType>Supporting Actress</roleType>
</role>
</movie>
<movie>
<movieTitle>Elf</movieTitle>
<movieSynopsis>
One Christmas Eve, a long time ago, a small baby at an orphanage crawled into
Santa’s bag of toys, only to go undetected and accidentally carried back to Santa’s
workshop in the North Pole. Though he was quickly taken under the wing of a surrogate
father and raised to be an elf, as he grows to be three sizes larger than everyone else,
it becomes clear that Buddy will never truly fit into the elf world. What he needs is
to find his real family. This holiday season, Buddy decides to find his true place in the
world and sets off for New York City to track down his roots.
</movieSynopsis>
<role>
<roleIDREF>wf1</roleIDREF>
<roleType>Lead Actor</roleType>
</role>
<role>
<roleIDREF>jc1</roleIDREF>
<roleType>Supporting Actor</roleType>
</role>
<role>
<roleIDREF>zd1</roleIDREF>
<roleType>Lead Actress</roleType>
</role>
<role>
<roleIDREF>ms1</roleIDREF>
<roleType>Supporting Actress</roleType>
</role>
</movie>
<castMember>
<castMemberID>rd1</castMemberID>
<castFirstName>Robert</castFirstName>
<castLastName>De Niro</castLastName>
<castSSN>489-32-5984</castSSN>
<castGender>male</castGender>
</castMember>
<castMember>
<castMemberID>bs1</castMemberID>
<castFirstName>Ben</castFirstName>
<castLastName>Stiller</castLastName>
<castSSN>590-59-2774</castSSN>
<castGender>male</castGender>
</castMember>
<castMember>
<castMemberID>tp1</castMemberID>
<castFirstName>Teri</castFirstName>
<castLastName>Polo</castLastName>
<castSSN>099-37-8765</castSSN>
<castGender>female</castGender>
</castMember>
<castMember>
<castMemberID>bd1</castMemberID>
<castFirstName>Blythe</castFirstName>
<castLastName>Danner</castLastName>
<castSSN>273-44-8690</castSSN>
<castGender>male</castGender>
</castMember>
<castMember>
<castMemberID>wf1</castMemberID>
<castFirstName>Will</castFirstName>
<castLastName>Ferrell</castLastName>
<castSSN>383-56-2095</castSSN>
<castGender>male</castGender>
</castMember>
<castMember>
<castMemberID>jc1</castMemberID>
<castFirstName>James</castFirstName>
<castLastName>Caan</castLastName>
<castSSN>389-49-3029</castSSN>
<castGender>male</castGender>
</castMember>
<castMember>
<castMemberID>zd1</castMemberID>
<castFirstName>Zooey</castFirstName>
<castLastName>Deschanel</castLastName>
<castSSN>309-49-4005</castSSN>
<castGender>female</castGender>
</castMember>
<castMember>
<castMemberID>ms1</castMemberID>
<castFirstName>Mary</castFirstName>
<castLastName>Steenburgen</castLastName>
<castSSN>988-43-4950</castSSN>
<castGender>female</castGender>
</castMember>
</movieCollection>
示例 9.4:movies_xpath.xml
以下是一个 XML 文档(示例 9.5)
<?xml version="1.0" encoding="UTF-8"?>
<cities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="cities.xsd">
<city>
<cityID>c2</cityID>
<cityName>Mandal</cityName>
<cityPopulation>13840</cityPopulation>
<cityCountry>Norway</cityCountry>
<tourismDescription>A small town with a big atmosphere. Mandal provides comfort
away from normal luxuries.
</tourismDescription>
<capitalCity>c3</capitalCity>
</city>
<city>
<cityID>c3</cityID>
<cityName>Oslo</cityName>
<cityPopulation>533050</cityPopulation>
<cityCountry>Norway</cityCountry>
<tourismDescription>Oslo is the capital of Norway for many reasons.
It is also the capital location for tourism. The culture, shopping,
and attractions can all be experienced in Oslo. Just remember
to bring your wallet.
</tourismDescription>
</city>
</cities>
示例 9.5:cites__xpath.xml
以下是“电影”架构(示例 9.6)
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified">
<!--Movie Collection-->
<xsd:element name="movieCollection">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="movie" type="movieDetails" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<!--This contains the movie details.-->
<xsd:complexType name="movieDetails">
<xsd:sequence>
<xsd:element name="movieTitle" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/>
<xsd:element name="movieSynopsis" type="xsd:string"/>
<xsd:element name="role" type="roleDetails" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<!--The contains the genre details.-->
<xsd:complexType name="roleDetails">
<xsd:sequence>
<xsd:element name="roleIDREF" type="xsd:IDREF"/>
<xsd:element name="roleType" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="ssnType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{3}-\d{2}-\d{4}"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="castDetails">
<xsd:sequence>
<xsd:element name="castMemberID" type="xsd:ID"/>
<xsd:element name="castFirstName" type="xsd:string"/>
<xsd:element name="castLastName" type="xsd:string"/>
<xsd:element name="castSSN" type="ssnType"/>
<xsd:element name="castGender" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
示例 9.6:movies.xsd
以下是“城市”架构(示例 9.7)
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:element name="cities">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="city" type="cityType" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="cityType">
<xsd:sequence>
<xsd:element name="cityID" type="xsd:ID"/>
<xsd:element name="cityName" type="xsd:string"/>
<xsd:element name="cityPopulation" type="xsd:integer"/>
<xsd:element name="cityCountry" type="xsd:string"/>
<xsd:element name="tourismDescription" type="xsd:string"/>
<xsd:element name="capitalCity" type="xsd:IDREF" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
示例 9.7:cities.xsd
以下是 XSL 样式表(示例 9.8)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="castList" match="castMember" use="castMemberID"/>
<xsl:output method="html"/>
<!-- example of using an abbreviated absolute path to pull info
from cities_xpath.xml for the city "Oslo" specifically -->
<!-- specify absolute path to select cityName and assign it the variable "city" -->
<xsl:variable name="city" select="document('cities_xpath.xml')
/cities/city[cityName='Oslo']/cityName" />
<!-- specify absolute path to select cityCountry and assign it the variable "country" -->
<xsl:variable name="country" select="document('cities_xpath.xml')
/cities/city[cityName='Oslo']/cityCountry" />
<!-- specify absolute path to select tourismDescription and assign it the variable "description" -->
<xsl:variable name="description" select="document('cities_xpath.xml')
/cities/city[cityName='Oslo']/tourismDescription" />
<xsl:template match="/">
<html>
<head>
<title>Movie Collection</title>
</head>
<body>
<h2>Movie Collection</h2>
<xsl:apply-templates select="movieCollection"/>
</body>
</html>
</xsl:template>
<xsl:template match="movieCollection">
<!-- let's say we just want to see the actors. -->
<!--
<xsl:for-each select="movie">
<hr />
<br />
<b><xsl:text>Movie Title: </xsl:text></b>
<xsl:value-of select="movieTitle"/>
<br />
<br />
<b><xsl:text>Movie Synopsis: </xsl:text></b>
<xsl:value-of select="movieSynopsis"/>
<br />
<br />-->
<!-- actor info begins here. -->
<b><xsl:text>Cast: </xsl:text></b>
<br />
<!-- specify an abbreviated relative path here for "role."
NOTE: there is no predicate in this one; it's just a path. -->
<xsl:for-each select="movie/role">
<xsl:sort select="key('castList',roleIDREF)/castLastName"/>
<xsl:number value="position()" format="
 0. " />
<xsl:value-of select="key('castList',roleIDREF)/castFirstName"/>
<xsl:text> </xsl:text>
<xsl:value-of select="key('castList',roleIDREF)/castLastName"/>
<xsl:text>, </xsl:text>
<xsl:value-of select="roleType"/>
<br />
<xsl:value-of select="key('castList',roleIDREF)/castGender"/>
<xsl:text>, </xsl:text>
<xsl:value-of select="key('castList',roleIDREF)/castSSN"/>
<br />
<br />
</xsl:for-each>
<!--
</xsl:for-each>-->
<hr />
<!--calling the variables -->
<span style="color:red;">
<p><b>Travel Advertisement</b></p>
<!-- reference the city, followed by a comma, and then the country -->
<p><xsl:value-of select="$city" />, <xsl:value-of select="$country" /></p>
<!-- reference the description -->
<xsl:value-of select="$description" />
</span>
</xsl:template>
</xsl:stylesheet>
示例 9.6:movies.xsl
摘要
[edit | edit source]在本章中,我们学习了 XML 路径语言的许多功能和能力。您现在应该对通过使用 XML 树结构的节点关系有了很好的理解。使用缩写和非缩写位置路径的概念,我们可以通过满足方括号中的谓词来缩小搜索范围,仅找到特定元素。相对路径和绝对路径用于指定路径到您的位置。相对路径给出了文件相对于当前工作目录的位置,而绝对路径给出了计算机或文件系统中文件或目录名称的精确位置。这两个概念可以组合起来得出四种类型的 XPath 位置路径:缩写相对路径、缩写绝对路径、非缩写相对路径,以及最后非缩写绝对路径。如果需要进一步过滤,可以使用 XPath 谓词和函数。这些允许对谓词进行评估,例如 true/false 和计数函数。如果正确使用,XPath 可以成为 XML 语言中非常强大的工具。 |