3 数据模型
XSLT 采用和XPath 基本一致的数据模型。
对于结果树而言,根节点可以拥有任意多个孩子,包括文本节点。如果转化为XML ,结果树不一定是良构的XML 文档,但必须是良构的一般外部解析实体。
对于源树而言,如果来自良构的XML 文档,则根节点只能有一个非文本的孩子元素,否则没有很强的限制。
每个节点都有一个基准URI ,用于将相对URI 属性解析为绝对URI 。外部实体中的元素或处理指令的基准URI 为外部实体的URI ,其他则为文档的基准URI 。文档节点的基准URI 即文档实体的基准URI 。文本节点、注释节点、属性节点、名称空间节点的基准URI 是父节点的基准URI 。
3.4 去除空白字符
源文档树和样式表文档树构造之后,执行XSLT 处理之前,一些文本节点将被删除。只有仅含空白字符的文本节点才会被挤掉。去除文档节点将从文档树上删除文本节点。去除过程允许指定需要保留其空白字符的元素名。样式表和源文档都要经过空白字符去除,但是采用不同方式指定需要保留空白的元素。
符合下列条件之一的文本节点将被保留:
l 文本节点的父元素要求保留空白字符;
l 至少包含一个非空白字符(XML 中的空白字符包括#x20 、#x9 、#xD 和#xA. )
l 文本节点的某个祖先元素指定了xsl:space 属性而且没有被更近的祖先元素取消。
树中的xml:space 属性不删除。
对于样式表来说,保留空白的元素只有xsl:text 。
<!-- Category: top-level-element -->
<xsl:strip-space elements = tokens />
<!-- Category: top-level-element -->
<xsl:preserve-space elements = tokens />
源文档使用xsl:strip-space 和xsl:preserve-space 顶层元素指定要保留或删除空白字符节点的元素名称,默认情况下保留所有元素的空白字符。
XSLT 使用XPath 表达式1 )选择要处理的节点,2 )指定处理节点的条件,3 )生成插入结果树中的文本。
最外层表达式(即不是其他表达式的一部分)确定上下文的规则如下:
l 上下文节点即当前节点
l 上下文位置即当前节点在当前节点列表中的位置,从1 开始
l 上下文的大小即当前节点列表中的节点个数
l 变量绑定即表达式所属元素作用域内的绑定
l 名称空间声明即表达式所属元素作用域内的名称空间声明,包括隐含声明但不包括默认声明
l 函数库包括核心函数库、附加和扩展函数。
对 源树中一系列节点的处理生成结果树片段,对根节点的处理生成结果树。对源节点列表中的所有节点按照顺序依次处理,将生成的片段追加到结果树中。处理一个节 点的过程如下:找出所有模式与该节点匹配的模板规则,选择其中最匹配的一个,以该节点为当前节点、以源节点列表作为当前节点列表实例化选中的模板。模板通 常包含选择其他源节点列表进行处理的指令。匹配、实例化、选择这个过程递归执行,直到没有新的待处理源节点结束。
模板规则使用模式来确定应用的节点。除了用于模板规则以外,模式还可用于编号(7.7 )和声明键(12.2 )。模式指定了选择节点的条件。符合这些条件的节点称为匹配该模式。模式的语法采用了XPath 表达式语法 的一个子集。具体来说就是满足一定条件的位置路径表达式可用于模式。比如:
l para 和所有的para 元素匹配
l * 匹配任何元素
l chapter|appendix 和所有的chapter 与appendix 元素匹配
l olist/item 和所有父元素为olist 的item 元素匹配
l appendix//para 和appendix 所有后代中的para 元素匹配
l / 匹配根节点
l text() 匹配所有文本节点
l processing-instruction() 匹配所有的处理指令
l node() 匹配属性节点和根节点之外的所有节点
l id(“W11”) 匹配ID 为W11 的元素
l para[1] 匹配作为父节点中第一个para 孩子出现的所有para 元素
l *[position()=1 and self::para] 匹配作为父节点中第一个孩子出现的所有para 元素。
l para[last()=1] 匹配作为父节点中唯一para 孩子出现的所有para 元素。
l items/item[position()>1] 匹配items 中第一个item 元素以外的所有item 元素。
l item[position() mod 2 = 1] 匹配父元素中序号为奇数的所有item 孩子。
l div[@class="appendix"]//p 匹配class 属性等于appendix 的div 元素所有后代中的p 元素。
l @class 匹配所有的class 属性。
l @* 匹配任何属性
模式由| 分割的一组位置路径模式组成。位置路径中只能使用孩子和属性轴。虽然不能使用descendant-or-self 轴,但可使用// 和/ 运算符。位置路径模式也可以id 或key 函数调用开始。模式中的谓词可使用任意表达式。
仅当存在某个上下文对模式表达式求值节点出现在结果节点集中的时候,才称模式与该节点匹配。比方说,p 与任何p 元素匹配,因为对于任何p 元素,当表达式p 以其父节点作为上下文计算的时候,结果节点集中都包括p 元素。
虽然模式的语义间接通过表达式求值来表达,但直接理解起来也很容易。| 表示“或”,只要匹配其中的一项即可。/ 或// 表示的步进模式StepPattern 从右向左匹配;Child 轴首先检查NodeTest 是否为真,然后确保不是属性节点;属性轴首先检查NodeTest 为真,然后确保是属性节点;如果包含谓词表达式,首选选择符合路径表达式的节点,然后用[] 中的条件进行测试。
比如:appendix//ulist/item[position()=1] ,匹配的过程如下:
l 该节点是一个item 元素(节点测试)
l 以该节点为上下文节点,该节点的item 兄弟节点组成当前节点列表计算谓词
l 父节点为ulist
l 有一个祖先节点是appendix 元素
<!-- Category: top-level-element -->
<xsl:template match = pattern name = qname priority = number mode = qname>
<!-- Content: ( xsl:param *, template) -->
</xsl:template>
属性match 是一个模式,选择应用该规则的源节点。
没有match 属性的话,模板必须有name 属性
match 属性不能包含变量引用
template 元素的内容是应用该模板规则时实例化的模板
<!-- Category: instruction -->
<xsl:apply-templates
select = node-set-expression
mode = qname>
<!-- Content: ( xsl:sort | xsl:with-param )* -->
</xsl:apply-templates>
下面的例子为chapter 元素创建了一个block ,然后处理chapter 的直接孩子:
<xsl:template match="chapter">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
由于没有select 属性,xsl:apply-templates 指令将处理当前节点的所有孩子,包括文本节点(不包括被去除的空白文本节点)。可以使用select 属性选择要处理的节点。select 属性的值是一个表达式,表达式的计算结果必须是一个节点集。选中的节点按照文档顺序处理。下面的例子处理author-group 的所有author 孩子:
<xsl:template match="author-group">
<fo:inline-sequence>
<xsl:apply-templates select="author"/>
</fo:inline-sequence>
</xsl:template>
下面的例子则处理author-group 所有athor 孩子的given-name 节点:
<xsl:template match="author-group">
<fo:inline-sequence>
<xsl:apply-templates select="author/given-name"/>
</fo:inline-sequence>
</xsl:template>
下例处理book 元素的所有heading 后代元素:
<xsl:template match="book">
<fo:block>
<xsl:apply-templates select=".//heading"/>
</fo:block>
</xsl:template>
处理不是当前节点后代的其他元素也是可能的。下例假设department 元素拥有group 孩子和employee 后代,首先找到雇员所属的department ,然后处理这个department 的group 孩子:
<xsl:template match="employee">
<fo:block>
Employee <xsl:apply-templates select="name"/> belongs to group
<xsl:apply-templates select="ancestor::department/group"/>
</fo:block>
</xsl:template>
同一个模板中可以包含多个xsl:apply-templates 元素来完成简单的排序。下例创建了两个HTML 表格,一个是国内销售额,一个是国外销售额:
<xsl:template match="product">
<table>
<xsl:apply-templates select="sales/domestic"/>
</table>
<table>
<xsl:apply-templates select="sales/foreign"/>
</table>
</xsl:template>
有可能存在两个匹配的后代,两者存在后代关系,比如对于源文档:<doc><div><div></div></div></doc> ,规则:
<xsl:template match="doc">
<xsl:apply-templates select=".//div"/>
</xsl:template>
将同时处理外层和内层的div 元素。
一般情况下,使用xsl:apply-templates 处理当前节点的后代,这种情况下不会造成无限循环。但是如果使用xsl:apply-templates 处理当前节点后代以外的节点,有可能造成无限循环。比如:
<xsl:template match="foo">
<xsl:apply-templates select="."/>
</xsl:template>
5.5 模板规则冲突的解决
同一个源节点有可能匹配多个模板规则。这种情况下按照下列规则选择模板:
首先排除低优先级的模板规则。模板规则的优先级由priority 属性指定,默认优先级的确定顺序如下:
用| 分隔的模式分解成多个模板规则
ChildOrAttributeAxisSpecifier+QName/processing-instructions ,0
ChildOrAttributeAxisSpecifier+NCName:* ,-0.25
ChildOrAttributeAxisSpecifier+NodeTest ,-0.5
其他,0.5
即,最常见的检测节点是否具有特定类型和特定扩展名的模式优先级为0 ;比较宽松,指定类型和名称空间URI 的测试优先级为-0.25 ;更宽松的仅指定类型的测试优先级为-0.5 ;比常见模式更具体的模式的优先级为0.5 。
如果经过上述排除后仍然剩下多条规则,则报错。
<!-- Category: instruction -->
<xsl:apply-imports />
用于覆盖导入样式表中模板规则的模板规则可使用xsl:apply-imports 元素调用被覆盖的模板规则。样式表处理过程中,任何时候都有一项当前模板规则。一旦通过模式匹配选择了一项模板规则,它就成了当前模板规则,对其进行模板实例化。使用xsl:for-each 元素的时候,当前模板规则变为null ,以便对xsl:for-each 元素的内容进行实例化。xml:apply-import 使用导入样式表的模板规则处理当前节点,处理的mode 采用当前模板规则的mode 。如果当前模板规则为null 就不能调用xsl:apply-import 。比如,假设样式表doc.xsl 包含用于example 元素的模板规则:
<xsl:template match="example">
<pre><xsl:apply-templates/></pre>
</xsl:template>
另一个样式表导入了doc.xsl 并改变对example 元素的处理方法:
<xsl:import href="doc.xsl"/>
<xsl:template match="example">
<div style="border: solid red">
<xsl:apply-imports/>
</div>
</xsl:template>
结果如下:
<div style="border: solid red"><pre>...</pre></div>
Mode 用于多次处理同一个元素,每次生成不同的结果。如果xsl:template 没有match 属性,则不能使用mode 属性;如果xsl:apply-templates 具有mode 属性,则仅调用那些具有相同mode 属性的xsl:template ,否则仅调用那些没有mode 属性的模板规则 。
5.8 内置模板规则
如果样式表中没有匹配的模板规则,则采用内置模板规则,如下:
<xsl:template match="*|/">
<xsl:apply-templates/>
</xsl:template>
带有mode 属性(m )的内置模板规则:
<xsl:template match="*|/" mode="m">
<xsl:apply-templates mode="m"/>
</xsl:template>
用于文本和属性节点(复制)的内置模板规则:
<xsl:template match="text()|@*">
<xsl:value-of select="."/>
</xsl:template>
过滤处理指令和注释的模板规则:
<xsl:template match="processing-instruction()|comment()"/>
内置的名称空间模板规则同样什么也不做。由于没有匹配名称空间节点的模式,因此这也是唯一用于名称空间节点的模板规则。
内置模板规则在样式表处理之前隐含导入,因此具有最低的优先级。
本文详细介绍了XSLT的数据模型、表达式、模板规则等内容。涵盖了如何通过XSLT处理XML文档,包括节点的选择、空白字符的处理、模板规则的应用及模式匹配等关键概念。
&spm=1001.2101.3001.5002&articleId=4313722&d=1&t=3&u=a7f1df346e724d8cbd7bd1b0e02ff875)
610

被折叠的 条评论
为什么被折叠?



