XSLT 1.0推荐标准摘译(第四部分)

来源:互联网 发布:windows nextcloud 编辑:程序博客网 时间:2024/06/05 07:22

8 重复

<!-- Category: instruction -->
<xsl:for-each
  select = node-set-expression>
  <!-- Content: (
xsl:sort*, template) -->
</xsl:for-each>

必要属性select 中的表达式计算结果必须是一个节点集。比如XML文档:

<customers>

  <customer>

    <name>...</name>

    <order>...</order>

    <order>...</order>

  </customer>

  <customer>

    <name>...</name>

    <order>...</order>

    <order>...</order>

  </customer>

</customers>

下例将遍历每个客户生成一张表:

<xsl:templatematch="/">

  <html>

    <head>

      <title>Customers</title>

    </head>

    <body>

      <table>

        <tbody>

          <xsl:for-eachselect="customers/customer">

            <tr>

              <th>

                <xsl:apply-templatesselect="name"/>

              </th>

              <xsl:for-eachselect="order">

                <td>

                  <xsl:apply-templates/>

                </td>

              </xsl:for-each>

            </tr>

          </xsl:for-each>

        </tbody>

      </table>

    </body>

  </html>

</xsl:template>

 

9 条件处理

9.1 xsl:if

<!-- Category: instruction -->
<xsl:if
  test = boolean-expression>
  <!-- Content: template -->
</xsl:if>

Test属性值是一个表达式,计算结果转化成布尔值;如果为真则实例化内容模板,否则什么也不做,下例将names元素中的名字生成一个逗号分隔的列表:

<xsl:templatematch="namelist/name">

  <xsl:apply-templates/>

  <xsl:iftest="not(position()=last())">, </xsl:if>

</xsl:template>

下例将表格每隔一行用黄色显示:

<xsl:templatematch="item">

  <tr>

    <xsl:if test="position() mod 2 =0">

       <xsl:attributename="bgcolor">yellow</xsl:attribute>

    </xsl:if>

    <xsl:apply-templates/>

  </tr>

</xsl:template>

9.2 xsl:choose

<!-- Category: instruction -->
<xsl:choose>
  <!-- Content: (
xsl:when+, xsl:otherwise?) -->
</xsl:choose>

<xsl:when
  test = boolean-expression>
  <!-- Content: template -->
</xsl:when>

<xsl:otherwise>
  <!-- Content: template -->
</xsl:otherwise>

处理xsl:choose元素的时候,依次测试每个xsl:when,只有第一个test属性表达式求值结果为真的when的内容模板被实例化;如果都不为真,则实例化otherwise的内容模板;如果没有otherwise模板则什么也不创建。比如下例根据有序列表的嵌套深度选择不同的编号格式:

<xsl:templatematch="orderedlist/listitem">

  <fo:list-item indent-start='2pi'>

    <fo:list-item-label>

      <xsl:variable name="level"

                   select="count(ancestor::orderedlist) mod 3"/>

      <xsl:choose>

        <xsl:when test='$level=1'>

          <xsl:numberformat="i"/>

        </xsl:when>

        <xsl:when test='$level=2'>

          <xsl:numberformat="a"/>

        </xsl:when>

        <xsl:otherwise>

          <xsl:numberformat="1"/>

        </xsl:otherwise>

      </xsl:choose>

      <xsl:text>. </xsl:text>

    </fo:list-item-label>

    <fo:list-item-body>

      <xsl:apply-templates/>

    </fo:list-item-body>

  </fo:list-item>

</xsl:template>

 

10 排序

<xsl:sort
  select = string-expression
  lang = { nmtoken }
  data-type = { "text" | "number" |qname-but-not-ncname }
  order = { "ascending" | "descending" }
  case-order = { "upper-first" | "lower-first"} />

排序xsl:sort元素可以出现在xsl:apply-templatesxsl:for-each中,xsl:sort的第一个孩子指定排序主键,第二个指定次重要键,依次类推。如果xsl:apply-templatesxsl:for-each元素中出现一个或多个xsl:sort,则不再按照文档序处理选中的节点,而是根据指定的键排列节点然后依次处理。如果用在xsl:for-each元素中, xsl:sort必须是第一个孩子。xsl:apply-templatesxsl:for-each实例化模板的时候,当前节点列表包括经过排序的所有待处理节点。

