6 循环
需要循环进行处理时可以使用xsl:for-each元素。基本代码如下所示。
<xsl:for-each
select = "节点集合">
<!-- 内容:(xsl:sort*, 模板) -->
</xsl:for-eaxh>
必须设置select属性,来指定被处理的节点集合。如果使用了后面讲述的排序的话则按照排序结果的顺序进行处理,否则按照节点出现顺序进行处理。
例如,如下所示,bookmark元素中包含了多个link元素。
<bookmark>
<link>
<title>技术评论公司</title>
<url>http://www.gihyo.co.jp</url>
</link>
<link>
<title>ONGS</title>
<url>http://www.ongs.gr.jp</url>
</link>
</bookmark>
利用下面使用了xsl:for-each元素的模板规则,可以将其转换成HTML表格(图1)。
<xsl:template match="bookmark">
<table border="1">
<xsl:for-each select="link">
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="url"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
但是,使用如下所示的模板规则,不用xsl:for-each元素也能得到同样的输出结果。
<xsl:template match="bookmark">
<table border="1">
<xsl:apply-templates select="link"/>
</table>
</xsl:template>
<xsl:template match="link">
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="url"/></td>
</tr>
</xsl:template>
仅定义模板规则有时候很难进行转换。例如,需要将行和列交换生成如图2所示的表时,不使用xsl:for-each元素就很难做到。
使用xsl:for-each元素可以生成如图2所示的输出结果。
<xsl:template match="bookmark">
<table border="1">
<tr>
<xsl:for-each select="link/title">
<td><xsl:value-of select="."/></td>
</xsl:for-each>
</tr>
<tr>
<xsl:for-each select="link/url">
<td><xsl:value-of select="."/></td>
</xsl:for-each>
</tr>
</table>
</xsl:template>
7 条件处理
在XSLT中,进行条件处理的元素有xsl:if和xsl:choose两个。xsl:if进行“如果~就~”的if-then型处理,xsl:choose当有多个选择项存在时进行处理。
7.1 xsl:if
xsl:if元素拥有test属性,可指定逻辑表达式。逻辑表达式为真的情况下执行模板的转换,假的情况下不进行转换。
<xsl:if
test = "逻辑表达式">
<!-- 内容: 模板 -->
</xsl:if>
例如,对以下XML文档,
<people>
<person>
<name>张三</name>
<age>30</age>
</person>
<person>
<name>李四</name>
<age>20</age>
</person>
<person>
<name>周五</name>
<age>10</age>
</person>
</people>
使用如下所示的模板进行变换。
<xsl:template match="people">
<ul>
<xsl:apply-templates select="person"/>
</ul>
</xsl:template>
<xsl:template match="person">
<li>
<xsl:value-of select="name"/>今年
<xsl:value-of select="age"/>岁
<xsl:if test="age[.< 18]">
(未成年)
</xsl:if>
</li>
</xsl:template>
<是<的意思(>是>)。age元素的值不足18的情况下输出“(未成年)”。输出结果如下所示。
<ul>
<li>张三今年30岁</li>
<li>李四今年20岁</li>
<li>周五今年10岁(未成年)</li>
</ul>
7.2 xsl:choose
xsl:choose元素由一个或一个以上的xsl:when元素和可选的xsl:otherwise元素组成。
<xsl:choose>
<xsl:when test="逻辑表达式">
<!-- 内容: 模板 -->
</xsl:when>
<xsl:otherwise>
<!-- 内容: 模板 -->
</xsl:otherwise>
</xsl:choose>
与xsl:if元素相同,test属性的逻辑表达式为真的情况下执行指定的模板。从上到下依次测试xsl:when元素,但只有第一个逻辑表达式为真的xsl:when院所的模板会被执行。如果所有的xsl:when元素的逻辑表达式均为假,则执行xsl:otherwise元素所指定的模板。xsl:otherwise元素不存在时则不执行任何模板。
例如,对于如下文档,
<ol>
<li>起床</li>
<li>洗脸</li>
<li>吃早饭</li>
<li>上班</li>
</ol>
应用如下所示的模板。last()函数返回被处理的内容的大小。
<xsl:template match="ol">
<morning>
<xsl:for-each select="li">
<todo>
<xsl:choose>
<xsl:when test="position()=1">
<xsl:text>首先</xsl:text>
</xsl:when>
<xsl:when test="position()=last()">
<xsl:text>最后</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>第</xsl:text>
<xsl:value-of select="position()"/>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="."/>
</todo>
</xsl:for-each>
</morning>
</xsl:template>
输出结果如下所示。
<morning>
<todo>首先起床</todo>
<todo>第2洗脸</todo>
<todo>第3吃早饭</todo>
<todo>最后上班</todo>
</morning>
8 排序
为将数据排序,可以在xsl:apply-templates元素或xsl:for-each元素的子节点中增加xsl:sort元素。xsl:sort元素的基本代码如下所示。
<xsl:sort
select = "字符串表达式"
data-type = "数据类型"
order = "顺序"/>
通过select属性指定排序的节点。通过data-type属性指定字符串的数据类型。设置为text就能够按照人们默认的字典顺序进行排序。设置为number将把字符串看作数字,按照数字的值进行排序。order属性设置排序的顺序。升序为ascending、降序为descending。未指定时默认为升序。其他能够设置的属性包括设置语言的lang属性,设置大小写字母哪个优先的case-order属性等。
例如,将如下所示的由姓名(name)、年龄(age)组成的人(person)的数据按照姓名和年龄进行排序。
<people>
<person>
<name>张三</name>
<age>30</age>
</person>
<person>
<name>李四</name>
<age>20</age>
</person>
<person>
<name>周五</name>
<age>10</age>
</person>
</people>
下面是按照年龄升序、姓名降序进行排序并生成HTML表格的模板规则。
<xsl:template match="people">
<h1>按照年龄升序排列</h1>
<table border="1">
<xsl:apply-templates select="person">
<xsl:sort select="age"
data-type="number"/>
</xsl:apply-templates>
</table>
<h1>按照姓名降序排列</h1>
<table border="1">
<xsl:apply-templates select="person">
<xsl:sort select="name" data-type="text" order="descending"/>
</xsl:apply-templates>
</table>
</xsl:template>
<xsl:template match="person">
<tr>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="age"/></td>
</tr>
</xsl:template>
输出结果如图3所示。
与此相同,使用xsl:for-each元素重新书写代码则如下所示。要注意,在将xsl:sort元素作为xsl:for-each元素的子节点使用时,必须将其写在开头的地方。
<xsl:template match="people">
<h1>按照年龄降序排列</h1>
<table border="1">
<xsl:for-each select="person">
<xsl:sort select="age" data-type="number"/>
<tr>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="age"/></td>
</tr>
</xsl:for-each>
</table>
<h1>排序</h1>
<table border="1">
<xsl:for-each select="person">
<xsl:sort select="name" data-type="text" order="descending"/>
<tr>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="age"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
9 变量
在XSLT中可以使用变量。
9.1 绑定变量
可以为变量赋值的元素有xsl:variable元素和xsl:param元素。
9.1.1 xsl:variable元素
基本代码如下所示。
<xsl:variable
name = "变量名"
select = "表达式">
<!-- 内容: 模板 -->
</xsl:variable>
使用name属性指定变量名(必须)。select属性和内容都不存在的话可以写成空字符串。
<xsl:variable name="x"/>
这种写法与下面的写法意思相同。
<xsl:variable name="x" select="''"/>
通过select属性可以指定变量中代入的值。使用select属性给变量赋值的话,内容必须为空。例如给变量x赋值为2时的代码如下所示。
<xsl:variable name="x" select="2"/>
这种情况下,使用
<xsl:value-of select="item[$x]"/>
将输出第二个item元素。
通过内容来赋值时,变量的值不是数值,而是结果树的片断。关于结果树的片断请参照参考文献[1]。
<xsl:variable name="x">2</xsl:variable>
这种情况下,使用
<xsl:value-of select="item[$x]"/>
不会输出第二个item元素,而是输出了第一个元素。使用值为结果树片断的变量时应当像下面这样书写代码。
<xsl:value-of select="item[position()=$x]"/>
9.1.2 xsl:param元素
xsl:variable元素和xsl:param元素基本上相同。一个区别是,XML解释器假定xsl:param变量中保存着默认值,并可以使用xsl:with-param元素来向模板中传值。详细情况请参见参考文献[1]。
9.2 访问变量
在表达式中访问变量时,需要在变量名前加上$符号。使用xsl:value-of元素访问变量则可以输出变量的值。
10 指定输出格式
XSLT处理器的任务是从XML文档转换成新的XML文档,但是也能够输出XML文档之外的格式。通过xsl:output元素可以指定输出格式。该元素只能作为顶层元素使用。基本代码如下所示。
<xsl:output
method = "输出格式"
version = "版本"
encoding = "编码"
omit-xml-declaration = "yes" | "no"
standalone = "yes" | "no"
indent = "yes" | "no" />
通过method指定输出格式。可以指定的格式包括html、html、text等。未指定时默认为xml,但如果满足以下条件则为html。
- 结果树的根节点的元素名为html(不区分大小写),并且含有子元素。
- 不包含命名空间的URI。
- 结果树的根节点的子元素之前出现的文本只包含空白。
通过version可以指定输出格式的版本。通过encoding指定输出时使用的字符编码。通过omit-xml-declaration来指定是否省略XML定义。通过standalone指定是否输出独立文档的声明。通过indent指定输出结果树时是否使用缩进的格式。
例如,输出i-mode能够浏览的HTML时,可以如下书写代码。由于i-mode只能使用Shift_JIS编码,因此需要按下面的方式定义。
<xsl:output method="html" encoding="Shift_JIS" indent="no"/>
注释
1该表达式并不一定正确。详细情况请参见参考文献[5][6]。
2并不是所有的属性都能够使用属性值模板来处理。详细情况请参见参考文献[1]。
3实际上该例子作为动态生成的例子并不恰当。