对XML模式进行排序,而无需重新排序已命名元素的子元素

时间:2019-07-03 10:01:34

标签: xml xslt xsd

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

为实现这一点,我们考虑了根据元素名称对元素进行重新排序,然后使用属性(name优先于其他属性)。

即排序

  1. <element>(元素名称)
  2. <element name="xyz">(属性“名称”)
  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>的直系子孙以外的所有事物?

非常感谢。

1 个答案:

答案 0 :(得分:1)

如果您不希望订购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>