2023年 9月 2日 233.2k 0

可扩展样式表语言转换 (XSLT) 是解决信息处理问题时需要考虑的最重要的 XML 技术之一。它也是一种与其他语言非常不同的编程语言,因此在选择它作为解决方案的一部分时,了解它的用途和工作原理非常重要。

假设您的 XML 内容已被标记,根据某种语义使用一组标签来标识内容的各个部分。也许这些是外观的显示语义,但更可能的是语义考虑了信息的某种固有属性。在航空航天、汽车、制药、办公文档、商业文档、专有供应商工具以及许多其他情况下,所有标记语言必然有所不同。内容中标记的标签使得可以根据标签的使用记录来解释内容的含义。为了帮助实现这一点,命名空间可以极大地帮助区分这些标签与其他 XML 词汇表中使用的标签。

1.手头的任务

当您需要的标签与您拥有的标签不同时,就需要 XML 文档翻译。在 Web 浏览器中显示内容时,HTML 有自己的一组标签,由浏览器解释并具有呈现信息的语义。在纸上显示内容时,可扩展样式表语言格式化对象 (XSL-FO) 有自己的一组标签,由合成引擎解释为具有生成打印图像的语义。当应用程序发布用于消费的 XML 词汇表时,例如接受发票数据的 ERP 系统,并且您的内容使用文档的 OASIS 通用商业语言 (UBL) 词汇表,您的信息需要更改其标签以供使用的信息通过 ERP 系统。

此外,您可能会以多种方式将 XML 信息转换为相同的目标词汇表,因为不同的受众对您的信息有不同的理解。创作/生成的顺序和标签可能适合编辑/审阅者,但不适合用户。不同的受众需要不同的转变,这些差异可能是微妙的,也可能是广泛的。

本质上,您是根据 XML 文档中的内容创建新的单独的 XML、HTML 或文本文档。也就是说,您需要表达如何从现有的标记信息树创建新的标记信息树。

大多数编程语言都有 XML 库或某种 API。您可能会想继续使用自己喜欢的语言和库来表达转换。此类使用文档对象模型 (DOM) 的语言提供了逻辑来更改文档的各个部分,然后将树序列化为输出。或者,人们可以使用该库来访问信息并使用程序逻辑简单地写出文档,尽管这实际上并不是很简单。负责创建输出 XML 语法和正确的 Unicode 编码可能会给程序员带来负担,甚至不考虑这样做不当的风险。

XSLT 是一种图灵完备的编程语言,使用 XML 语法编写并使用。它采用格式良好的 XML 语法并生成格式良好的 XML 语法,而程序员不必担心其中任何一个语法可能出现的变化。XSLT 在其自己的命名空间中被定义为 XML 词汇表,因此,它本身是完全可组合的。也就是说,XSLT 样式表可以创建 XSLT 样式表。稍后会详细介绍这一点。

顾名思义,XSLT 可以以标准方式扩展以访问非标准功能。供应商可以提供非标准化功能,例如数据投影、独特的校对算法和自定义函数,但符合标准的 XSLT 处理器可以以标准化方式优雅地处理无法识别的功能。

2. XSLT 与其他编程语言有何不同

XSLT 及其姊妹规范 XQuery(一种 XML 查询语言)几乎在所有方面都非常相似,除了程序员编写的表达语言截然不同。两者使用相同的数据模型。许多供应商提供运行两种转换表达式的单一转换引擎。两种语言使用相同的输出序列化规范。但是 XSLT 是用 XML 编写的,而 XQuery 不是。XQuery 是使用类似 XML 的伪语法编写的,这种语法永远不会解析为 XML 文档。

而且,比较 XSLT 表达式(样式表)和 XQuery 表达式时的主要思维方式和写作风格非常不同。这些差异对于编写高质量的 XSLT 样式表至关重要,并且可能会影响您的团队基于编程方法经验的表现。

大多数编程语言主要是以命令式风格编写的。逻辑从程序代码的顶部开始,一直运行到代码的末尾,并一路产生输出。有些函数调用会跳出到其他模块,而包含指令会将其他代码段拉入主代码块,但通常是从头开始一直到结束。JavaScript、C 和 Python 只是命令式编程语言的几个例子。XQuery 也是这样一种命令式语言。XQuery 表达式本身是按照输出文档组织方式构建的。

