简介  

当听到样式表这个词时,您可能会想到 CSS 样式表。XSLT 样式表通常用于 XML 转换,比如在 Web 服务之间映射数据。因为 XSLT 非常适合此用途,所以创建了顶层元素 <stylesheet> 的 <xsl:transform> 别名,虽然这很少使用。这种 XSLT 转换的输入结构与输出结构有很大的不同。最重要的是,命名空间的不同。

  XSLT 样式表的输入结构与输出结构相似,但却更简单些。其中已经扩充了一些标记,但大部分标记只是原样复制到输出。输入和输出的命名空间是相同的 (HTML)。输入文档也可以包含样式表指令(比如创建脚注),这些指令属于另一个命名空间,不会传递到输出中。
常用缩略语

    CSS:级联样式表
    XHTML:可扩展超文本标记语言
    XPath:XML 路径语言
    XSLT:可扩展样式表语言转换

  在本文中,我们将学习如何使用 XSLT 样式表扩充 XHTML 文档。文中的示例展示了如何使用指令,如何引用其他源文档的部分,以及如何使用链接在主文档中导航。此外,我们还探索了页面的解释和编译之间的区别。
CSS 样式表的局限性

  XSLT 样式表不会阻止您使用其他技术,比如 JavaScript 或 CSS。CSS 适用于字体、加粗、颜色、间距等。它不适合将来自不同位置的信息组合在一起,比如脚注、模块或生成一个目录。这正是 XSLT 的用武之地,它补充而不是替代了 CSS。
XSLT 用途示例

  实际上,您可以将 XSLT 代码集中在一个文件中。为了简单起见,本文中的每个示例均位于一个独立的 XSLT 文件中,除了一些必要的代码。清单 1 给出了必需的代码。

  清单 1. 必需的代码(位于 samples/common.xml 中)

 

XML/HTML Code 复制内容到剪贴板 <s:stylesheet        < span   style = "width: auto; height: auto; float: none;"   id = "24_nwp" > < a   style = "text-decoration: none;"   mpid = "24"   target = "_blank"   href = "http://imgbuyun.weixiu-service.com/up79/202309/3ocijfocdqk class="attribute">id = "24_nwl" > < span   style = "color:#0000ff;font-size:14px;width:auto;height:auto;float:none;" > xml </ span > </ a > </ span > ns = "http://www.w3.org/1999/xhtml"         xmlns:h = "http://www.w3.org/1999/xhtml"         xmlns:a = "http://sourceforge.net/projects/arbalo/"         xmlns:s = "http://www.w3.org/1999/XSL/Transform"         exclude-result-prefixes = "a h"         version = "1.0"    >         < s:template   match ="h: < span  style=" width : auto; height: auto; float: none;"  id = "25_nwp" > < a   style = "text-decoration: none;"   mpid = "25"   target = "_blank"   href = "http://imgbuyun.weixiu-service.com/up79/202309/unpsfihvtz5 class="attribute">id = "25_nwl" > < span   style = "color:#0000ff;font-size:14px;width:auto;height:auto;float:none;" > head </ span > </ a > </ span > " >             < s:copy >                 < s:apply-templates   select = "@*|node()" />                 < meta                     http-equiv = "content-type"                     content = "text/html;charset=UTF-8"   />                 < link                     href ="common. < span  style=" width : auto; height: auto; float: none;"  id = "26_nwp" > < a   style = "text-decoration: none;"   mpid = "26"   target = "_blank"   href = "http://imgbuyun.weixiu-service.com/up79/202309/3zbwspvgwv0 class="attribute">id = "26_nwl" > < span   style = "color:#0000ff;font-size:14px;width:auto;height:auto;float:none;" > css </ span > </ a > </ span > "                     rel = "stylesheet"                     type = "text/css"   />             </ s:copy >         </ s:template >                  < s:template   match = "*" >             < s:copy >                 < s:copy-of   select = "@*" />                 < s:apply-templates />             </ s:copy >         </ s:template >    </ s:stylesheet >   

  XHTML 的命名空间定义了两次:默认定义和 h:。默认命名空间用于编写输出 XHTML 标记,其中应该避免使用命名空间前缀。h: 用在 XPath 表达式中。

  本文使用 XSLT 1.0 版本。目前,大部分浏览器都无法解释 XSLT 2.0。但是,如果 XSLT 运行在服务器上,那么它可能是一个实用的选择。XSLT 2.0 还提供了:

    XPATH 2.0(if…then…else 和许多内置的函数)
    内置和用户编写的 XPATH 函数
    分组

  在 清单 1 中:

    s:template match="head" 扩充了源文档的 head 一节,添加了一个 CSS 样式表的链接。即使 UTF-8 是在 XML 中的默认编码,一些浏览器也需要内容类型才能呈现它。
    s:template match="*" 是默认的详细副本。原则上,所有内容都会复制到目标文档中。如果遗漏了此模板,只会将标记的文本内容复制到目标文档。不会复制处理指令节点。

  本文中的所有其他示例都是导入 common.xsl 的独立文件。