属性select的值是一个表达式,处理每个节点的时候,以处理的节点为当前节点、没有排序的全部待处理节点作为当前节点列表对这个表达式求值,结果转化为字符串,作为该节点的排序键。Select属性的默认值为.,即以当前节点的字符串值作为排序键。

其他属性作为属性值模板处理,用于控制排序。Order指定按升序(ascending)还是降序(descending)排序。Lang说明按什么语言排序,默认由系统环境决定。data-type指定字符串的类型:text表示按照lang语言习惯的词典序排序,number 说明要转化成数字进行排序,此时不再考虑lang属性;如果采用其他数据类型也可指定一个QName;默认值为textcase-order取值upper-first lower-first,表明text类型的键按照大写字母还是小写字母在前。

比如:

<employees>

  <employee>

    <name>

      <given>James</given>

      <family>Clark</family>

    </name>

    ...

  </employee>

</employees>

可采用下列模板规则:

<xsl:templatematch="employees">

  <ul>

    <xsl:apply-templatesselect="employee">

      <xsl:sortselect="name/family"/>

      <xsl:sortselect="name/given"/>

    </xsl:apply-templates>

  </ul>

</xsl:template>

 

<xsl:templatematch="employee">

  <li>

    <xsl:value-ofselect="name/given"/>

    <xsl:text> </xsl:text>

    <xsl:value-ofselect="name/family"/>

  </li>

</xsl:template>

11 变量和参数

<!-- Category: top-level-element -->
<!-- Category: instruction -->
<xsl:variable
  name = qname
  select = expression>
  <!-- Content: template -->
</xsl:variable>

<!-- Category: top-level-element -->
<xsl:param
  name = qname
  select = expression>
  <!-- Content: template -->
</xsl:param>

变量是绑定某个值的名称,绑定的值可以是表达式能够返回的任何对象。绑定变量可使用xsl:variablexsl:param元素,差别在于为xsl:param变量指定的值仅仅是一个默认值,引用参数额模板或样式表被调用时,可使用传递的参数代替默认值。变量绑定元素在样式表树中都有一定的可见区域,在该区域中,对于变量绑定元素本身可见的任何变量绑定都是不可见的,就是说只有最内层的变量可见。

11.1 结果树片段

除了四种基本XPath数据类型(字符串、数字、Boolean和节点集)之外,变量为表达式语言引入了一种新的数据类型:结果树片段。结果树片段表示结果树的一部分,相当于只有一个根节点的节点集,但是只允许字符串操作,而不能使用///[]运算符。结果树片段复制到结果树中的时候,所有节点全部复制。只有引用结果树片段类型的变量,或者调用返回结果树片段类型的扩展函数、请求返回结果树片段类型的系统属性,表达式才会返回这种类型的值。

 

11.2 变量和参数的值

为变量绑定元素赋值有三种方式:select属性(此时元素的内容必须为空)、指定元素内容模板(没有select属性,变量的值为模板实例化得到的结果树片段)或者取默认值空字符串(没有select和内容模板)。如果使用内容模板,则结果树片段中的节点不能有属性和名称空间节点,结果树片段中节点的基准URI即变量绑定元素的基准URI

如果使用变量引用节点位置,不能用:

<xsl:variablename="n">2</xsl:variable>...

<xsl:value-ofselect="item[$n]"/>

因为变量n绑定的是一个结果树片段,而不是数字,上述模板将输出第一个item元素的值。可改为下面的形式:

<xsl:variablename="n" select="2"/>...

<xsl:value-ofselect="item[$n]"/>

或者

<xsl:variablename="n">2</xsl:variable>...

<xsl:value-ofselect="item[position()=$n]"/>

下面的模板将参数值指定为空节点集:

<xsl:paramname="x" select="/.."/>

 

11.3 xsl:copy-of中使用变量和参数

<!-- Category: instruction -->

<xsl:copy-of  select= expression />

