排序 XML 模式而不重新排序命名元素的子元素

Sort XML Schema without reordering children of named element

我们从模型生成 XML 模式,但我们发现这会导致 XML 模式随时间重新排序。这不是我们可以轻易控制的事情,因此我们打算对生成的 XML 模式应用 XSLT 转换,以便为它们提供更稳定的顺序。

为实现这一点,我们考虑先根据元素名称对元素重新排序,然后是属性(name 理想情况下优先于其他属性)。

即按

排序
  1. <element>(元素名称)
  2. <element name="xyz">(属性'name')
  3. <element *="*">(所有其他属性)

然而,有一组元素我们无法对其子元素重新排序,即 <xs:sequence>,因为它们具有严格的顺序。

下面是一个不能更改顺序的示例定义。

  <xs:complexType name="OBJECT.OtherSystemClaimsXref">
    <xs:sequence>
      <xs:group ref="FIELDS.OtherSystemClaimsXref"/>
      <xs:group ref="FIELDS.ExternallyMaintained"/>
      <xs:group ref="FIELDS.DtoSupplier"/>
      <xs:group ref="FIELDS.BusinessObject"/>
      <xs:group ref="FIELDS.OtherSystemXrefAbstract"/>
    </xs:sequence>
    <xs:attribute name="externalSystemReference" type="TYPE.OpenTwinsExternalReference" use="required"/>
    <xs:attribute name="dataChangedEnum" type="ENUM.DataChangedEnum" use="optional"/>
    <xs:attribute name="importable" type="xs:boolean" use="optional"/>
  </xs:complexType>

我想出了下面的 XSLT 作为起点。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" omit-xml-declaration="no" />
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:apply-templates select="node()">
                <xsl:sort select="name()" />
                <xsl:sort select="@*" order="ascending" data-type="text" />
                <xsl:sort select="." />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:strip-space elements="*" />
</xsl:stylesheet>

我试图通过阻止 <xs:sequence> 的排序来改变行为,但这没有用。

        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:apply-templates select="*[not(local-name()='sequence')]">
                <xsl:sort select="name()" />
                <xsl:sort select="@*" order="ascending" data-type="text" />
                <xsl:sort select="." />
            </xsl:apply-templates>
            <xsl:apply-templates select="*[local-name()='sequence']"/>
        </xsl:copy>

除了 <xs:sequence> 的直系子代之外,我如何将这些规则应用于所有对象?

非常感谢。

如果您不希望 xsl:sequence 的子项被排序,您应该为此添加一个优先于通用模板的特定模板。

<xsl:template match="xs:sequence">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>

这将要求您在样式表中声明 xs 命名空间前缀。

试试这个 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output indent="yes" omit-xml-declaration="no" />

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

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:apply-templates select="node()">
                <xsl:sort select="name()" />
                <xsl:sort select="@*" order="ascending" data-type="text" />
                <xsl:sort select="." />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="xs:sequence">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>