8.5 流程控制元素

前面介绍的XSLT标签都是最基本的模板定义和输出元素等,本节将会介绍XSLT中进行分支和循环控制的流程控制元素。

8.5.1 分支处理

XSLT提供了<if…/>、<choose…/>、<when…/>和<otherwise…/>等4个元素用于分支处理,其中<if…/>元素可以单独使用,而<choose…/>、<when…/>和<otherwise…/>元素应该结合使用。

<if…/>元素的作用类似于Java里if语句的作用,而<choose…/>、<otherwise…/>和<when…/>元素则类似于Java里if、else if和else的作用。

使用<if…/>元素时可以指定一个test属性,其值是一个布尔表达式,该元素的内容是模板内容,当test属性指定的布尔表达式为true时,计算输出该元素包含的模板内容,否则不会计算输出该元素包含的模板内容。

假设有如下XML文档:

程序清单:codes\08\8.5\book.xml

alt

假设需要对<price…/>元素的值进行判断:当价格大于50时,即认为该图书价格较高,购买需慎重,就可使用<if…/>元素进行处理,如以下XSLT文档所示:

程序清单:codes\08\8.5\if.xslt

alt

使用<if…/>元素只能进行简单的判断,如果需要进行类似于if、else if和else组合的复杂分支处理,则可以使用<choose…/>、<when…/>和<otherwise…/>元素进行分支控制。<choose…/>、<when…/>和<otherwise…/>元素的语法格式如下:

alt

<when…/>和<otherwise…/>元素必须放在<choose…/>元素里使用,每个<choose…/>元素里可以包含多个<when…/>子元素,但最多只能包含一个<otherwise…/>子元素。第1个<when…/>子元素相当于if、else if和else组合里if分支的作用,后面的<when…/>子元素则相当于if、else if和else组合里else if分支的作用,最后的<otherwise…/>子元素相当于if、else if和else组合里else分支的作用。由此可见,<when…/>子元素需要指定一个布尔表达式作为判断条件,而其test属性就用于指定这个判断条件。

如以下XML文档所示:

程序清单:codes\08\8.5\choose.xslt

alt

需要指出的是,上面的XSLT文档中的布尔表达式“price &lt; 20”里的“&lt;”是一个实体引用,XSLT文档也是XML文档,因此一样可以使用XML里的实体引用。

8.5.2 循环控制

除了上面进行分支控制的各元素之外,XSLT还提供了<for-each…/>元素进行循环控制,使用<for-each…/>元素必须指定一个select属性,其值是一个XPath表达式,表示一个节点集。<for-each…/>元素将依次迭代节点集内的每个节点,其中正在被迭代处理的节点会变成当前节点。

<for-each…/>元素的语法格式如下:

alt

XSLT将会使用<for-each…/>元素里包含的模板定义来转换每个被迭代处理的节点。

假设有如下XML文档:

程序清单:codes\08\8.5\list.xml

alt

下面可以使用<for-each…/>元素来迭代转换上述文档里的每个<item…/>元素:

程序清单:codes\08\8.5\for-each.xslt

alt

<for-each…/>元素显式指定迭代转换节点集中的每个节点,而<apply-templates…/>元素则实际上具有隐式的迭代功能,因此上面的XSLT文档可以改写为如下形式:

程序清单:codes\08\8.5\apply-templates.xslt

alt

这两份XSLT文档对上面的list.xml文档的转换结果完全一样。由此可见,大多数时候,使用<apply-templates…/>元素的隐式循环可以代替<for-each…/>元素的循环功能。

8.5.3 排序控制

排序控制并不是流程控制的一种,只不过它需要放在<for-each…/>和<apply-templates…/>元素里使用,用于对被迭代处理的元素进行排序。

使用<sort…/>元素可以指定如下几个属性:

alt select:用于指定一个XPath表达式,该表达式所表示的节点将作为排序关键字。

alt lang:用于指定排序顺序的语言字母表。如果未指定lang属性值,将根据系统环境确定语言。

alt data-type:指定字符串的数据类型。如果未指定数据类型,将使用表达式的类型作为默认类型。data-type只能接受如下3个属性值:

● text:指定排序关键字应按照字母顺序排序。

● number:指定排序关键字应转换为数字,然后根据数值进行排序。

● QName:展开为扩展名称,标识该数据类型。

alt order:指定是使用“升序”(用ascending属性值)还是“降序”(用descending属性值)进行排序。

alt case-order:当data-type属性值为text时,该属性指定大写字母应该在小写字母之前还是之后,该属性只能接受upper-first(大写字母排在前面)和lower-first(小写字母排在前面)两个值。

在<for-each…/>和<apply-templates…/>元素里可以使用多个<order…/>元素,其中第1个<order…/>元素的select属性表示的节点代表首要关键字,第2个<order…/>元素的select属性表示的节点代表次要关键字……依此类推。

假设有如下XML文档:

程序清单:codes\08\8.5\booklist.xml

alt

如果希望XSLT迭代转换每个<book…/>元素时先根据其<type…/>子元素的值进行排序,当<type…/>子元素的值相同时,再根据<price…/>子元素的值进行排序,则可使用如下XSLT文档进行转换:

程序清单:codes\08\8.5\order.xslt

alt

使用浏览器浏览上面的booklist.xml文档,可看到图8.15所示页面。

alt

图8.15 使用sort元素进行排序