xsl:value-of首先转换成字符串不同, xsl:copy-of元素直接将结果树片段插入结果树。如果必要属性select表达式计算的结果是一个结果树片段,则将整个片段复制到结果树中。如果是一个节点集,则将所有节点按照文档顺序插入结果树:元素节点的复制包括名称空间节点、属性节点、孩子结点以及该元素本身;根节点的复制包括所有的孩子但不包括它自身。如果结果既不是结果树片段也不是节点集,则转化成字符串插入结果树。

 

11.4 顶层变量和参数

顶层变量绑定声明的是全局变量,到处可见。顶层xsl:param元素为样式表本身声明参数,但XSLT本身没有定义向样式表传递参数的机制。样式表不能包含相同导入优先级的同名变量绑定。定义变量值的表达式或者模板计算时,上下文节点即处理根节点时所用的上下文节点,当前节点即源文档的根节点,当前节点列表仅包含根节点。如果全局变量的值引用另一个变量,应避免循环引用。

<xsl:variablename="para-font-size">12pt</xsl:variable>

 

<xsl:templatematch="para">

 <fo:blockfont-size="{$para-font-size}">

   <xsl:apply-templates/>

 </fo:block>

</xsl:template>

 

11.5 模板中的变量和参数

在模板中,xsl:variable可以出现在任何允许指令的地方,xsl:param只能出现在xsl:template的开始位置。绑定对其后的兄弟及其后代都是可见的,但对于变量绑定元素本身不可见。同一模板中的变量绑定不能同名,但可以使用相同的名称覆盖(上层模板或?)顶层的变量绑定。为便于批处理方式处理器的实现,变量一经绑定,其值不再改变。

 

11.6 向模板传递参数

<xsl:with-param  name = qname select =expression>
   <!-- Content: template -->
</xsl:with-param>

元素xsl:with-param用于向模板传递参数,可用于xsl:call-templatexsl:apply-templates。属性name指定要替换其默认值的参数名称,没有匹配参数名的xsl:with-param将被忽略。赋值的方法和变量绑定相同,计算select表达式的上下文和模板调用元素xsl:apply-templatesxsl:call-template相同。

<xsl:templatename="numbered-block">

  <xsl:param name="format">1.</xsl:param>

  <fo:block>

    <xsl:numberformat="{$format}"/>

   <xsl:apply-templates/>

  </fo:block>

</xsl:template>

 

<xsl:templatematch="ol//ol/li">

  <xsl:call-templatename="numbered-block">

    <xsl:with-paramname="format">a. </xsl:with-param>

  </xsl:call-template>

</xsl:template>

 

12 其它函数

12.1 多个源文档

Function: node-set document(object, node-set?)

Document函数用于访问主源文档之外的XML文档。

如果第一个参数不是节点集,则转化成字符串作为文档URI,检索文档并构造源树。如果URI不包含片段标识符,则返回的节点集中仅包含文档的根节点,否则返回片段标识符所指定的节点。

When the document function has exactly one argument and the argument is anode-set, then the result is the union, for each node in the argument node-set,of the result of calling the document function with the first argument being the string-value of the node, and the second argument being a node-setwith the node as its only member. When the document function has two arguments and the first argument is anode-set, then the result is the union, for each node in the argument node-set,of the result of calling the document function with the first argument being the string-value of the node, and with the second argument being thesecond argument passed to the document function.

URI引用是相对的。使用第二个参数node-set中第一个节点的基准URI来解析绝对URI。如果没有第二个参数,则默认为样式表中调用document函数的那个节点。document("") 引用样式表的根节点。

Two documentsare treated as the same document if they are identified by the same URI. TheURI used for the comparison is the absolute URI into which any relative URI wasresolved and does not include any fragment identifier. One root node is treatedas the same node as another root node if the two nodes are from the samedocument. Thus, the following expression will always be true:

generate-id(document("foo.xml"))=generate-id(document("foo.xml"))

The document function gives rise to the possibility that a node-setmay contain nodes from more than one document. With such a node-set, therelative document order of two nodes in the same document is the normal document order defined by XPath [XPath]. The relative document order of two nodes in differentdocuments is determined by an implementation-dependent ordering of thedocuments containing the two nodes. There are no constraints on how theimplementation orders documents other than that it must do so consistently: animplementation must always use the same order for the same set of documents.

