【发布时间】:2011-02-17 18:46:26
【问题描述】:
我已经搜索过这个问题,但是用语言来表达涉及 XSL 的问题似乎非常困难,所以我什么也没想到。
我的问题是这样的:
一家公司生产了一个应用程序,该应用程序使用 XML 文件来存储其“文档”。这些文件是针对架构版本 1.1 强制执行的
但是,该公司决定发布一个新版本的软件,该版本针对具有不同结构的新模式(模式 1.2)进行验证
为了让客户无缝地使用新版本,我们希望在打开文件时以编程方式将其符合 1.1 的文件转换为符合 1.2 的文件。理想情况下,我们使用 XSL 转换来做到这一点。
在这两种模式中,有些类型是相同的,有些类型有新的或重命名的成员,有些则存储在完全不同的结构中。因此,编写从一个到另一个的转换是相当乏味的,维护它更是如此。
如果能编写一种生成转换的转换,它可以将旧模式中未更改的类型匹配到新模式,并在它不能做的地方发出占位符元素(例如<xsl:message> 元素),那就太好了因此,为了提示开发人员在需要的地方手动编写自定义逻辑,并保证其他地方都兼容。
所以程序是这样的:
- 针对 Schema 1.2 运行转换 A。这会生成变换 B;
- 针对 Schema 1.1 运行转换 B。这会在可能的情况下将 Schema 1.2 与 Schema 1.1 匹配,生成转换 C;
- Transform C 被开发人员用作骨架来编写从 instance 1.1 到 instance 1.2 的水密转换。
我已经通过实现它获得了一个公平的方法,但是 XSLT 1.0 的一些细节给我带来了问题。
转换 B 需要自动生成 <xsl:call-template> 语句,并将遇到的每个元素的类型名写入name 属性。然后,这将为每个 type 正确运行转换逻辑,以生成转换 C。
但是,call-template 似乎不接受任何 xpath 语法。它坚持name 必须只包含一个 NMTOKEN 和一个 NMTOKEN。从设计的角度来看,我可以理解这一点,但这很烦人,因为我想根据元素的类型而不是名称在元素上运行逻辑。我想在xsl:template match="element" 模板中声明call-template name="@type"。我的第一阶段确保存在一个匹配的命名模板来调用。
我不确定如何继续。有没有人尝试过这样的事情?是否有一些计算机科学的基本理论宣称在声明性语法中是不可能的? (希望不会!)
我希望我的解释清楚。如果没有,我会发布代码。
【问题讨论】:
-
一个可能有用的解决方案是使用xsl:namespace-alias 从 XSLT 本身生成 XSLT 代码。因此,您将能够提供您通常无法在运行时执行的操作,例如从字符串评估 XPath 表达式。虽然dyn:evaluate 也是一种选择。
-
我不相信有通用的方法来做到这一点。
-
@Tom W:我认为你正在用这种方法浪费时间。任何模式都不应该如此复杂(标准当然也不是)以至于它不会让您轻松编写从一个模式到另一个模式的转换。
-
@Alejandro: 我不知道是什么让你这么说。模式很少非常复杂,但它们很长。当我说手动保持转换很乏味时,我是根据经验说话的。此外,频繁的版本修改需要每次都用肉眼检查转换。
-
@John Saunders:我担心你可能弄错了。我已经通过实施看起来广泛适用的东西获得了公平的方法。我只是在处理细节问题,同时对陷阱和并发症提出一般要求。