gpt4 book ai didi

xslt - XSLT : How to reorder entries according to the dependencies 的 XSD 转换

转载 作者:行者123 更新时间:2023-12-05 06:41:52 25 4
gpt4 key购买 nike

我正在尝试使用 XSLT 将 XSD 方案(转换为 C++ 类)。我目前遇到的问题是我想根据依赖项对 complexType 条目重新排序。 IE。如果 complexType Type1 包含 complexType Type2 的属性,我希望 Type2 在输出中出现在 Type1 之前(出于显而易见的原因 - 在 C++ header 中,如果 Type2 在 Type1 之后定义,则 Type2 不能用于声明 Type1 中的属性)。

示例输入 XSD 文件:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Type1">
<xs:sequence>
<xs:element name="id" type="xs:short" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Type2">
<xs:sequence>
<xs:element name="id" type="xs:short" />
<xs:element name="value" type="Type3" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Type3">
<xs:sequence>
<xs:element name="id" type="xs:short" />
<xs:element name="value" type="Type4" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Type4">
<xs:sequence>
<xs:element name="id" type="xs:short" />
</xs:sequence>
</xs:complexType>
</xs:schema>

到目前为止我管理的是这个 XSLT(这是一个简化的例子,只是生成类型名称排序,而不是实际的类):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text" encoding="utf-8" indent="no"/>

<xsl:strip-space elements="*"/>

<xsl:template name="gen-type-list">
<xsl:param name="name"/>
<xsl:value-of select="concat('[', $name, ']')"/>
</xsl:template>

<!--
Generate the type order according to dependencies

Dependency should come before the dependent type.
-->
<xsl:template name="gen-type-order">
<xsl:param name="name"/>
<xsl:param name="typeList"/>
<xsl:for-each select="xs:attribute | xs:complexContent/xs:extension//xs:attribute | xs:sequence/xs:element | xs:complexContent/xs:extension/xs:sequence/xs:element">
<xsl:variable name="typeEntry">
<xsl:value-of select="concat('[', @type, ']')"/>
</xsl:variable>
<xsl:if test="contains($typeList, $typeEntry)">
<xsl:value-of select="$typeEntry"/>
</xsl:if>
</xsl:for-each>
<xsl:value-of select="concat('[', $name, ']')"/>
</xsl:template>

<!--
Print the ordered listing (line by line)
-->
<xsl:template name="print-type-order">
<xsl:param name="typeList"/>
<xsl:choose>
<xsl:when test="not(contains($typeList, ']['))">
<xsl:value-of select="substring-after(substring-before($typeList, ']'), '[')"/>
<xsl:text>&#x0a;</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-after(substring-before($typeList, ']'), '[')"/>
<xsl:text>&#x0a;</xsl:text>
<xsl:call-template name="print-type-order">
<xsl:with-param name="typeList" select="substring-after($typeList, ']')"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<!--
The main processing template handling the entire document
-->
<xsl:template match="/xs:schema">
<xsl:variable name="typeList">
<xsl:for-each select="xs:complexType">
<xsl:call-template name="gen-type-list">
<xsl:with-param name="name" select="@name"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="$typeList"/>
<xsl:text>&#x0a;</xsl:text>
<xsl:variable name="typeOrder">
<xsl:for-each select="xs:complexType">
<xsl:call-template name="gen-type-order">
<xsl:with-param name="name" select="@name"/>
<xsl:with-param name="typeList" select="$typeList"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:call-template name="print-type-order">
<xsl:with-param name="typeList" select="$typeOrder"/>
</xsl:call-template>
</xsl:template>

</xsl:stylesheet>

在示例 XSD 上运行的输出如下:

[Type1][Type2][Type3][Type4]
Type1
Type3
Type2
Type4
Type3
Type4

第一行只是所有类型的简单列表(用于调试目的,用于实际检查类型是否为 gen-type-order 模板中的复杂类型)。这已经很接近我想要的了,应该是:

Type1
Type4
Type3
Type2

我挣扎的是:

  1. 如何检查类型是否已经在列表中(不重复 Type3,因为它已经被添加为类型 2 的依赖项)
  2. 如何递归调用它(以便在 Type3 之前添加依赖项 Type4)
  3. 是否可以在不初始创建 complexType 列表 (gen-type-list) 的情况下执行此操作,即直接检查类型名称是否为 complexType? (我最初尝试使用类似 <xsl:if test="//xs:complexType[name = @type]" 的东西,但那没有用)
  4. 是否有更好/更简洁的方法来做到这一点? (即根据依赖关系以正确的顺序处理项目)

事实上,最简单的方法是重新排序 XSD 本身,不幸的是,XSD 不在我的控制之下,因此很难管理它。

注意:我知道有一些工具可以将 XSD 转换为 C++,例如 Code Synthesis xsdcxx,但我更喜欢使用 XSLT,因为大多数工具都依赖于其他库,例如 Xerces,而我不需要这些库也不想要(除了工具本身的许可问题)。并且在未来我想使用类似的 XSLT 来转换为不同的输出类型(例如 Thrift 消息文件)。

//编辑

我刚刚通过使用以下方法解决了第 3) 点:

<xsl:template name="gen-type-order">
<xsl:param name="name"/>
<xsl:for-each select="xs:attribute | xs:complexContent/xs:extension//xs:attribute | xs:sequence/xs:element | xs:complexContent/xs:extension/xs:sequence/xs:element">
<xsl:variable name="typeEntry">
<xsl:value-of select="concat('[', @type, ']')"/>
</xsl:variable>
<xsl:variable name="typeName">
<xsl:value-of select="@type"/>
</xsl:variable>
<xsl:if test="//xs:complexType[@name = $typeName]">
<xsl:value-of select="$typeEntry"/>
</xsl:if>
</xsl:for-each>
<xsl:value-of select="concat('[', $name, ']')"/>
</xsl:template>

但其他点仍然存在。

最佳答案

在 XSLT 2.0 中,以正确的顺序排列事物并不难。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text" encoding="utf-8" indent="no"/>

<xsl:strip-space elements="*"/>

<xsl:key name="type" match="xs:complexType" use="@name"/>


<!-- Returns value 1 if there are no dependencies, 2 if there's 1 etc. -->
<xsl:template match="*" mode="get-dependency-depth">
<xsl:param name="depthSummands" as="xs:integer*">
<xsl:apply-templates mode="get-dependency-depth"
select="key('type', (
xs:attribute | xs:complexContent/xs:extension//xs:attribute |
xs:sequence/xs:element | xs:complexContent/xs:extension/xs:sequence/xs:element
)/@type)"/>
</xsl:param>
<xsl:copy-of select="sum($depthSummands) + 1"/>
</xsl:template>


<xsl:template match="*" mode="process-types">
<xsl:value-of select="concat(@name, ' (dependency depth: ')"/>
<xsl:apply-templates mode="get-dependency-depth" select="."/>
<xsl:value-of select="')&#10;'"/>
</xsl:template>


<xsl:template match="/xs:schema">
<xsl:apply-templates select="xs:complexType" mode="process-types">
<xsl:sort data-type="number">
<xsl:apply-templates mode="get-dependency-depth" select="."/>
</xsl:sort>
</xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>

应用于输入 XML 时的输出:

Type1 (dependency depth: 1)
Type4 (dependency depth: 1)
Type3 (dependency depth: 2)
Type2 (dependency depth: 3)

这既不会测试循环依赖,也不会对大型依赖树特别有效 - 对于那些有依赖深度缓存之类的东西会很有用。

关于xslt - XSLT : How to reorder entries according to the dependencies 的 XSD 转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39141991/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com