XSLT 则不然,它的核心是一种声明性编程语言。XSLT 为转换带来的功能和强大功能在声明性风格中得到了最好的利用。人们可以为单个事件触发的所有内容声明一个 XSLT 处理程序(称为“模板”),并以命令式风格编写该处理程序,命令式程序员无疑会发现最简单的方法使用 XSLT。但这并不是使用 XSLT 的最佳方式。程序员需要熟练地构思和建立细粒度的声明性处理,同时巧妙地处理事件生成,以产生输出。

诚然,在命令式语言中使用回调是声明式编程风格的一个示例。甚至 XML 编程接口(例如 SAX)也经常使用命令式语言进行设置,并带有回调来控制由 XML 语法触发的事件。但在大多数编程语言中,这是建立在命令式模型之上的发明。

正是编写样式表方法的这种根本区别将优秀的 XSLT 程序员与在使用 XSLT 时通过黑客手段获得正确结果的程序员区分开来。虽然最终的结果是获得正确的结果,但良好地编写 XSLT 可以创建一个可以用于其他解决方案的解决方案,并且可以在维护时更加保证减少工作代码中引入的错误。编写好 XSLT 需要练习,并且需要熟练的程序员采用与使用传统命令式语言编写时所需的思维方式完全不同的思维方式。这些要点将在稍后进行说明。

考虑案例研究http://www.cranesoftwrights.com/links/ipepaper.htm 以 XML 编写的美国情报文件的呈现。几十年来,不同的情报组织产生了截然不同的情报报告,美国情报界已经就特工用来记录信息的单一 XML 词汇达成一致。在该项目中,各组织希望继续以自己的个人风格查看信息,其中只有低级结构(如部分、段落、表格、图形等)看起来相同。整体效果图,例如标题页、目录和布局约束有很大不同。XSLT 中的声明式样式非常适合创建具有重写组件的单一解决方案。未重写的已声明组件在所有文档中呈现相同的内容部分。为每个组织覆盖的已声明组件呈现不同的内容部分。以声明式风格自下而上的设计创建了一个可以根据需要在多个安装中轻松利用的解决方案。

使用传统编程语言的经验丰富的开发人员还必须认识到,XSLT 底层的数据和处理模型与他们所处理的不同。毫无疑问,程序员非常习惯于考虑程序输入文件的语法、程序输出文件的语法以及程序中从输入语法创建输出语法的步骤。依赖这种传统方法会阻碍程序员对 XSLT 的看法,并妨碍他们正确理解 XSLT 样式表的编写和处理完全脱离输入和输出文件的语法。如下所示,程序员获得了在输入文档中找到的信息,

3. XSLT和XQuery的共享数据模型

标记 XML 文件时,可以从多种语法变体中进行选择。作为练习,尝试想出五种不同的语法方法来标记简单的数学表达式“a<b” 1 ]。值得庆幸的是,XSLT 和 XQuery 处理器中的 XML 处理器可以容纳所有变幻莫测的 XML 语法,并提取文档中找到的标记 Unicode 字符信息树。这棵树中的分支和叶子称为节点,每个节点都有一个值以及与该节点上方、旁边和下方的其他节点的关系。节点也有名称,这些名称是 XML 中使用的标签(例如输入元素),以便在创建新标签信息(例如输出元素)时可以在转换中识别文档的各个部分。

XML 文档的标记树有一个正式模型,该模型定义为 XQuery 和 XPath(XML 路径语言)规范的一部分,很明显,它被称为 XDM(XQuery 和 XPath 数据模型)。在节点树中表达每个可能的 XML 文档只需要七种节点。在 XML 中定义顺序的情况下,例如元素子元素的顺序,顺序将保留在由供应商的实现创建的节点树中。如果 XML 中未定义顺序(例如元素属性的顺序),则供应商实现的顺序是任意的,并且必须在编写良好的样式表中进行适当处理。考虑到这一点,那么,

但为了创建适合 XQuery 和 XSLT 访问的 XDM,输入数据不必是 XML 语法。通过数据投影功能,供应商可以向转换提供任何内容,前提是该内容呈现为七种不同类型节点的完整 XDM 树。至少,每个供应商必须提供将 XML 文件投影为节点的 XDM 树,并将不采用 XML 语法的简单文本文件输入投影为包含单个文本节点的 XDM 树。除此之外,供应商可以在他们提供的产品上变得非常富有想象力。很明显,数据库供应商将其数据库内容表作为 XDM 树投影到用于创建输出结果的 XQuery 和 XSLT 进程。关系表可以投影为内容行和列的节点。