12.2

Key用于隐含交叉索引。XML中的IDIDREFIDREFS属性用于对XML文档进行显式的交叉索引,XSLT提供了XPath id 函数来访问这些属性。但这种机制有不少局限性:ID属性必须在DTD中声明,如果采用外部DTD,只有读入的时候才能识别;一个文档只能包含一组彼此不同的ID;元素ID只能作为属性指定;ID只能是XML名,不能包含空格;一个元素最多只能有一个ID。因此有时候XML文档采用其他的交叉索引结构。

一个key是一个三元组:节点、键的名称和键值(字符串)。键是ID的推广,但没有ID的局限。在样式表中使用xsl:key元素声明,命名键的值可以在任何适当的地方指定,比如属性、孩子或内容,使用XPath表达式赋值,键值可以是任何字符串。同一个节点可有多个键,这些键甚至可以同名但值不同。同一个文档中可有多个键名、键值都相同但属于不同节点的键。

<!-- Category: top-level-element -->

<xsl:key  name= qname match = pattern use = expression />

属性name指定键名,必须是一个QName。属性match是一个模式,与其匹配的任何节点都可拥有该键。属性use是一个表达式,对和模式匹配的每个节点计算一次,将结果作为键值。如果结果是节点集,则该节点拥有多个同名的键,每个键的值分别是节点集中每个节点的字符串值;否则结果转化成字符串作为键值。因此,如果节点x有一个键y,值为z,则必须存在一个xsl:key元素:

xxsl:keymatch属性匹配;

xsl:key元素属性name的值为y

如果use属性以x为当前节点、仅含x的节点列表为当前节点列表,计算得到对象u,则z等于u转化成字符串的值,或者等于u中每个节点的字符串值。

如果节点和多个xsl:key元素匹配,所有匹配的xsl:key元素都会使用。属性usematch不能包含变量引用。

Function: node-set key(string, object)

第一个参数指定了键的名称。如果第二个参数是节点集以外的类型则转化成字符串作为键值,返回文档中具有该键且键值为这个字符串的所有节点组成的节点集。如果第二个参数是节点集,相当于指定了多个键值(彼此为或的关系)。

比如,对于声明<xsl:keyname="idkey" match="div" use="@id"/>,表达式("idkey",@ref)相当于id(@ref),假设XML源文档中声明了唯一的ID属性<!ATTLISTdiv id ID #IMPLIED>而且当前节点的ref属性没有空格。

假一个描述函数库的文档使用prototype元素定义函数:

<prototype name="key"return-type="node-set">

<arg type="string"/>

<arg type="object"/>

</prototype>

并且有一个function元素引用函数名:

<function>key</function>

可用下面的样式表在引用和定义之间建立超链接:

<xsl:key name="func"match="prototype" use="@name"/>

 

<xsl:template match="function">

<b>

  <ahref="#{generate-id(key('func',.))}">

   <xsl:apply-templates/>

  </a>

</b>

</xsl:template>

 

<xsl:template match="prototype">

<p><a name="{generate-id()}">

<b>Function: </b>

...

</a></p>

</xsl:template>

还可使用key检索其它文档中的键。比方说,假设文档中有形如<bibref>XSLT</bibref>的参考资料引用,而另一个XML文档bib.xml则包含资料记录<entryname="XSLT">...</entry>,可用下面的样式表转换bibref元素:

<xsl:key name="bib" match="entry"use="@name"/>

 

<xsl:template match="bibref">

  <xsl:variablename="name" select="."/>

  <xsl:for-eachselect="document('bib.xml')">

   <xsl:apply-templates select="key('bib',$name)"/>

 </xsl:for-each>

</xsl:template>

 

12.3 数字格式

Function: string format-number(number, string, string?)

