首页
XPath
XQuery
XSLT
Haifeng Xu
(hfxu@yzu.edu.cn)
This slide is based on Jeffrey D. Ullman's work, which can be download from his website.
References:
XPath 简介
XPath 简介
XSL 是指 Extensible Stylesheet Language. 它对于 XML 的作用类似于 CSS 对于 HTML.
由于 XML 中的标签并不是事先定义的, World Wide Web Consortium (W3C) 为此研发了 XSL 用于理解和转换XML文档或对其作样式处理. XSL 是基于 XML 的样式语言. XSL 文档指定了浏览器该如何渲染一个 XML 文档.
以下是 XSL 的主要组成部分:
- XSLT -- 将 XML 文档转换为其他类型的文档.
- XPath -- 用于 XML 文档的导航.
- XSL-FO -- 用于格式化 XML 文档.
在使用 XPath 时, 我们应记住
- XPath 是 XSLT 标准的核心组件.
- XSLT 如果没有 XPath 则无法工作.
- XPath 是 XQuery 和 XPointer 的基础.
XPath 规范指定七种类型的结点,这些结点可以是 XPath 表达式执行的输出。
- Root : 根结点
- Element : 元素
- Text : 文本
- Attribute : 属性
- Comment : 注释
- Processing Instruction : 处理说明
- Namespace : 命名空间
XPath 利用 path 表达式在 XML 文档中选择某个结点或一系列结点.
XPath/XQuery 数据模型
XPath/XQuery 数据模型
XPath 是 XQuery 的一个子集.
对应到关系模型的基本“关系”是: sequence of items.
一个 项(item) 是如下二者之一:
- 基本类型的值, 如: 整数、实数、布尔值或字符串.
- 一个结点(node).
关于在线测试 XQuery, 可以访问 http://www.xpathtester.com/xquery
结点的主要类型
结点的主要类型
- 文档结点(document node): 表示整个 XML 文档.
- 元素结点(element): 是 XML 元素, 包括它们的开始标签、配对结束标签(如果有的话), 以及在开始标签和结束标签之间的所有内容.
- 属性结点(attribute): 位于开始标签中.
文档结点
文档结点
形如 doc(URL) 或 document(URL).
例如: doc(/usr/class/cs145/bars.xml)
所有 XPath(及 XQuery)查询都指向某个文档结点, 或是明确或是隐含的.
- 例如: XML 模式中的键定义具有 Xpath 表达式, 其指向被模式描述的文档.
运行例子的 DTD
运行例子的 DTD
<!DOCTYPE BARS [
<!ELEMENT BARS (BAR*, BEER*)>
<!ELEMENT BAR (PRICE+)>
<!ATTLIST BAR name ID #REQUIRED>
<!ELEMENT PRICE (#PCDATA)>
<!ATTLIST PRICE theBeer IDREF #REQUIRED>
<!ELEMENT BEER EMPTY>
<!ATTLIST BEER name ID #REQUIRED>
<!ATTLIST BEER soldBy IDREFS #IMPLIED>
]>
例子: Document
例子: Document
<BARS>
<BAR name = "JoesBar">
<PRICE theBeer = "Bud">2.50</PRICE>
<PRICE theBeer = "Miller">3.00</PRICE>
</BAR>
...
<BEER name = "Bud" soldBy = "JoesBar
SuesBar ... "/>
...
</BARS>
- <BAR ...> ... </BAR> 是一个元素结点.
- <BEER ... /> 中的 name="Bud" 是一个属性结点.
- 文档结点指整个文档, 包括所有这些内容, 及第一行 <? xml version ... ?>
Nodes as Semistructured Data
Nodes as Semistructured Data
XML 文档中的路径
XML 文档中的路径
XPath 是描述 XML 文档中路径的一种语言.
路径的描述是用一列 item 来表示的. 即所谓的路径表达式. 通常从根结点开始.
路径表达式(Path Expressions)
路径表达式(Path Expressions)
简单的路径表达式是用斜杠和标签组成的一个序列, 以 / 开始.
从文档结点开始, 然后从左到右依次构建这个路径.
Evaluating a Path Expression
Evaluating a Path Expression
路径表达式从根结点开始, 沿着一条具体路径(标签的序列/T1/T2/.../Tn)找到文档中的所有元素Tn.
- Assume the first tag is the root.
- Processing the doc node by this tag results in a sequence consisting of only the root element.
- Suppose we have a sequence of items, and the next tag is X.
- For each item that is an element node, replace the element by the subelements with tag X.
以下是翻译, 可能有翻译不正确的地方.
- 假设第一个标签是根标签(root tag),
- 使用此标签处理这个doc 结点将得到仅由根元素组成的序列.
- 假设我们有一列项(a sequence of items), 并且下一个标签是 X.
- 对每个是元素结点的项, 使用标签为 X 的子元素替换该元素.
例子: /BARS
例子: /BARS
<BARS>
<BAR name = "JoesBar">
<PRICE theBeer = "Bud">2.50</PRICE>
<PRICE theBeer = "Miller">3.00</PRICE>
</BAR> ...
<BEER name = "Bud" soldBy = "JoesBar
SuesBar ... "/> ...
</BARS>
/BARS 所代表的只有一项, 即整个 BARS 元素.
例子: /BARS/BAR
例子: /BARS/BAR
<BARS>
<BAR name = "JoesBar">
<PRICE theBeer = "Bud">2.50</PRICE>
<PRICE theBeer = "Miller">3.00</PRICE>
</BAR>
...
<BEER name = "Bud" soldBy = "JoesBar
SuesBar ... "/> ...
</BARS>
/BARS/BAR, 代表 <BARS> ... </BARS> 中的所有 BAR 子元素.
例子: /BARS/BAR/PRICE
例子: /BARS/BAR/PRICE
<BARS>
<BAR name = "JoesBar">
<PRICE theBeer = "Bud">2.50</PRICE>
<PRICE theBeer = "Miller">3.00</PRICE>
</BAR>
...
<BEER name = "Bud" soldBy = "JoesBar
SuesBar ... "/> ...
</BARS>
/BARS/BAR/PRICE, 代表了所有 <BAR> ... </BAR> 元素中的所有 PRICE 子元素.
路径中的属性(Attributes in Paths)
路径中的属性(Attributes in Paths)
有时候用户想找的不是元素, 而是元素的某个属性的值.
在属性名前面加一个 @ 符号, 表示这是属性.
- 如: /T1/T2/.../Tn/@A 表示元素 Tn 中属性 A.
例子: /BARS/BAR/PRICE/@theBeer
例子: /BARS/BAR/PRICE/@theBeer
<BARS>
<BAR name = "JoesBar">
<PRICE theBeer = "Bud">2.50</PRICE>
<PRICE theBeer = "Miller">3.00</PRICE>
</BAR>
...
<BEER name = "Bud" soldBy = "JoesBar
SuesBar ... "/> ...
</BARS>
/BARS/BAR/PRICE/@theBeer, 代表了所有 <PRICE> 元素中属性名为 theBeer 的值. 即得到的结果是 "Bud Miller", 以及包括其他 BAR 元素中 PRICE 子元素中 theBeer 属性的值.
Remember: Item Sequences
Remember: Item Sequences
到现在为止, 所有的 item sequences 都是元素的序列.
当路径表达式以属性结束, 则所得的结果是一些值组成的序列, 如上一个例子中的字符串序列.
可以从任何结点开始的路径
可以从任何结点开始的路径
若路径表达式从文档结点开始并以 //X 结束, 则第一步是从根标签或是从根标签的任意一个子元素开始寻找, 直到找到所有的 X 标签.
例子: //PRICE
例子: //PRICE
<BARS>
<BAR name = "JoesBar">
<PRICE theBeer = "Bud">2.50</PRICE>
<PRICE theBeer = "Miller">3.00</PRICE>
</BAR>
...
<BEER name = "Bud" soldBy = "JoesBar
SuesBar ... "/> ...
</BARS>
该路径也可找到所有的 PRICE 元素.
有用的路径表达式
表达式 |
描述 |
nodename |
选取所有名为"nodename"的结点. (此结点的所有子结点是该结点的内容, 当然也被选取.) |
/ |
从根结点选取 |
// |
从匹配选择的当前结点开始选择文档中的结点,而不考虑它们的位置 |
. |
选取当前结点 |
.. |
选取当前结点的父结点 |
@ |
选取属性 |
百搭牌 (Wild-Card) *
百搭牌 (Wild-Card) *
星号 * 可以代替任意一个标签.
例如: /*/*/PRICE 代表所有在第三嵌套层次的 PRICE 对象.
例子: /BARS/*
例子: /BARS/*
<BARS>
<BAR name = "JoesBar">
<PRICE theBeer = "Bud">2.50</PRICE>
<PRICE theBeer = "Miller">3.00</PRICE>
</BAR>
...
<BEER name = "Bud" soldBy = "JoesBar
SuesBar ... "/>
...
</BARS>
代表第二嵌套层次中的所有 BAR 子元素和所有 BEER 子元素, 等等.
选择条件
选择条件
如果需要查找某个特定的结点或者包含某个指定值的结点, 则可以在标签名后面跟一个方括号, 里面放置所要满足的条件. 如: /BARS/BAR/PRICE[@theBeer="Miller"]
则只有 theBeer 属性值等于 Miller 的那些 /BARS/BAR/PRICE 元素才包含在路径表达式的执行结果中.
例子: 选择条件
例子: 选择条件
/BARS/BAR/PRICE[.< 2.75], 其中 . 代表当前元素.
<BARS>
<BAR name = "JoesBar">
<PRICE theBeer = "Bud">2.50</PRICE>
<PRICE theBeer = "Miller">3.00</PRICE>
</BAR>
...
<BEER name = "Bud" soldBy = "JoesBar
SuesBar ... "/> ...
</BARS>
这里的条件是 PRICE 必须小于 $2.75$.
例子: 选择属性
例子: 选择属性
/BARS/BAR/PRICE[@theBeer="Miller"]
<BARS>
<BAR name = "JoesBar">
<PRICE theBeer = "Bud">2.50</PRICE>
<PRICE theBeer = "Miller">3.00</PRICE>
</BAR>
...
<BEER name = "Bud" soldBy = "JoesBar
SuesBar ... "/> ...
</BARS>
注意 PRICE 元素被整个选取了, 包括位于其他 /BARS/BAR 元素中满足条件的 PRICE 子元素.
轴(Axes)
轴(Axes)
轴可定义相对于当前结点的结点集.
一般的, 路径表达式允许我们从根标签开始按照步骤去找出每一步的结点集.
在每一步, 我们可以跟随一些轴(axes)中的某一个.
默认轴是 child::, 即到达当前结点集的所有子结点.
例子: 轴(Axes)
例子: 轴(Axes)
/BARS/BEER 实际上代表 /BARS/child::BEER
@ 实际上代表 attribute:: 轴.
- 于是, /BARS/BEER[@name="Bud"] 是下面的缩写
- /BARS/BEER[attribute::name="Bud"]
更多轴(More Axes)
更多轴(More Axes)
一些有用的轴是:
- parent:: = 当前结点(集)的父结点(集)
- descendant-or-self:: = 当前结点(集)以及所有的后代.
- ancestor:: = 先辈
- ancestor-or-self = 先辈或自己
- self = 自己, 即 .
轴(Axes)
轴名称 |
结果 |
ancestor |
选取当前结点的所有先辈(父、祖父等)。 |
ancestor-or-self |
选取当前结点的所有先辈(父、祖父等)以及当前结点本身。 |
attribute |
选取当前结点的所有属性。 |
child |
选取当前结点的所有子元素。 |
descendant |
选取当前结点的所有后代元素(子、孙等)。 |
descendant-or-self |
选取当前结点的所有后代元素(子、孙等)以及当前结点本身。 |
following |
选取文档中当前结点的结束标签之后的所有结点。 |
namespace |
选取当前结点的所有命名空间结点。 |
parent |
选取当前结点的父结点。 |
preceding |
选取文档中当前结点的开始标签之前的所有结点。 |
preceding-sibling |
选取当前结点之前的所有同级结点。 |
self |
选取当前结点。 |
XQuery
XQuery
XQuery 将 XPath 扩充成为一种查询语言, 类似于 SQL
使用相同的项目序列数据模型.
XQuery 是一种表达式语言.
- 类似于关系代数, 任何 XQuery 表达式可以作为其他 XQuery表达式的参数.
更多关于 Item Sequences
更多关于 Item Sequences
XQuery 有时将会形成序列的序列.
所有序列都是“被压平的”(flattened).
例如: (1 2 () (3 4)) =(1 2 3 4). 其中 () 是空序列(empty sequence).
FLWR 表达式
FLWR 表达式
FLWR (发音为 flower) 表达式, 在某种程度上类似于 SQL 中的 select-from-where 表达式.
- 零个或多个 for 子句和 let 子句
- 然后是一个可选的 where 子句.
- 最后是一个 return 语句.
FLWR 表达式的语义
FLWR 表达式的语义
每个 for 创建了一个循环.
对于每一层嵌套的循环,
如果 where 子句返回 TRUE, 则执行 return 语句, 并且将返回的值追加到输出中.
FOR 语句
FOR 语句
for <variable> in <expression>, ...
- 变量必须以 $\$$ 开头.
- 一个 for-变量遍历 XPath 表达式所得到的项目序列中的每一项.
- 无论跟在 for 语句后面的是什么, 对于 for-变量的每个值, 它都执行一次.
例子: FOR
例子: FOR
for $beer in
document("bars.xml")/BARS/BEER/@name
return
<BEERNAME> {$beer} </BEERNAME>
- bars.xml 是我们的例子文档.
- {$beer}: 变量 $beer 外面加花括号表示将用它的值来代替变量字符串本身用于输出.
- for-变量 $beer 遍历文件 bars.xml 中所有 <BEER> 子元素中的 name 属性.
- 返回的结果是一列 BEERNAME 元素:
<BEERNAME>Bud</BEERNAME>
<BEERNAME>Miller</BEERNAME>
...
花括号的使用
花括号的使用
假定有一个变量 $x, 它的值是 abc.
- 比如: <A>$x</A> 是一个 A 元素, 它的值为 $x. 而不是 abc
- 但是语句 return $x 会带来歧义.
- 如果返回的是没有加标签的字符串, 则一定要用引号括起来. 如:
returen "$x"
LET 子句
LET 子句
let <variable> := <expression>, ...
- 变量的值被令为 XPath 表达式所得到的项目序列.
- 注意 let 子句并不导致循环, for 子句才导致循环.
例子: LET 子句
例子: LET 子句
let $d := document("bars.xml")
let $beers := $d/BARS/BEER/@name
return
<BEERNAMES> {$beers} </BEERNAMES>
返回所有啤酒的名字这样的元素序列. 如:
- <BEERNAMES>Bud Miller ...</BEERNAMES>
Order-By 子句
Order-By 子句
FLWR 实际上是 FLWOR: 在 return 语句之前可以有 order-by 子句.
形式为: order by <expression>
- 可以有选项 ascending 或 descending.
其中的表达式 <expression> 对每个变量的赋值都
例子: Order-By
例子: Order-By
列出 Bud 啤酒的所有售价, 并按从低到高排序.
let $d := document("bars.xml")
for $p in
$d/BARS/BAR/PRICE[@theBeer="Bud"]
order by $p
return $p
- for 语句将凡是 Bud 啤酒的价格, 即 PRICE 元素的值绑定到变量 $p.
- order by $p: 根据价格排序.
- return $p: 对每个绑定的变量都输出值. 因此结果是一列 PRICE元素.
SQL ORDER BY
SQL ORDER BY
SQL 也是同样工作的, 只是对于 FROM ... WHERE ... 所得的结果关系排序, 而不是对输出排序.
例如: 对于关系 R(a,b),
SELECT b FROM R
WHERE b > 10
ORDER BY a;
- SELECT 中的属性是 b, 表示只是将 b 的值从所得关系中抽取出来, 按照同样的顺序打印出来.
- 这里的 ORDER BY 语句是将关系 R 中满足 b>10 的所有元组进行排序, 这些元组是包括属性 a 的.
谓语(Predicates)
谓语(Predicates)
以量化形式的条件.
例子: /BARS/BAR[@name] 意思是所有含有属性 name 的酒吧.
例子: /BARS/BEER[@soldAt="Joe's Bar"] 得到的结果是所有在 Joe's Bar 出售的啤酒.
例子: 比较
例子: 比较
我们来列出 Joe 酒吧出售的所有啤酒的 PRICE 元素,
输出要求是一个 BBP 元素. 它有两个属性, 其中一个属性是 bar, 值为酒吧名; 另一个属性是 beer, 值是啤酒名, 而价格作为BBP元素的值.
策略(Strategy)
策略(Strategy)
- 建立一个三重 for 循环, 变量遍历所有的 BEER 元素, 以及那些 BAR 元素中的所有 PRICE 元素.
- 检查此啤酒是否由 Joe's Bar 所销售, 并且啤酒的名称是否和 PRICE 元素中的 theBeer 属性的值一致.
- 构造输出元素.
The Query
The Query
let $bars = doc("bars.xml")/BARS
for $beer in $bars/BEER
for $bar in $bars/BAR
for $price in $bar/PRICE
where $beer/@soldAt = "Joe's Bar" and
$price/@theBeer = $beer/@name
return <BBP bar = {$bar/@name} beer
= {$beer/@name}>{$price}</BBP>
where 中条件 $beer/@soldAt = "Joe's Bar" 为 True, 当且仅当 "Joe's Bar" 出现在 XPath 表达式 $beer/@soldAt 的结果序列的任一位置.
严格比较(Strict Comparisons)
严格比较(Strict Comparisons)
如果要求比较的对象是单元素构成的序列, 则使用 Fortran 比较算子:
例如: $beer/@soldAt eq "Joe's Bar" 为真当且仅当 Joe's Bar 是唯一销售此啤酒的酒吧.
元素与值的比较
元素与值的比较
当一个元素与一个基本值作比较时, 若元素的值是原子性的(atomic), 则元素作为值来处理.
例如:
/BARS/BAR[@name="Joe's Bar"]/PRICE[@theBeer="Bud"] eq "2.50"
为真当且仅当 Joe's Bar 以 $\$2.50$ 的价格售卖 Bud.
两个元素的比较
两个元素的比较
两个元素即使看起来很像, 有时也不一定相等. 如:
/BARS/BAR[@name="JoesBar"]/
PRICE[@theBeer="Bud"] eq
/BARS/BAR[@name="SuesBar"]/
PRICE[@theBeer="Bud"]
返回 false. 即使 Joe 和 Sue 关于 Bud 啤酒卖同样的价钱.
对于相等的元素, 它们必须是完全相同的. (physically in the implied document)
敏锐(Subtlety): 元素实际上是指向特殊文档的指针, 而不是出现在节中的下一个字符串.
从元素中取得数据
从元素中取得数据
假设我们要比较元素的值, 而不是比较它们在文档中的位置.
如果要从元素 E 只提取数据(例如得到价格本身). 则使用 data(E).
例子: data()
例子: data()
return <BBP bar = {$bar/@name}
beer = {$beer/@name} price =
{data($price)} />
消除重复(Eliminating Duplicates)
消除重复(Eliminating Duplicates)
将函数 distinct-values 应用到某个序列上.
Subtlety: this function strips tags away
from elements and compares the string
values.
例子: 所有不同的价格
例子: 所有不同的价格
return distinct-values(
let $bars = doc("bars.xml")
return $bars/BARS/BAR/PRICE
)
记住: XQuery 是一种表达式语言. 一个 XQuery 系列可以出现在任意一个值可以出现的地方.
有效的布尔值(Effective Boolean Values)
有效的布尔值(Effective Boolean Values)
表达式的有效布尔值(effective boolean values, EBV)是指
- 如果表达式是布尔类型的, 则表达式取实际的值.
- 如果表达式为 0 或者是空字符串 "", 或是空序列(), 则返回
FALSE.
- 其他的都认为是 TRUE.
EBV 例子
EBV 例子
- @name="Joe's Bar" 的 EBV 是 TRUE 或 FALSE, 这取决于 name 属性是否为 Joe's Bar.
- /BARS/BAR[@name="Golden Rail"]
当某个酒吧的名称为 Golden Rail 时, 方括号中表达式的 EBV 为 TRUE; 否则为 FALSE.
布尔算子(Boolean Operators)
布尔算子(Boolean Operators)
$E_1$ and $E_2$, $E_1$ or $E_2$, not($E$) 可应用于任何表达式.
首先对于表达式求它们的 EBV.
例如: not(3 eq 5 or 0) 的 EBV 是 TRUE.
true() 和 false() 是两个函数, 分别返回 TRUE 和 FALSE.
分支表达式(Branching Expressions)
分支表达式(Branching Expressions)
表达式 if($E_1$) then $E_2$ else $E_3$ 是这样计算的:
- 首先计算 $E_1$ 的 EBV.
- 如果为 TRUE, 则结果是 $E_2$, 否则结果是 $E_3$.
- 这与 C 语言中的 $E_1$?$E_2$:$E_3$ 是类似的.
例子: 如果酒吧是 Joe's Bar 则返回 $bar 的子元素 PRICE.
if($bar/@name eq "Joe's Bar")
then $bar/PRICE else ()
() 是指空序列. 注意这里没有 if-then 表达式.
限定符表达式(Quantifier Expressions)
限定符表达式(Quantifier Expressions)
some $\$x$ in $E_1$ satisfies $E_2$
- 计算序列 $E_1$;
- 令 $x 遍历序列 $E_1$ 中的每一项, 然后计算 $E_2$;
- 如果 $E_2$ 对于至少一个 $x 的 EBV 为 TRUE, 则返回 TRUE.
类似的的表达式
every $\$x$ in $E_1$ satisfies $E_2$
例子: Some
例子: Some
求至少销售一种低于 $\$2$ 的啤酒的酒吧.
for $bar in
doc("bars.xml")/BARS/BAR
where some $p in $bar/PRICE
satisfies $p < 2.00
return $bar/@name
注意: 使用 where $bar/PRICE < 2.00 也可以的.
例子: Every
例子: Every
列出没有 $\$5$ 以上啤酒的酒吧.
for $bar in
doc("bars.xml")/BARS/BAR
where every $p in $bar/PRICE
satisfies $p <= 5.00
return $bar/@name
文档次序(Document Order)
文档次序(Document Order)
文档次序的比较使用 << 和 >>
例子:
$d/BARS/BEER[@name="Bud"]
<< $d/BARS/BEER[@name="Miller"]
这个表达式为真当且仅当在文档 $d 中, Bud 元素在 Miller 元素之前出现.
集合算子(Set Operators)
集合算子(Set Operators)
union, intersect, except 可以作用在结点序列上.
- 与 SQL 中的含义相同.
- 结果中重复的被消除.
- 结果按照文档次序出现.
Java 与 XQuery
Java 与 XQuery
JDK 内置了XPath的一个实现, 可以通过 javax.xml.path 这个API来使用. 这个API 也可以被其他的XPath实现使用, 比如 Saxon 和 Jaxen.
没有与 JDK 一起发行的 XQuery 引擎, 但是有一些第三方的产品. 可以访问 W3C XQuery 页面, 那里有一些. 其中一个简单的就是 Saxon.
从 Java 访问 XQuery 有一个标准的API, 称为 XQJ(打包成 javax.xml.xquery),
Saxon 有另一个界面, 称为 s9api.
References
https://stackoverflow.com/questions/13403170/how-can-i-run-an-xquery-on-an-xml-file-using-javax-xml-xpath
http://saxon.sourceforge.net/
https://sourceforge.net/projects/saxon/files/
XSLT
XSLT
XSLT扩展的样式语言(extensible stylesheet language - transforms) 是处理 XML 文档的一种说明性语言. 用于将XML文档(包括XHTML文档)转换为其他XML、XHTML、HTML或文本文件.
最初是作为一种呈现语言的: 将 XML 文档(不能被显示)转换为 HTML 页面.
也可以执行 XML 到 XML 的转换, 因此可以作为一种查询语言.
实验
上机实践: 点击 test_bar.xml, 你将会看到此 XML 文档在 test_bar.xsl 下的输出效果.
或者使用软件如 Xalan 将 test_bar.xml 根据 test.bar.xsl 中的规则转换为 test_bar.html.
Xalan -o test_bar.html test_bar.xml test_bar.xsl
Windows 系统下可以安装 Microsoft 的免费 Win32 可执行 XSLT 处理器 MSXSL.
下载地址: http://www.microsoft.com/en-us/download/details.aspx?id=21714, 查找 MSXSL.
XSLT 程序
XSLT 程序
与 XML Schema 类似, XSLT 本身也是一个 XML 文档.
XSLT 有自己的标签命名空间, 通常被记为 xsl:
模板(Templates)
模板(Templates)
xsl:template 元素描述了(将要被处理的文档的)一族元素, 以及对它们将要作何处理.
形式如下:
<xsl:template match = path >
...
</xsl:template>
match 属性给出一个 XPath 表达式, 描述如何找到模板要应用的结点(集).
例子: BARS Document --> Table
例子: BARS Document --> Table
我们将把 bars.xml 转换为 HTML 文档, 就像描述关系 Sells(bar,beer,price) 时所用的表格一样.
第一个模板将匹配文档的根结点 /, 并生成一个空表.
根结点的模板
根结点的模板
<xsl:template match = "/">
<table>
<tr>
<th>bar</th>
<th>beer</th>
<th>price</th>
</tr>
</table>
</xsl:template>
match="/" 表示该模板仅匹配根结点.
蓝色部分的 html 代码就是模板的输出, 这是一张表格, 只有表格头, 没有数据行.
显然, 这样是没有办法插入数据行的. 需要改进.
策略概要(Outline of Strategy)
策略概要(Outline of Strategy)
- 对每个酒吧元素 BAR, 利用 xsl:variable 变量 b 存储该酒吧的名称.
- 利用 xsl:for-each, 对每个 PRICE 元素, 生成啤酒的名称和价格. 这里啤酒的名称和价格要利用刚才的变量 b 及 xsl:value-of.
模板的递归使用(Recursive use of templates)
模板的递归使用(Recursive use of templates)
一个 XSLT 文档通常包含很多模板.
从应用于根结点的第一个模板开始.
任意模板中可以包含标签 <xsl:apply-templates/>, 它将从当前结点开始, 对它子元素递归应用此模板.
应用模板(Apply-Templates)
应用模板(Apply-Templates)
属性 select 给出了一个 XPath 表达式, 描述哪些子元素将被模板作用.
例如:
<xsl:apply-templates select = "BARS/BAR" />
从当前结点(即模板正在被应用的元素)开始, 对于匹配为 BARS/BAR 的子元素, 将模板应用到它身上.
例子: 应用模板(Apply-Templates)
例子: 应用模板(Apply-Templates)
<xsl:template match = "/">
<table>
<tr>
<th>bar</th>
<th>beer</th>
<th>price</th>
</tr>
<xsl:apply-templates select = "BARS" />
</table>
</xsl:template>
提取值(Extracting Values)
提取值(Extracting Values)
<xsl:value-of select = XPath expression />
将生成一个值(字符串)作为输出.
例子: 假定我们正在应用某个模板到 BAR 元素上, 希望将它的名称(属性 name 的值)输出到表格中.
<xsl:value-of select = "@name" />
变量(Variables)
变量(Variables)
我们可以用下们的方式声明一个变量:
<xsl:variable name = "x" />
例如:
<xsl:variable name = "bar">
<xsl:value-of select = "@name" />
</xsl:variable>
将上面的代码放在应用于 BAR 元素的模板中, 则将该酒吧的名称赋给变量 bar.
变量的使用
变量的使用
当使用刚才定义的变量时, 只需在它前面加上符号 $.
例如: <td>$bar</td>
完成表格(Completing the Table)
完成表格(Completing the Table)
- 我们将对每个 BAR 元素应用一个模板.
- 这个模板将酒吧的名称赋给变量 b, 并且对每个 PRICE 子元素进行迭代.
- 对每个 PRICE 子元素, 我们利用 b 和 theBeer 属性及 PRICE 本身打印出该行数据.
循环(Iteration)
循环(Iteration)
<xsl:for-each select = "Xpath expression">
...
</xsl:for-each>
对当前结点(由XPath表达式指定)的每个子结点执行 for-each 迭代.
BARS 的模板
BARS 的模板
<xsl:template match = "BAR">
<xsl:variable name = "b">
<xsl:value-of select = "@name" />
</xsl:variable>
<xsl:for-each select = "PRICE">
<tr>
<td>$b</td>
<td><xsl:value-of select = "@theBeer" /></td>
<td><xsl:value-of select = "data(.)" /></td>
</tr>
</xsl:for-each>
</xsl:template>
- 在模板中, 首先定义了一个变量 b, 它用来存储 BAR 元素中 name 属性的值, 即酒吧名.
- <xsl:for-each select="PRICE">...</xsl:for-each> 对于该 BAR 元素中的所有 PRICE 子元素进行迭代.
- <tr>...</tr> 部分是生成 html 代码.
- data(.) 中的点是指当前元素, 即 PRICE 子元素.
End
Thanks very much!
This slide is based on Jeffrey D. Ullman's work, which can be download from his website.