该图描绘了对两个不同输入使用单个转换或对单个输入使用两个不同转换的许多可能的数据流。

数据投影到XDM节点

在所有情况下,所示的变换输入都是源 XDM 节点的点三角树,并且变换的输出是结果 XDM 节点的点三角树。在顶部,XML 文档被解释为源 XDM 节点树。图中下方显示的另一源 XDM 节点树是通过某些非 XML 内容的源数据投影创建的。虽然该图仅显示从结果 XDM 节点树序列化的 XML 文档,但实际上 XSLT 和 XQuery 共享序列化规范的使用,该规范提供从节点树创建 XML、HTML、XHTML 或简单文本语法实体。该图还仅显示了转换过程的单个输入和单个输出,而事实上,

值得注意的是,供应商在标准功能的性能以及超出规范的扩展功能中可用的设施上进行竞争。如果您选择利用扩展功能,您需要注意将自己锁定在供应商的产品上。至少,由于除了 XML 和文本之外,没有标准化的数据投影请求,因此您需要区分如何请求使用 XDM 提供的非 XML 和非文本内容。然而,除此之外,您还可以选择坚持可用的标准化行为,或者通过调用特定于供应商的行为来超越产品独立性。

多年来一直关注数据文件及其语法的程序员需要以不同的方式看待 XSLT 和 XQuery,因为您的 XML 文档不被视为 XML 语法,它们被视为 XDM 节点。

4. XSLT和XQuery的共享处理模型

查看来自转换过程的输入和输出信息的共享 XDM 数据模型推断出处理模型是相似的,事实上,情况也是如此。许多供应商提供了实现处理模型的底层引擎,该处理模型影响节点上的转换,而不管用于表达转换的表达语言如何。因此,该产品同样支持 XSLT 样式表或 XQuery 表达式,因为其中任何一个都被解释为另一棵树,即操作 XDM 节点的树。

该图描述了转换过程的本质,将结果 XDM 节点创建为源 XDM 节点和转换操作 XDM 节点的混合。它还显示可用于创建源 XDM 节点的数据投影以及结果 XDM 节点的许多可能的序列化结果和解释。

XSLT和XQuery的处理模型

请注意图中的约定,即使用主符号在输出树中关联给定节点是从哪个输入树复制的。

该图说明了处理模型如何建立转换逻辑与输入和输出文件语法的独立性。该转换仅作用于操作节点和源节点以产生结果节点。处理器关心语法,而不是程序员。

同样,这与程序员习惯处理的情况非常不同。XSLT 和 XQuery 在程序员的控制下根据对输入执行的操作来组装结果。程序员没有写出语法。程序员不必考虑 XML 文档中的变化莫测的内容。不需要进行输入缓冲或线路处理,因为这一切都是由幕后的处理器处理的。您的程序员需要关注如何最好地表达如何最好地完成将输入组装到结果中。

5. XSLT 样式表的利用:多态性

在样式表的声明性质中可以找到将给定样式表的投资运用到多个解决方案中的机会。与传统的命令式编程语言相比,在评估 XSLT 时,这一优势可能会被忽视。选择使用 XSLT 并不是简单地选择使用最新、最好的面向 XML 的技术,而是选择一个比其他环境更灵活、更健壮的编程环境,可以根据结构化输入创建结构化结果。

编写 XSLT 样式表的声明式方法要求程序员以与自上而下命令式方法截然不同的方式看待转换。程序员必须建立与输入 XML 粒度相关联并匹配的输出片段的特定粒度。然后,将这些片段中的每个片段作为与输入的单个节点的处理相关联的结果的模板。这种关联只需针对输入节点的每种类型和名称进行一次,并且每次处理给定类型和名称的节点时都会将模板复制到结果中。例如,由名为“img”的 HTML 输出元素节点组成的模板,表示最终要序列化的输出<img>可以与名为“figure”的元素节点的处理相关联,该元素节点表示 的投影 XML DocBook 输入 <figure>

在此图中对此进行了描述,其中输入源节点用数字标记,输出结果节点用字母标记。管理转换的样式表是通过每个输入节点的类型和名称与该节点关联的模板的集合。当遇到每个输入节点时,样式表将结果组装为 结果的下一部分。