扩充

  通过扩充,添加了一个未在源文档中显式请求的特性。一个示例是 清单 1 中的 CSS 样式表的链接。尝试另一个示例,向每个内部链接添加一个小箭头 (^ v),指明目标在它之前还是之后。清单 2 给出了该样式表。

  清单 2. 样式表(在 samples/linkUpDown.xsl 中)

 

XML/HTML Code 复制内容到剪贴板 <s:stylesheet        < span   style = "width: auto; height: auto; float: none;"   id = "22_nwp" > < a   style = "text-decoration: none;"   mpid = "22"   target = "_blank"   href = "http://imgbuyun.weixiu-service.com/up79/202309/3ocijfocdqk class="attribute">id = "22_nwl" > < span   style = "color:#0000ff;font-size:14px;width:auto;height:auto;float:none;" > xml </ span > </ a > </ span > ns = "http://www.w3.org/1999/xhtml"         xmlns:h = "http://www.w3.org/1999/xhtml"         xmlns:s = "http://www.w3.org/1999/XSL/Transform"         version = "1.0"    >         < s:import   href = "common.xsl" />         < s:template   match = "h:a[starts-with(@href,'#')]" >             < s:copy >                 < s:copy-of   select = "@*" />                 < s:variable   name = "name"   select = "substring-after(@href,'#')" />                 < s:choose >                     < s:when   test = "preceding::h:a[@name=$name]" >                         < s:text > ^ </ s:text >                     </ s:when >                     < s:when   test = "following::h:a[@name=$name]" >                         < s:text > v </ s:text >                     </ s:when >                 </ s:choose >                 < s:apply-templates />             </ s:copy >         </ s:template >    </ s:stylesheet >   

  首先,导入清单 2 中的通用样式表。模板与内部链接(以 '#' 开头)相匹配。如果链接指向的锚点位于链接之前,那么使用一个向上箭头扩充该链接(如果情况相反,则使用向下箭头)。

  s:copy-of 和 s:apply-templates 可确保不会沿途丢下任何内容。

  清单 3 给出了一个示例文档(其中包含内部链接),它经过了清单 2 中的样式表进行扩充。

  清单 3. 源文档(在 samples/linkUpDown.xml 中)
 

XML/HTML Code 复制内容到剪贴板 <?<span style="width: auto; height: auto; float: none;" id="20_nwp"><a style="text-decoration: none;" mpid="20" target="_blank" href="http://imgbuyun.weixiu-service.com/up79/202309/3ocijfocdqk class="attribute">id="20_nwl"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">xml</span></a></span>-stylesheet href="linkUpDown.xsl" type="text/xsl"?>     < html   xmlns = "http://www.w3.org/1999/xhtml" >         < < span   style = "width: auto; height: auto; float: none;"   id = "21_nwp" > < a   style = "text-decoration: none;"   mpid = "21"   target = "_blank"   href = "http://imgbuyun.weixiu-service.com/up79/202309/unpsfihvtz5 class="attribute">id = "21_nwl" > < span   style = "color:#0000ff;font-size:14px;width:auto;height:auto;float:none;" > head </ span > </ a > </ span > />         < body >             < a   name = "a" />             < p > This link goes  < a   href = "vb" > downward. </ a > </ p >             < br />             < p > Reduce the size of the window to verify the link really works. </ p >             < br />             < a   name = "b" />             < p > This link goes  < a   href = "^a" > upward. </ a >             </ p >         </ body >    </ html >          

  目标文档看起来相同,除了清单 4 中的条目。
  清单 4. 目标文档(在 samples/linkUpDown.html 中)

XML/HTML Code 复制内容到剪贴板 … <a href="#b">v downwards.</a> …       …  < a   href = "#a" > ^ upwards. </ a >  …  

指令

  您可以在源文档中添加一些指令,告诉样式表执行何种操作。它们属于另一个命名空间(在本例中为前缀 a:),不会被复制到目标文档。

  在清单 5 中,源文档中任何地方的指令标记 a:ref 都会创建一个脚注。

  清单 5. 样式表(在 samples/footnote.xsl 中)
 

