xslt
XML和XSLT的组合在中型和大型网站的网站管理员中越来越受欢迎。 在使用XSLT之前,更改网站的显示是一项重要的工作:必须重新访问并更改网站上的每个页面。 XSLT使过程自动化,从而节省大量时间。
提示1:级联样式表,表格和XSLT
从XSLT文章中CSS技巧开始似乎很奇怪,但是我经常被问到“这两种样式表语言兼容吗?” 答案是肯定的。
清单1中的products.xml(用XML编写的产品列表)对此进行了说明。 花一点时间来熟悉products.xml,因为我将在五个技巧中使用它。
清单1. products.xml,XML产品列表
<?xml version="1.0"?>
<products>
<product href="http://www.playfield.com/text">
<name>Playfield Text</name>
<price currency="usd">299</price>
<description>Faster than the competition.</description>
<version>1.0</version>
</product>
<product href="http://www.playfield.com/virus">
<name>Playfield Virus</name>
<price currency="eur">199</price>
<description>
Protect yourself against malicious code.
</description>
<version>5.0</version>
</product>
<product href="http://www.playfield.com/calc">
<name>Playfield Calc</name>
<price currency="usd">299</price>
<description>Clear picture on your data.</description>
<version>1.5</version>
</product>
<product href="http://www.playfield.com/db">
<name>Playfield DB</name>
<price currency="cad">599</price>
<description>Organize your data.</description>
</product>
</products>
要格式化HTML这个文件,你可以使用table.xsl清单2.应用table.xsl到products.xml看起来像图1 。 如您所见,每隔一行都有灰色背景,这提高了可读性。 在table.xsl中,这是通过级联样式表实现的。
清单2. table.xsl,一个使用CSS的XSLT样式表
<?xml version="1.0"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"indent="no"/>
<xsl:template match="/products">
<html>
<head>
<title>Cascading Style Sheet</title>
<link rel="stylesheet" type="text/css" href="table.css"
title="Style"/>
</head>
<body>
<table>
<tr class="header">
<td>Name</td>
<td>Price</td>
<td>Description</td>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="product[position() mod 2 = 1]">
<tr class="odd">
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="price"/></td>
<td><xsl:value-of select="description"/></td>
</tr>
</xsl:template>
<xsl:template match="product">
<tr class="even">
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="price"/></td>
<td><xsl:value-of select="description"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
图1. HTML中的产品列表
它是如何工作的? table.xsl样式表在输出中插入HTML <link>
元素。 <link>
加载级联样式表:
<link rel="stylesheet" type="text/css" href="table.css" title="Style"/>
CSS和XSLT之间不存在冲突,因为它们不能同时使用。 XSLT样式表首先应用于XML文档products.xml 。 结果是一个HTML文档被传递到浏览器。 在此阶段,HTML文档加载级联样式表的事实是无关紧要的。 只有在浏览器加载HTML文档时,CSS才可以使用。
class
odd
even
match
<xsl:template match="product[position() mod 2 = 1]">
<tr class="odd">
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="price"/></td>
<td><xsl:value-of select="description"/></td>
</tr>
</xsl:template>
清单3中的简单层叠样式表table.css在表的偶数行上放置了灰色背景。
清单3. table.css,图1中的表CSS
.header { background-color: #999999; font-weight: bold; }
.odd { background-color: normal; }
.even { background-color: #dfdfdf; }
什么时候应该混合使用CSS和XSLT? 我认为这种组合在以下情况下很有吸引力:
- 由于CSS比原始HTML强大,因此可以更好地控制显示
- 产生下载速度更快的较小HTML文件
但是请注意,将两种类型的样式表组合使用时,在可维护性方面不会获得太多好处。 确实,设计师最初是被CSS吸引的,因为一个文件控制着整个网站的设计。 在这方面,CSS在XSLT中是多余的,这已经使得立即重新格式化多个文档变得容易。
谨防! 本文中的table.xsl和其他样式表需要符合标准的XSLT处理器。 Internet Explorer 5.0和5.5附带的不符合标准。 如果需要兼容的XSLT处理器,请尝试使用Xalan(Apache项目中的XSLT处理器),或将IE中的处理器升级到3.0版(请参阅参考资料 )。
提示2:HTML实体
开发人员有关编写XSLT样式表的另一个常见问题是如何插入HTML实体。 特别是如何插入
实体(牢不可破的空间)。 除其他外,
空格用于在表中创建非空单元格。
不幸的是,明显的解决方案不起作用:
<tr> </tr>
为什么? XSLT样式表是一个XML文档。 解析后,实体将被解析,并且
实体解析为XML实体。 自
未在HTML中定义,则会导致错误。
解决方法在清单4的nbsp.xsl中进行了说明,相关元素以红色突出显示。 如您所见,用HTML编写实体所需要的字符数比每次需要输入的字符数都要多,但是一旦知道了代码,您就可以简单地将其剪切并粘贴到适当的位置。
清单4. nbsp.xsl,展示了如何在样式表中插入HTML实体
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="no"/>
<xsl:template match="/">
<html>
<head><title>HTML Entities</title></head>
<body>
<table border="1">
<tr>
<td>Name</td>
<td>Price</td>
<td>Description</td>
<td>Version</td>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="product[version]">
<tr>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="price"/></td>
<td><xsl:value-of select="description"/></td>
<td><xsl:value-of select="version"/></td>
</tr>
</xsl:template>
<xsl:template match="product">
<tr>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="price"/></td>
<td><xsl:value-of select="description"/></td>
<td>
<xsl:text disable-output-escaping="yes">&nbsp;</xsl:text>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
清单4摘录的不间断空间实体的正确代码是:
<xsl:text disable-output-escaping="yes">&nbsp;</xsl:text>
该行代码中发生了什么? 诀窍是将<xsl:text>
元素与disable-output-escaping="yes"
属性一起使用。 <xsl:text>
在输出HTML中创建一些文本。 该属性告诉处理器不要转义文本的内容。 文字本身就是
&
字符转义为XML。
同样,样式表被读取为XML文档,因此&nbsp;
是
。 如果您告诉处理器不要在输出HTML中转义&
,则它会写为
。
提示3:多个输入文件
典型的XSLT样式表将一个XML文档转换为另一个XML文档或HTML文档。 有时,这太局限了。 (有关如何处理反向操作的介绍,请参见侧栏, 多个输出文档。 )
例如,在products.xml中注意<price>
元素具有currency
属性。 货币不是用明文书写的,而是用代码(例如, usd
表示美元或cad
表示加元)。 在显示代码之前,您将需要翻译它们。
在全球有一百多种货币以及许多处理货币的应用程序,您确实应该将货币列表存储在其自己的XML文档中。 该文件的摘录可能类似于清单5中的codes.xml 。
清单5. codes.xml,带有货币代码的XML文档
<?xml version="1.0"?>
<currencies>
<currency>
<code>eur</code>
<name>Euros</name>
</currency>
<currency>
<code>usd</code>
<name>Dollars</name>
</currency>
<currency>
<code>cad</code>
<name>Canadian dollars</name>
</currency>
</currencies>
实际上,现在该示例具有两个XML文件,即products.xml和codes.xml ,您需要将其合并以创建HTML文档。 幸运的是,如清单6中的multi.xsl所示,XSLT使合并多个输入XML文件变得容易。
multi.xsl中有两个重要步骤。 首先,样式表打开codes.xml (带有document()
函数)并将其分配给currencies
变量:
<xsl:variable
name="currencies"
select="document('codes.xml')/currencies"/>
然后,样式表可以通过变量从代码列表中提取信息。 当然,您可以使用XPath查询货币文档:
<xsl:value-of select="$currencies/currency[code=$currency]/name"/>
清单6. multi.xsl,一个组合了几个XML文档的样式表
<?xml version="1.0"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="no"/>
<xsl:variable
name="currencies"
select="document('codes.xml')/currencies"/>
<xsl:template match="/">
<html>
<head><title>Multiple documents</title></head>
<body>
<table>
<tr bgcolor="#999999">
<td>Name</td>
<td>Price</td>
<td>Description</td>
<td>Version</td>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="product">
<xsl:variable name="currency" select="price/@currency"/>
<tr>
<td><xsl:value-of select="name"/></td>
<td>
<xsl:value-of select="price"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$currencies/currency[code=$currency]/name"/>
</td>
<td><xsl:value-of select="description"/></td>
<td><xsl:value-of select="version"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
技巧4:XSLT和客户端JavaScript
尽管XSLT功能强大,但在某些情况下还不够。 例如,您可能要使用客户端脚本,例如JavaScript,JScript或VBScript。
正如我们在CSS上看到的那样,XSLT对生成HTML没有任何限制-包括使用脚本的功能。 此外,如清单7中的javascript.xsl所示,可以将值从XSLT传递给JavaScript。
清单7. javascript.xsl,一个生成客户端JavaScript的样式表
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="no"/>
<xsl:template match="/">
<html>
<head>
<title>JavaScript</title>
<script language="JavaScript"><xsl:comment>
// creates and initializes an array of product descriptions
var urls = new Array()
<xsl:for-each select="products/product">
urls[<xsl:value-of select="position()"/>] =
"<xsl:value-of select="@href"/>"
</xsl:for-each>
// user function
function doSelect(i)
{
open(urls[i])
}
// </xsl:comment></script>
</head>
<body>
<ul>
<xsl:for-each select="products/product">
<li><a href="javascript:doSelect({position()})">
<xsl:value-of select="name"/>
</a></li>
</xsl:for-each>
</ul>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
同样,要阅读javascript.xsl ,您需要记住在哪里发生了什么。 首先应用XSLT并生成HTML文件。 该文件包含一个<script>
元素,其内容由XSLT生成。 接下来,浏览器加载HTML文件并执行脚本。 请记住,脚本是由浏览器而不是样式表执行的。
例如,在javascript.xsl中以红色突出显示的行中,样式表会初始化JavaScript数组; 实际上,将值传递给脚本。
稍后,样式表生成对函数的调用,并再次将值(通过XSLT position()
函数)传递给脚本,如清单7中以蓝色突出显示的行所示 。
清单8显示了HTML生成的内容。 当用户单击<a>
标记时,该脚本由浏览器执行,如下所示:
清单8.从javascript.xsl生成HTML
<ul>
<li><a href="javascript:doSelect(1)">Playfield Text</a></li>
<li><a href="javascript:doSelect(2)">Playfield Virus</a></li>
<li><a href="javascript:doSelect(3)">Playfield Calc</a></li>
<li><a href="javascript:doSelect(4)">Playfield DB</a></li>
</ul>
您能否从XSLT样式表而不是HTML文档中调用JavaScript脚本? 是的,使用XSLT扩展。 不幸的是,XSLT扩展在XSLT 1.0中并未完全标准化。 XSLT 1.1将改善支持。
提示5:自动创建样式表
该技巧是迄今为止这五个技巧中最雄心勃勃的。
在某些情况下,您必须编写太多样式表,以至于可以使用样式表来创建样式表。 这并不像您想的那样困难,它对于以不同语言编写的网站或具有许多仅在细节上有所不同的页面的网站特别有用。
清单9中的start.xsl样式表对此进行了说明。乍一看,它看起来像一个典型的XSLT样式表。 如果仔细观察,您会发现它使用了诸如<link>
和<para>
类的特殊元素,而不是HTML元素(它们本来是<a>
或<p>
)。 此外, <xsl:output>
元素缺少method
属性。
清单9. start.xsl,一个通用的XSLT样式表
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output/>
<xsl:template match="/">
<page title="XSLT Through Generation">
<xsl:for-each select="products/product">
<para>
<link href="{@href}"><xsl:value-of select="name"/></link>
</para>
</xsl:for-each>
</page>
</xsl:template>
</xsl:stylesheet>
诀窍是使用清单10中的另一个样式表generate_html.xsl将start.xsl转换为更典型的样式表。
清单10. generate_html.xsl,一种样式表,用于将start.xsl修改为HTML
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="xsl:output">
<xsl:copy>
<xsl:attribute name="method">html</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match="page">
<html>
<head><title><xsl:value-of select="@title"/></title></head>
<body>
<h1><xsl:value-of select="@title"/></h1>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="link">
<a href="{@href}"><xsl:apply-templates/></a>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
generate_html.xsl样式表将start.xsl视为一个XML文档,并将其转换为另一个XML文档。 start.xsl本身就是XSLT样式表,这一事实与generate_html.xsl无关。 例如,以下规则将<link>
元素转换为<a>
:
<xsl:template match="link">
<a href="{@href}"><xsl:apply-templates/></a>
</xsl:template>
<xsl:output>
method
<xsl:template match="xsl:output">
<xsl:copy>
<xsl:attribute name="method">html</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template>
<xsl:for-each>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
将generate_html.xsl应用于start.xsl会生成一个样式表generate.xsl 。 它是generate.xsl而不是start.xsl ,它将创建HTML文档。
这个技巧不是关于一条狗追尾,而是将XSLT的逻辑推到最大的好处。 确实,由于XSLT非常适合将XML文档转换为其他XML文档,因此有理由认为它是转换XSLT样式表本身的理想选择。
清单11. generate.xsl,展示了start.xsl如何专门用于HTML
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
<html><head><title>XSLT Through Generation</title></head>
<body><h1>XSLT Through Generation</h1>
<xsl:for-each select="products/product">
<p>
<a href="{@href}"><xsl:value-of select="name"/></a>
</p>
</xsl:for-each>
</body></html>
</xsl:template>
</xsl:stylesheet>
当您的网站需要创建许多样式表时,您将希望应用此技巧。 例如,通过将generate_html.xsl替换为generate_wml.xsl ,您可以自动将start.xsl改编为WML(WML是无线智能手机的标记语言)。
清单12. generate_wml.xsl,它使start.xsl适应WML
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="xsl:output">
<xsl:copy>
<xsl:attribute name="method">xml</xsl:attribute>
<xsl:attribute name="doctype-public">-//WAPFORUM//DTD WML 1.1//EN</xsl:attribute>
<xsl:attribute name="doctype-system">http://www.wapforum.org/DTD/wml_1.1.xml
</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match="page">
<wml>
<card title="{@title}">
<xsl:apply-templates/>
</card>
</wml>
</xsl:template>
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="link">
<anchor><go href="{@href}"/><xsl:apply-templates/></anchor>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
故事的寓意:如果您追求大型网站的最大自动化,仅从XML文档自动生成HTML文档是不够的,那么还应该自动生成XSLT样式表。
翻译自: https://www.ibm.com/developerworks/xml/library/x-xslt5/index.html
xslt