从与源节点关联的模板组装结果节点

程序员始终控制在模板集合中推送哪些源节点,并且 XSLT 引擎通过匹配用于构建结果的最合适的模板来响应每个推送的节点。一切都被视为节点,而不是开始标签或结束标签或空标签。

查看该图,您可以看到标识为“2”的节点的模板具有两个节点的父/子组合。当构造结果时,如此标识的四个节点被推送到样式表并触发八个结果节点“B/C”、“G/H”、“U/V”和“Y/Z”的创建。也许这个节点“2”是 XML <figure>元素,模板中的两个节点是 <div>元素父元素和<img>元素子元素。输入 XML 文档中的每个内容都会在浏览器的输出 HTML 文档中<figure>生成一对 。<div><img>

在评估样式表的长期维护成本时,XSLT 区别于大多数其他编程语言的一个宝贵属性是它“无副作用”。全局变量没有变化,因为它们在声明时与最终值绑定。模板只能看到自己的变量和全局变量,看不到其他模板的变量。在模板中所做的任何事情都不会影响所有其他模板的处理。这使得在项目的维护阶段可以进行非常稳健的转换,因为在接触其他模板时不可能“破坏”未接触过的模板。模板越细,即模板越多,代码的工作位就越孤立。

模板越多,用另一个覆盖 XML 文档声明处理的样式表包装样式表的机会就越多。这为关联的模板定义提供了一种多态性。这种覆盖通过提供如何构建结果的不同定义来利用被覆盖的样式表。为新受众创建结果可以利用现有受众的样式表,仅更改那些需要更改的行为并保留那些不需要更改的行为。也许您需要抑制向老受众公开的特定信息。一个常见的要求是使用对审阅者重要的编辑详细信息来增强最终用户的页面,以便创建最终用户从未见过的审阅副本。但审阅者可以查看增强内容,以查看原本生成的内容。

在此图中考虑导入样式表如何为标识为“2”的节点提供替代处理,如上图中所示的导入样式表。现在,构建结果时,将为四个输入节点中的每一个节点添加一个节点到树中,以创建素数标记节点“B'”、“G'”、“U'”和“Y'”。这说明了如何抑制写出节点“C”、“H”、“V”和“Z”,或者如何完全替换节点“B”、“G”、“U”和“Y”。按照前面的示例,现在<figure>输入 XML 文档中的每个内容都将成为输出 HTML 中的不同类型,<div>而无需<img>。也许输出是针对有视觉障碍的观众,因此图形图像被抑制,文本以不同的方式呈现给音频阅读器。在此示例中,没有其他任何不同,只有 的处理不同 <figure>

导入样式表以更改输出行为

在下图中考虑导入样式表如何增强对标识为“2”的节点的现有处理,如上图中所示的导入样式表。现在,当构建结果时,四个输入节点中的每一个都会将三个节点添加到树中,其中一个是新节点,另外两个是原始输出。这样,就创建了具有节点“B'/B/C”、“G'/G/H”、“U'/U/V”和“Y'/Y/Z”的结果树。这说明了如何在不触及原始样式表的情况下使用附加信息来增强输出。再次遵循前面的示例,现在输入 XML 文档中的每个内容都成为文件名或围绕该文件的其他图像元数据的<figure>包装。<div><div><span>由导入的样式表创建。也许此输出是针对编辑人员的,他们需要查看对主要受众隐藏的重要信息,但对于审查正在发布的 XML 文档内容的任务至关重要。<figure> 同样,仅更改了的处理。

导入样式表以增强输出行为

通过用针对另外两个不同受众的两个不同样式表包装主要受众的样式表,主样式表中的大部分工作不必单独维护。开发主样式表的成本可以为新受众所利用,而无需付出相对的努力。将此方法与命令式语言以及命令式片段的不同组装和维护所需的方法进行比较。使用 XSLT,导入的样式表保持完整,并且导入样式表提供了不同方法的多态性,以便<figure>为不同的受众处理 XML 文档中的元素。

一个有趣的机会是对可能被锁定到源代码控制系统的只读样式表实施第 11 小时的生产修复。导入样式表用所需的处理取代不需要的处理,直到所需的处理可以迁移到基本样式表中。