函数format-number将参数number中的数字按照第二个参数string指定的格式转化成字符串,第三个参数用于指定小数格式(否则采用默认小数格式)。格式化字符串采用JDK1.1 DecimalFormat类定义的语法,不能包含货币符号(#x00A4)。小数格式必须是QName,引用decimal-format元素。

<!--Category: top-level-element -->

<xsl:decimal-format

  name = qname

  decimal-separator = char

  grouping-separator = char

  infinity = string

  minus-sign = char

  NaN = string

  percent = char

  per-mille = char

  zero-digit = char

  digit = char

pattern-separator = char />

属性name给出了小数格式的名称,如果没有指定name属性则为默认小数格式。其他属性和JDK 1.1 DecimalFormatSymbols 类中的方法相对应。属性decimal-separator指定小数部分的分隔符号,默认为“.”(小数点)。属性percent 指定百分号,默认为%per-mille千分位,默认为Unicode千分符 (#x2030)zero-digit指定代表零的符号,默认为0

下面两个属性控制格式化模式(字符串)的解释:digit指定格式化字符串中的数字占位符,默认为#pattern-separator用于将模式划分为两部分,分别用于正数和负数,默认值为;

下面三个属性指定可以出现在格式化结果中的字符或字符串:infinity定义用于表示无限大的字符串,默认值为InfinityNaN定义表示NaN值的字符串,默认为NaNminus-sign定义默认的负数符号,缺省值为-

 

12.4 杂项函数

Function: node-set current()

返回一个节点集,其中只包含当前节点。对于最外层表达式,当前节点一定是上下文节点,因此<xsl:value-of select="current()"/><xsl:value-of select="."/>是相同的。但是谓词中([])中的当前节点通常和上下文节点不一致,比如<xsl:apply-templatesselect="//glossary/item[@name=current()/@ref]"/>将处理glossaryname属性与当前节点ref属性相同的所有item节点,而不同于<xsl:apply-templatesselect="//glossary/item[@name=./@ref]"/>,后者相当于<xsl:apply-templatesselect="//glossary/item[@name=@ref]"/>,即name属性和ref属性值相同的item节点。模式中不能使用current函数。

Function: string unparsed-entity-uri(string)

返回指定名称的非解析实体URI作为当前节点。

Function: string generate-id(node-set?)

生成一个字符串唯一标识参数node-set中的第一个节点,如果省略参数则默认为当前节点。生成的唯一标识符只能由ASCII字母或数字组成,并且必须以字母开始。

Function: object system-property(string)

返回指定的系统属性。xsl:version,处理器实现XSLT版本号(数字); xsl:vendorXSLT处理器提供商(字符串);xsl:vendor-url,提供商的主页(字符串)。

 

13 消息

<!-- Category:instruction -->

<xsl:message  terminate = "yes" |"no">

  <!-- Content: template -->

</xsl:message>

发送一条消息,具体发送方式依赖于XSLT处理器。Xsl:message的内容是一个模板,实例化的时候创建一个XML片段作为消息的内容。如果属性terminate的值是yes,发送这条消息后XSLT处理器应停止处理,默认值为no

实现消息本地化,最好的办法是将某种语言的消息文本集中到一个文件中。比如,假设L语言的消息存储到/L.xml文件中:

<messages>

  <messagename="problem">A problem was detected.</message>

  <messagename="error">An error was detected.</message>

</messages>

样式表可通过下面的办法检索:

<xsl:param name="lang"select="en"/>

<xsl:variable name="messages"

 select="document(concat('resources/', $lang,'.xml'))/messages"/>

 

<xsl:template name="localized-message">

  <xsl:paramname="name"/>

 <xsl:message>

   <xsl:value-of select="$messages/message[@name=$name]"/>

 </xsl:message>

</xsl:template>

 

<xsl:template name="problem">

 <xsl:call-template name="localized-message"/>

   <xsl:with-paramname="name">problem</xsl:with-param>

  </xsl:call-template>

</xsl:template>

 

14 扩展

XSLT支持两种形式的扩展:扩展元素和扩展函数。

 

15 退让

<!-- Category:instruction -->

<xsl:fallback>

  <!-- Content: template -->

</xsl:fallback>

通常实例化xsl:fallback元素什么也不做。但是,如果XSLT处理器对指令元素执行退让,而指令元素有一个或多个xsl:fallback孩子,则所有xsl:fallback孩子的内容必须按照顺序实例化。xsl:fallback元素的内容是模板。

下列函数可与xsl:choosexsl:if指令结合使用,定义如果某个元素或函数不存在样式表应如何处理。

Function: boolean element-available(string)

判定是否存在指定的指令。

Function: boolean function-available(string)

判定函数库中是否存在指定的函数。

 

16 Output

<!-- Category:top-level-element -->
<xsl:output
  method = "xml" | "html" | "text" |qname-but-not-ncname
  version = nmtoken
  encoding = string
  omit-xml-declaration = "yes" | "no"
  standalone = "yes" | "no"
  doctype-public = string
  doctype-system = string
  cdata-section-elements = qnames
  indent = "yes" | "no"
  media-type = string />

元素xsl:output用于指定输出格式,只能作为顶层元素出现。属性method定义了输出结果树的基本方式。如果没有前缀的话,只能是xmlhtmltext之一。

如果结果树的根节点有元素孩子,而且第一个元素孩子(文档元素)的扩展名包含html(不论大小写)且没有名称空间URI,第一个元素孩子之前的所有文本节点都只含空白字符,则默认输出方法为html,否则默认输出方法为xml

Version指定output方法的版本;indent说明输出结果树的时候是否允许添加空白,只能是yesnoencoding指定对输出字符序列的编码方法,大小写敏感,必须是IANARFC2278)注册的字符集或者以X-开始;media-type指定数据的MIME媒体类型,不应包含charset参数;doctype-system指定文档类型声明中使用的系统标识符;doctype-public指定文档类型声明使用的公共标识符;omit-xml-declaration指定是否输出XML声明,只能是yesnostandalone指定是否输出独立文档声明,只能是yesnocdata-section-elements指定一组元素名称,文本孩子结点使用CDATA节输出。

16.1 XML输出方法

Xml输出方法将结果树作为良构的XML一般可解析实体输出,如果结果树只有一个元素节点孩子而没有文本节点孩子,也可看做良构的XML文档实体。 注意,输出XML处理器可能需要增加名称空间声明。

Version属性指定输出结果树使用的XML版本,默认为1.0

Encoding指定编码格式,处理器必须支持UTF-8UTF-16

属性indent如果为yes,可以使结果比较美观,默认值为no

16.2 HTML输出方法

The html outputmethod outputs the result tree as HTML; for example,

<xsl:stylesheet version="1.0"

               xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="html"/>

<xsl:template match="/">

  <html>

  <xsl:apply-templates/>

  </html>

</xsl:template>

...

</xsl:stylesheet>

属性version的默认值为4.0。扩展名包含非空名称空间URI的元素应该作为XML输出。如果元素扩展名没有名称空间URI,但是本地名也不是HTML元素名,则作为非空的行内元素输出。空元素不输出结束标签,如areabasebasefontbrcolframehr, imginputisindexlinkmetaparam。比如样式表中的<br/> <br></br>应输出<br>HTML元素名称不区分大小写,应该都能正确识别,如BRBr应该都输出没有结束标签的brHtml输出方法不能对脚本或样式元素的内容转义,比如<script>if (a &lt; b) foo()</script><script><![CDATA[if (a < b) foo()]]></script>应该输出<script>if (a < b) foo()</script>。不能转义属性值中出现的<字符。Indent的默认值是yesHtml输出方法应该转义URI属性值中出现的非ASCII字符。输出处理指令时应用>代替?>。以最简形式输出布尔属性值,如<OPTIONselected="selected">输出<OPTIONselected>。不能转义属性值中的“&{”,如<BODY bgcolor='&amp;{{randomrbg}};'>应输出<BODY bgcolor='&{randomrbg};'>

如果有HEAD元素,应添加META元素指定实际使用的字符编码,如<HEAD><METAhttp-equiv="Content-Type" content="text/html;charset=EUC-JP">...media-type 的默认值是text/html

 

16.3 Text输出方法

文本输出方式不对字符进行转义,media-type属性的默认值是text/plain

 

16.4 禁用输出转义

通常为保证输出XML是良构的,xml输出方法会对&< (可能还有其他字符)进行转义,但是对xsl:value-ofxsl:text元素可通过disable-output-escaping =yes’禁用输出转义。