使用 xslt 转换多个 xml 模式文档
Posted
技术标签:
【中文标题】使用 xslt 转换多个 xml 模式文档【英文标题】:Using xslt to transform multiple xml schema documents 【发布时间】:2012-01-12 06:29:21 【问题描述】:我有许多 xml 架构文档,用于描述我的应用程序的配置设置。 xml 模式看起来类似于以下几行:
客户端.xsd
<xsd:schema targetNamespace="http://www.example.com/network"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="Client">
<xsd:attribute name="Host" type="xsd:string>
</xsd:complexType>
</xsd:schema>
服务器.xsd
<xsd:schema targetNamespace="http://www.example.com/network"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="Server">
<xsd:attribute name="Port" type="xsd:unsignedShort>
<xsd:attribute name="MaxConnections" type="xsd:int default="32">
</xsd:complexType>
</xsd:schema>
Application.xsd
<xsd:schema targetNamespace="http://www.example.com/core"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="Application">
<xsd:attribute name="Name" type="xsd:string>
<xsd:attribute name="Id" type="xsd:int>
</xsd:complexType>
</xsd:schema>
FooClient.xsd
<xsd:schema targetNamespace="http://www.example.com/foo"
xmlns:core="network://www.example.com/network"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://www.example.com/network"
schemaLocation="client.xsd"/>
<xsd:complexType name="FooClient">
<xsd:complexContent>
<xsd:extension base="network:Client">
<xsd:attribute name="foo" type="xsd:string"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
FooServer.xsd
<xsd:schema targetNamespace="http://www.example.com/foo"
xmlns:core="network://www.example.com/network"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://www.example.com/network"
schemaLocation="client.xsd"/>
<xsd:complexType name="FooServer">
<xsd:complexContent>
<xsd:extension base="network:Server">
<xsd:attribute name="foo" type="xsd:string"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
FooApplication.xsd
<xsd:schema targetNamespace="http://www.example.com/foo"
xmlns:core="http://www.example.com/core"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://www.example.com/core"
schemaLocation="Application.xsd"/>
<xsd:include schemaLocation="FooClient.xsd"/>
<xsd:include schemaLocation="FooServer.xsd"/>
<xsd:complexType name="FooApplication">
<xsd:complexContent>
<xsd:extension base="core:Application">
<xsd:sequence>
<xsd:element name="FooInput" type="FooClient"/>
<xsd:element name="FooOutput" type="FooServer"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="Foo" type="FooApplication"/>
</xsd:schema>
这是一个实例文档的示例:
<foo:Foo xmlns:foo="http://www.example.com/foo"
Id="1234"
Name="FooInstance1">
<FooInput Host="localhost:12345"
Name="Input"
foo="bar"/>
<FooOutput Port="54321"
Name="Output"
foo="bar"/>
</foo:Foo>
我的目标是获取 FooApplication 架构文档并将其转换为人类可读的形式,以便负责维护应用程序的人员准确了解可用的配置选项、数据类型、默认值等。最终我将添加文档也可以添加到输出中的元素,但现在我试图保持简单。所以上面的例子可能看起来像这样:
FooApplication/Id, int
FooApplication/Name, string
FooApplication/FooInput/Host, string
FooApplication/FooInput/foo, string
FooApplication/FooOutput/Port, unsignedShort
FooApplication/FooOutput/MaxConnections, int, default=32
FooApplication/FooOutput/foo, string
对于这项任务,xslt 似乎是显而易见的工具。但是,我很难弄清楚如何从多个文档中提取数据。我尝试过这样的事情(例如用于索引 complexType 的所有元素):
<xsl:template match="xsd:include">
<xsl:apply-templates select="document(@schemaLocation)"/>
</xsl:template>
<xsl:template match="xsd:import">
<xsl:apply-templates select="document(@schemaLocation)"/>
</xsl:template>
<xsl:key name="complexType" match="xsd:complexType" use="@name"/>
但是在使用密钥时,只有来自 FooApplicaiton.xsd 的 complexType 被解析。
有人对如何实现这一点有任何见解吗?
非常感谢。
【问题讨论】:
【参考方案1】:我会先看看DocFlex,看看他们处理 XML Schema 文档的方法是否对您有意义。然后,您应该能够按比例放大或缩小。对于任何琐碎的事情,如果您必须构建自己的文档系统,我认为它应该基于 XML 模式对象模型 API (XSOM),然后创建可以使用 XSLT 呈现的 XML...
【讨论】:
【参考方案2】:你不需要以任何方式处理模式,除了更好地编写模式。
在任何允许xs:annotation
的地方尽可能多地使用xs:annotation
元素及其子元素xs:documentation
。
然后您可以使用良好的 XML 编辑器(例如 Visual Studio XML 编辑器)和 IDE 的智能感知自动创建架构实例:
显示注释(描述含义和类型)。 提示/枚举属性的可能名称和值以及元素的可能子项。对于所有这些在选择时(在按 Enter 之前),智能感知也会显示它们各自的注释。XML 编辑器还会用红色曲线标记任何错误,并且错误窗口会显示任何错误或警告消息——所有这些都是在用户输入 XML 文档时实时显示的。
最后:如果在创建注释后您仍想生成类似单独(甚至是打印)文档的内容,您可以使用 XSLT 轻松处理模式并输出可用的注释。 p>
【讨论】:
【参考方案3】:xsl:key 不适合您的原因是它只在单个文档中搜索。解决方案可能是创建一个复合文档(在 xsl:variable 中),它合并不同模式文档的内容,然后在其上使用 xsl:key。
(或者使用 Saxon-EE,它会在需要时自动创建索引,避免需要显式键。)
一般来说,使用 XSLT 操作原始模式文档是很困难的,因为在 XSD 中编写相同的东西有很多不同的方法。但是,如果您可以控制架构文档中使用的编码样式,则很有可能实现。
【讨论】:
谢谢,我最终制作了一个复合文档,但在单独的 xslt 通道中,就像一个魅力。我无法让它一次通过,xslt 处理器无法将 xsl:variable 识别为节点集。虽然分步操作更容易,而且我的样式表也很简单,但它确实感觉像是在作弊。【参考方案4】:感谢Petru Gardea 提及我们的工具 DocFlex/XML XSDDoc!
确实,使用我们的 XML 模式 doc-gen 可以将最初问题中提到的所有示例 XML 模式记录在一起。
这是我刚刚由他们生成的这样一个文档:
http://www.filigris.com/pr/***.com/questions/8369677/using-xslt-to-transform-multiple-xml-schema-documents/xsddoc/
但我不得不说提供的 XSD 列表有些不正确。如果您从字面上理解这些文本并从中创建相应的 XSD 文件,那么将没有任何效果! (要生成我需要更正的文档。)
首先,某些模式中的 XML 标记完全无效(例如,在 Application.xsd 中)。
其次,FooApplication.xsd 使用了不正确的类型引用。 它定义了元素 'FooInput' 和 'FooOutput' 对应的类型为 'FooClient' 和 'FooServer'。 这些类型在 FooClient.xsd 和 FooServer.xsd 中定义,它们包含在 FooApplication.xsd 中。没关系。 这里缺少的是这些类型是在命名空间中定义的:“http://www.example.com/foo”。但是 FooApplication.xsd 中使用它们的 XML 位置绑定到不同的命名空间——默认命名空间(即没有命名空间)。所以,声明:
<xsd:element name="FooInput" type="FooClient"/>
实际上不是指类型:
http://www.example.com/foo:FooClient
而是类型:
no namespace:FooClient
要使类型引用正确,您需要在 FooApplication.xsd 的
<xsd:schema targetNamespace="http://www.example.com/foo"
xmlns="http://www.example.com/foo"
xmlns:core="http://www.example.com/core"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
或使用绑定到“http://www.example.com/foo”的附加命名空间前缀。
因此,如果您曾经尝试使用我们的工具 DocFlex/XML XSDDoc 直接记录您的原始架构,显然您不会收到正确的文档!
(我们的 XML 模式 doc-gen 不会自动验证任何 XML 模式。它根本不能,因为首先,这不是它的工作,其次,任何模式验证都需要额外的处理时间,这可能会让大多数人感到烦恼谁确定他们的架构是正确的。毕竟,您总是可以在构建文件中添加一些额外的架构验证步骤)
最后,如果上述所有内容都与您无关——也就是说,示例模式中的所有错误都只是这个特定问题的不准确之处——那么听听为什么会很有趣我们的工具不适合您的任务(除了任何商业、财务或组织问题)。
Petru Gardea 建议我们的解决方案可能会“按比例放大”。但是,一般来说,它可能需要在什么方向上扩大规模?听到这真的很有趣!因为这正是我们自己关心的问题——如何让我们的工具文档 XML 模式变得更好。
附言 这个网站还有一个问题,也和这个话题非常相关:
How to convert xsd to human readable documentation?
我也提供了一个answer(尽管有些人可能认为这是一个有争议的问题,尤其是从主流观点来看)。不幸的是,那时我还没有这个帐户,所以我无法直接联系到它。
【讨论】:
感谢您的反馈。 DocFlex 工具看起来很有趣,但是我希望将其转换为可以在我们内部 wiki 中使用的简单格式。这个想法是负责维护应用程序的人员有一个可用的配置选项列表,包括 cmets、默认值等。简而言之,DoxFlex 的输出太复杂了。我要记录的不是架构,而是配置选项。我只是在 xsd 中指定我期望的配置选项,以便我可以有效的配置文件,并自动生成这个 wiki 文档。 附注这些模式的问题来自于我是从内存中写到这里的,实际的 xsd 文件不包含这些错误。 好的。您需要的也可以使用我们的工具来完成! XML 模式文档生成器,我们称之为“DocFlex/XML XSDDoc”,实际上只是一个模板集。整个软件是 DocFlex/XML(见filigris.com/products/docflex_xml)。它是一个在许多方面与 XSLT 工作方式相同的系统。模板相当于 XSLT 脚本。 DocFlex/XML 生成器是两个 DocFlex/XML 版本的免费软件部分,扮演 XSLT 处理器的角色。我们上面有的是模板设计器,它提供了一个 GUI 来创建/编辑模板。 它以更具交互性的可视化方式表示模板代码,尽可能模仿生成的输出。我们的模板语言不是基于 XSLT(尽管借鉴了一些想法)。这完全是我们的专有技术。这使我们能够在需要或发明时快速引入新功能。我相信,这让我们让这个系统比 XSLT 更强大(它自 2002 年以来就已经在开发中,它的重点不仅是 XML,而且还远不止于此)。当然,从负面来看,这不是来自某个古老的财团的任何一种开放标准。 相反,它目前仅由我们提供、支持和解释。但它允许我们做一些没人做的事情,这就是我们能够生存的原因。我们的客户,尽管目前还很少,已经包括坐在 Adobe、IBM 和 Microsoft 等地方的人,我相信,只要他们能在其他地方找到他们需要的东西,他们就会讨厌与这些小家伙打交道。以上是关于使用 xslt 转换多个 xml 模式文档的主要内容,如果未能解决你的问题,请参考以下文章
CSS 转换不起作用 Firefox for XML 文档使用 XSLT 转换为 HTML