使用这些技术,项目团队可以创建已调试和工作样式表的库,这些样式表将被引入多个解决方案中并在多个解决方案中使用。片段可以被覆盖或增强,但语言的无副作用性质保证片段不会被其他模板的影响“破坏”。这是前面提到的美国情报文件发布系统的本质:导入的样式表提供通用的基本行为,而导入的样式表提供机构特定的外观和增强,所有这些都以稳健的方式完成,从而实现快速的新部署和系统范围的维护。而且,

6. 在单个数据流中同时使用 XQuery 和 XSLT

虽然 XQuery 不提供与常见代码片段相同级别的多态性,但命令式性质对传统程序员非常有吸引力。那么,人们可能会考虑在组装内容时在数据流中使用 XQuery,在发布内容时在数据流中使用 XSLT。这将描述如下。

通过 XQuery 然后 XSLT 投影内容以生成多个结果

该图显示了两个包装器 XSLT 样式表,它们导入相同的导入样式表集合,以根据投影数据的 XQuery 解释创建的一个结构化输入生成独特的结果。当然,XSLT 可以以命令式的方式代替 XQuery,并且工作人员只需学习一种基于 XML 的语言,而不是两种。然而,与尝试部署 XQuery 以利用 XSLT 中可用的通用代码多态性相反,这将是编程和维护方面的挑战。

7.浏览器中的XSLT

在何处在线部署 XSLT 与首先使用 XSLT 一样重要。基本选择是直接在用户代理中运行转换,或者在服务器上运行转换,要么在浏览器连接之前静态运行,要么动态响应浏览器交互。

选择在浏览器环境中部署 XSLT 的位置

然而,重要的是要认识到,XSLT 可以通过两种方式在浏览器用户代理中运行。许多浏览器本身仅提供 XSLT 1.0 支持,而且即使如此,也不一致。XML 处理器的不同选择和 XSLT 处理器的不同选择会导致浏览器实现之间的结果不同且不一致。Saxon/CE(客户端版)提供的非常可行的替代方案http://www.saxonica.com/ce/index.xmlXSLT 处理器完全兼容 XSLT 2.0,支持在浏览器中作为压缩的 JavaScript 代码执行,无需任何服务器端可执行文件。如果未禁用 JavaScript,所有现代 Web 浏览器都会一致地执行该引擎,为所有用户产生相同的结果。此外,XSLT 2 设施远远优于可用的 XSLT 1 设施。

8. XSLT 创建 XSLT

由于 XSLT 的性质是使用格式良好的 XML 语法编写的,因此需要考虑最后一个细微差别。由于 XSLT 生成格式良好的 XML 语法,因此 XSLT 转换可以创建输出 XSLT 转换。人们解释描述如何处理信息的 XML 文档,并输出实现如此描述的处理的 XSLT 样式表。如下所示。

合成要根据内容进行处理的样式表

这不仅仅是学术性的。非常强大的 Schematron (ISO/IEC 19757-3) 值验证语言是一种 XML 词汇表,其中表达有关 XML 内容的断言和规则。当使用 XSLT 实现时,免费提供的 Schematron XSLT 样式表使用 Schematron 表达式并发出要在 XML 输入上执行的 XSLT 逻辑中的等效内容。针对生产数据执行生成的 XSLT 逻辑的输出是验证报告。

9. 两个非常简单的编码示例

这两个简单的示例摘自Udemy 上 24 小时流式 XSLT 实践培训课程的 5 小时免费预览。这是本文中包含的唯一代码,并且该工作代码中的概念被大大简化,以说明编写 XSLT 时命令式和声明式编程风格之间的对比。我将示例限制为 XSLT 1.0,以便根据需要可以在浏览器中运行这些示例。

首先,考虑向客户销售产品的摘要的测试 XML 文档。