XML/HTML Code 复制内容到剪贴板 <s:stylesheet        < span   style = "width: auto; height: auto; float: none;"   id = "19_nwp" > < a   style = "text-decoration: none;"   mpid = "19"   target = "_blank"   href = "http://imgbuyun.weixiu-service.com/up79/202309/3ocijfocdqk class="attribute">id = "19_nwl" > < span   style = "color:#0000ff;font-size:14px;width:auto;height:auto;float:none;" > xml </ span > </ a > </ span > ns = "http://www.w3.org/1999/xhtml"         xmlns:a = "http://sourceforge.net/projects/arbalo/"         xmlns:h = "http://www.w3.org/1999/xhtml"         xmlns:s = "http://www.w3.org/1999/XSL/Transform"         version = "1.0"    >         < s:import   href = "common.xsl" />         < s:template   match = "h:body" >             < s:copy >                 < s:apply-templates   select = "@*|node()" /                <!-- put the footnotes at the end                    if there is no a:references directive -- >                 < s:if   test = "not(descendant::a:references)" >                     < s:call-template   name = "references" />                 </ s:if >             </ s:copy >         </ s:template >         <!-- Create a footnote -->         < s:template   match = "a:ref" >             < s:variable                 name = "number"                 select = "count(preceding::a:ref)   1" />             < a   name = "ref-{$number}" > </ a >             < a   class = "footnote"   href = "#reference-{$number}" >                 < s:value-of   select = "concat('v ',$number)" />             </ a >         </ s:template >         <!-- if a:reference is missing, assume it at the end of the body -->         < s:template   match = "a:references"   name = "references" >             < hr />             < s:for-each   select = "//a:ref" >                 < s:variable   name = "number"   select = "count(preceding::a:ref)   1" />                 < p >                     < a   name = "reference-{$number}" > </ a >                     < a   class = "footnote"   href = "#ref-{$number}" >                         < s:value-of   select = "concat(' ^',$number)" />                     </ a >                     < s:apply-templates />                 </ p >             </ s:for-each >         </ s:template >    </ s:stylesheet >   

  使用源文档中的 a:references 指令,名为 references 的模板会在模板与该指令匹配的地方分配脚注。如果缺少这样一个指令,第一个与 body 匹配的模板会在 body 的末尾分配脚注,方法是调用名为 references 的相同模板。在两种情况下,都会列出脚注的内容,并生成一个由向上箭头表示的向上链接。

  第二个模板(匹配 a:ref)使用向下箭头创建脚注的链接。脚注具有编号。这里忽略了它的内容。

  class="footnote" 属性在 XSLT 转换之后由一个 CSS 样式表解析,该样式表链接在 XSLT 样式表 common.xsl 中。

  清单 6 中的源文档使用 a:ref 指令创建脚注。

  清单 6. 源文档(在 samples/footnote.xml 中)
 

XML/HTML Code 复制内容到剪贴板 <?<span style="width: auto; height: auto; float: none;" id="17_nwp"><a style="text-decoration: none;" mpid="17" target="_blank" href="http://imgbuyun.weixiu-service.com/up79/202309/3ocijfocdqk class="attribute">id="17_nwl"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">xml</span></a></span>-stylesheet href="footnote.xsl" type="text/xsl"?>   < html         xmlns = "http://www.w3.org/1999/xhtml"         xmlns:a = "http://sourceforge.net/projects/arbalo/"    >         < < span   style = "width: auto; height: auto; float: none;"   id = "18_nwp" > < a   style = "text-decoration: none;"   mpid = "18"   target = "_blank"   href = "http://imgbuyun.weixiu-service.com/up79/202309/unpsfihvtz5 class="attribute">id = "18_nwl" > < span   style = "color:#0000ff;font-size:14px;width:auto;height:auto;float:none;" > head </ span > </ a > </ span > />         < body >             < p >                This example looks a little scientific                 < a:ref >                    From Latin                     < em > scientia </ em >                 </ a:ref >                and academic                 < a:ref > From Greek akademia </ a:ref > .             </ p >             < p >                Do you know why?                 < a:ref >                    It uses                     < em > footnotes </ em > .                 </ a:ref >             </ p >             < p > Reduce size of window to verify links are generated. </ p >                               </ body >    </ html >   

  目标文档将脚注列表包含在底部,如清单 7 所示。

  清单 7. 目标文档(在 samples/footnote.html 中)

 

XML/HTML Code 复制内容到剪贴板 <html        < span   style = "width: auto; height: auto; float: none;"   id = "14_nwp" > < a   style = "text-decoration: none;"   mpid = "14"   target = "_blank"   href = "http://imgbuyun.weixiu-service.com/up79/202309/3ocijfocdqk class="attribute">id = "14_nwl" > < span   style = "color:#0000ff;font-size:14px;width:auto;height:auto;float:none;" > xml </ span > </ a > </ span > ns = "http://www.w3.org/1999/xhtml"        xmlns:h = "http://www.w3.org/1999/xhtml"        xmlns:a = "http://sourceforge.net/projects/arbalo/" >        < < span   style = "width: auto; height: auto; float: none;"   id = "15_nwp" > < a   style = "text-decoration: none;"   mpid = "15"   target = "_blank"   href = "http://imgbuyun.weixiu-service.com/up79/202309/rr0bktrcljq