01  <?xml version="1.0"?>
02  <!DOCTYPE sales [
03  <!ELEMENT sales ( products, record )> <!--sales information-->
04  <!ELEMENT products ( product+ )>         <!--product record-->
05  <!ELEMENT product ( #PCDATA )>      <!--product information-->
06  <!ATTLIST product id ID #REQUIRED>
07  <!ELEMENT record ( cust+ )>                <!--sales record-->
08  <!ELEMENT cust ( prodsale+ )>     <!--customer sales record-->
09  <!ATTLIST cust num CDATA #REQUIRED>     <!--customer number-->
10  <!ELEMENT prodsale ( #PCDATA )>     <!--product sale record-->
11  <!ATTLIST prodsale idref IDREF #REQUIRED>
12  ]>
13  <sales>
14    <products><product id="p1">Packing Boxes</product>
15              <product id="p2">Packing Tape</product></products>
16    <record><cust num="C1001">
17              <prodsale idref="p1">100</prodsale>
18              <prodsale idref="p2">200</prodsale></cust>
19            <cust num="C1002">
20              <prodsale idref="p2">50</prodsale></cust>
21            <cust num="C1003">
22              <prodsale idref="p1">75</prodsale>
23              <prodsale idref="p2">15</prodsale></cust></record>
24  </sales>

该 XML 文档的结构不围绕任何特定的表示。相反,XML 是围绕树中表达的信息的内在关系构建的。第 14-15 行包含所有产品信息。第 16-23 行记录了所有向客户销售的产品的记录,按客户组织。为了不重复销售记录中的产品标题,使用引用 ID 类型属性的 XML IDREF 语义在内部引用产品。第 2 行到第 12 行中的嵌入 DTD 包括第 5 行的声明,该声明将 ID 属性归因于元素id=的属性 <product>

现在,让我们将该信息的两个 HTML 表示视为两个浏览器窗口中显示的两个单独的转换,其中左侧是信息的表格表示,右侧是相同内容的列表表示。

来自同一 XML 源的不同 HTML 结果

我们需要编写从 XML 输入构建到 HTML 输出的样式表,其中包含表达 HTML 表示语义的元素和属性,因为浏览器无法识别输入中使用的面向销售的元素。在此示例中,信息没有改变,只是信息的排列和新顺序中使用的元素发生了变化。我们需要两个转换采用相同的 XML 输入,以便获得两个不同的 HTML 输出。

首先考虑以命令式方式使用 XSLT,就像编写 XQuery 一样,其中整个自包含表达式是一个模板。

01  <?xml version="1.0"?>
02  <!--XSLT 1.0 - http://www.CraneSoftwrights.com/training -->
03  <html xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
04        xsl:version="1.0">
05    <head><title>Product Sales Summary</title></head>
06    <body><h2>Product Sales Summary</h2>
07      <table summary="Product Sales Summary" border="1">
08                                               <!--list products-->
09        <tr align="center"><th/>
10            <xsl:for-each select="//product">
11              <th><b><xsl:value-of select="."/></b></th>
12            </xsl:for-each></tr>
13                                              <!--list customers-->
14        <xsl:for-each select="/sales/record/cust">
15          <xsl:variable name="customer" select="."/>
16          <tr align="right"><td><xsl:value-of select="@num"/></td>
17            <xsl:for-each select="//product">   <!--each product-->
18              <td><xsl:value-of select="$customer/prodsale
19                                          [@idref=current()/@id]"/>
20              </td></xsl:for-each>
21          </tr></xsl:for-each>
22                                                   <!--summarize-->
23        <tr align="right"><td><b>Totals:</b></td>
24            <xsl:for-each select="//product">
25              <xsl:variable name="pid" select="@id"/>
26              <td><i><xsl:value-of 
27                        select="sum(//prodsale[@idref=$pid])"/></i>
28              </td></xsl:for-each></tr>
29      </table>
30    </body></html>

重要的是要理解,在 XSLT 中,我们显示样式表表达式中的输出,而不是使用函数调用凭空合成元素和属性(尽管这是可用的,有时它是动态计算输出的最便捷方法)信息)。第 3 行和第 30 行分别表示输出的顶点元素的开始标记和结束标记<html>。仅其存在于样式表中就足以创建输出。事实上,这就是 XSLT 的核心:样式表以模板的形式显示输出,该模板由输入信息触发并充实。在命令式示例中,整个样式表是结果树的模板。

在每个模板中,无论大小,不在 XSLT 命名空间中的元素都直接在结果中使用,而 XSLT 命名空间中的元素是被解释为控制构造或操作指令的指令,用于获取或组装要包含在下面和旁边的信息明显的结果元素。

第 5 行到第 7 行中看到的元素只是复制到结果中,因为没有遇到任何指令,以该元素开始表,以该元素<table>开始表头<tr>,并将一个空 <th>元素作为其第一个子元素。该空表头是标题行开头的空白单元格。该指令从第 10 行开始,到第 12 行结束,在该指令下可以找到单个表头元素<xsl:for-each> 的清单表达式的模板。该指令使用地址“ ”来<th>寻址文档的所有元素,因此每个模板都会重复添加到结果一次<product>//product<product>同时将嵌入式指令的焦点依次集中在每个<product>元素上。第 11 行的指令<xsl:value-of> 在使用“ .”时解决当前焦点,因此样式表向结果添加一个文本节点,其值是元素的文本值 <product>。因此,标题行的第二个和后续单元格包含所有产品名称。

第 14 行到第 21 行的元素<xsl:for-each>及其后代访问每个<cust>元素并构建一行客户编号信息和每个相应的销售编号项。第 15 行显示了当前节点与名为“customer”的变量的绑定。第 18 行和第 19 行有一个 XPath 地址,用于查找要包含在报告中的适当信息。

最后,第 23 行到第 28 行构建了总计行,其中包括单词“Totals”的单元格,并在第 27 行使用内置函数对样式表寻址的所有单元格进行求和。程序员不必实现求和逻辑,只需要求处理器对寻址节点的值求和就足够了。

接下来考虑使用声明式样式来遍历 XML,以便创建列表项的 HTML 无序列表。请注意如何存在三个模板规则,一个用于根节点(/在 XPath 中称为“”),一个用于元素 <record>,一个用于元素 <prodsale>

01  <?xml version="1.0"?>
02  <!--XSLT 1.0 - http://www.CraneSoftwrights.com/training -->
03  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
04                  version="1.0">
05  
06  <xsl:template match="/">                         <!--root rule-->
07    <html><head><title>Record of Sales</title></head>
08      <body><h2>Record of Sales</h2>
09        <xsl:apply-templates select="/sales/record"/>
10      </body></html></xsl:template>
11  
12  <xsl:template match="record">   <!--processing for each record-->
13    <ul><xsl:apply-templates/></ul></xsl:template>
14  
15  <xsl:template match="prodsale">   <!--processing for each sale-->
16    <li><xsl:value-of select="../@num"/>   <!--use parent's attr-->
17        <xsl:text> - </xsl:text>
18        <xsl:value-of select="id(@idref)"/>      <!--go indirect-->
19        <xsl:text> - </xsl:text>
20        <xsl:value-of select="."/></li></xsl:template>
21  
22  </xsl:stylesheet>

处理首先使用第 6 行到第 10 行中声明的根节点的模板规则模板构建结果树。第 7 行和第 10 行具有元素及其后代的开始和结束标记<html><xsl:apply-templates/>第 9 行是寻址<record> 元素并指示处理器将这些元素推送到样式表的指令 。

元素有一个模板规则<record>来处理推送它们所生成的事件,第 13 行将<ul>无序列表元素添加到结果中,在该规则下,<xsl:apply-templates/> 处理(推送)当前节点的子节点<record>

子“ ”元素没有模板规则<cust>,因此内置处理只是将子节点推送到样式表以进行进一步处理。元素的子元素<cust>是 <prodsale>元素。

元素有一个模板规则<prodsale>,第 16 行到第 20 行构造了添加到结果树中的列表项。

通过这种方式,结果树以零碎的方式构建,从 <html>元素开始一直到所有叶 <li>元素,以表达一个完整的 HTML 文档以在浏览器窗口中呈现。

通过模板的隔离来对比两种解决方案。命令式解决方案中只有一个模板,因此样式表只能用于创建一个结果。声明性解决方案中有三个模板,因此可以通过多个导入样式表覆盖模板来利用样式表来生成多个结果。并且这三个模板中的任何逻辑都不会影响其他任何模板,因此维护一个模板不会破坏其他模板。

10. 结论

XSLT 和 XQuery 是使用 XML 创建并为 XML 创建的图灵完备编程语言,这与将 XML 视为其基本性质的附属物的语言形成鲜明对比。

与 XQuery 和其他命令式语言相比,XSLT 的表达式语言具有许多优点,主要体现在用于创建不同但相关的解决方案的转换行为的多态性方面。

虽然该语言需要在创建细致且强大的样式表片段方面进行培训和实践,但投资的回报是所部署的样式表的完整性、灵活性和稳健性。

选择使用 XSLT 对于 XML 和其他结构化内容(例如数据库中的内容)的信息处理规划非常重要。正确部署是值得付出努力的。

 

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论