【问题标题】:Removing superfluous complex types in XML Schema using XSLT使用 XSLT 删除 XML Schema 中多余的复杂类型
【发布时间】:2014-12-31 22:13:30
【问题描述】:

我收到了一组包含“多余”复杂类型的 XML 模式,我正在寻找一种使用 XSLT 删除它们的方法。

模式(见下文)有许多 <xsd:element name="ElementX" type="ComplexTypeX"> 标记,每个标记都引用一个复杂类型。每个复杂类型都继承自另一个模式 (Datatypes.xsd) 中的基类型,但是没有扩展或限制类型 - 因此毫无意义!

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema targetNamespace="..." xmlns:xsd="..." xmlns="...">
  <xsd:include schemaLocation="Datatypes.xsd" />

  <xsd:complexType name="ComplexType1">
    <xsd:simpleContent>
      <xsd:extension base="ActualType1" />
    </xsd:simpleContent>
  </xsd:complexType>
  <xsd:element name="ElementName1" type="ComplexType1" />

  <xsd:complexType name="ComplexType2">
    <xsd:simpleContent>
      <xsd:extension base="ActualType2" />
    </xsd:simpleContent>
  </xsd:complexType>
  <xsd:element name="ElementName2" type="ComplexType2" />

  ...
 </xsd:schema>

我正在尝试(但不是很远......)将 XSLT 转换写入:

  • 将每个元素的类型替换为对应的复杂类型的基类型。例如。上面 ElementName1 的类型将变为 ActualType1。

  • 从输出中删除整个 complexType。

生产输出:

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema targetNamespace="..." xmlns:xsd="..." xmlns="...">
  <xsd:include schemaLocation="Datatypes.xsd" />

  <xsd:element name="ElementName1" type="ActualType1" />

  <xsd:element name="ElementName2" type="ActualType2" />
  .
  .
  .
 </xsd:schema>

目前,所有 complexType 元素都不会以任何方式更改基本类型,因此执行替换是安全的。但是,如果将来某些 complexType 元素被更改以限制或扩展它们的基本类型(并且具有有意义的用途),我只想执行剩余多余类型的替换/删除。虽然我意识到这会在一定程度上增加 XSLT 的复杂性。

背景:这些模式来自第三方,不幸的是我无法控制它们的生产。我怀疑由于用于生成模式的工具而存在额外的复杂类型层。

谢谢!

【问题讨论】:

    标签: xslt xsd


    【解决方案1】:

    我正在尝试(但不是很远......)编写一个 XSLT 转换 到:

    • 将每个元素的类型替换为对应的复杂类型的基类型。例如。上面 ElementName1 的类型将变为 实际类型 1。

    • 从输出中删除整个 complexType。

    这两个可以通过:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:key name="complex" match="xsd:complexType" use="@name" />
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- replace element type -->
    <xsl:template match="xsd:element">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:attribute name="type">
                <xsl:value-of select="key('complex', @type)/xsd:simpleContent/xsd:extension/@base"/>
            </xsl:attribute>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- remove complexType -->
    <xsl:template match="xsd:complexType"/>
    
    </xsl:stylesheet>
    

    这部分恐怕我没看懂:

    但是,在这种情况下,一些 complexType 元素被更改为 限制或扩展它们的基本类型(并有一些有意义的用途),我 想在执行之前添加一个检查 更换/移除。

    【讨论】:

    • 我已经修改了我的问题的第二部分 - 我想知道是否有可能在 XSLT 中检测 complexType 是否是“多余的”,然后只执行替换/删除。如果 complexType 仅包含一个 simpleContent 元素,而该元素又包含一个指定基本属性的扩展元素,则可以将其定义为多余的;不得有其他子元素或属性。虽然我意识到这会增加一些复杂性!非常感谢您在上面的回答。
    • @jonnyr 我建议您扩展您的示例(输入和输出)以显示所有可能的组合。
    【解决方案2】:

    你似乎想要这样的东西:

    <?xml version="1.0" ?>
    <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    
      <!-- anything not otherwise matched gets copied -->
    
      <xsl:template match="@*|node()">
        <xsl:apply-templates select="." mode="literal"/>
      </xsl:template>
    
      <xsl:template match="@*|node()" mode="attribute-filter">
        <xsl:apply-templates select="." mode="literal"/>
      </xsl:template>
    
      <xsl:template match="@*|node()" mode="literal">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <!-- in mode 'attribute-filter', 'name' and 'type' attributes transform to nothing -->
      <xsl:template match="@name|@type" mode="attribute-filter">
        <!-- transforms to nothing -->
      </xsl:template>
    
      <!-- keep only meaningful extension types -->
      <xsl:template match="/xsd:schema/xsd:complexType[./xsd:simpleContent/xsd:extension]">
        <xsl:if test="boolean(./xsd:simpleContent/xsd:extension/node())">
          <!-- a bona fide extension -->
          <xsl:apply-templates select="." mode="literal"/>
        </xsl:if>
        <!-- else it transforms to nothing -->
      </xsl:template>
    
      <!-- patch up element declarations where necessary -->
      <xsl:template match="xsd:element[@type]">
        <xsl:variable name="typename" select="@type" />
        <xsl:choose>
          <xsl:when test="not(/xsd:schema/xsd:complexType[@name = $typename]/xsd:simpleContent)">
            <xsl:apply-templates select="." mode="literal"/>
          </xsl:when>
          <xsl:when test="boolean(/xsd:schema/xsd:complexType[@name = $typename]/xsd:simpleContent/xsd:restriction)">
            <xsl:apply-templates select="." mode="literal"/>
          </xsl:when>
          <xsl:when test="boolean(/xsd:schema/xsd:complexType[@name = $typename]/xsd:simpleContent/xsd:extension/node())">
            <xsl:apply-templates select="." mode="literal"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:element name="xsd:element">
              <xsl:copy-of select="@name" />
              <xsl:attribute name="type">
                <xsl:value-of select="/xsd:schema/xsd:complexType[@name = $typename]/xsd:simpleContent/xsd:extension/@base"/>
              </xsl:attribute>
              <xsl:apply-templates select="@*|node()" mode="attribute-filter"/>
            </xsl:element>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:template>
    
    </xsl:stylesheet>
    

    假设不需要的 complexType 声明都使用简单内容的“扩展”替代方案,如示例中所示,但它也可以扩展为也处理其他不需要的类型。

    【讨论】:

    • 与声明相反,这是一个 XSLT 2.0 样式表。我也对结果感到困惑,因为元素类型保持不变。
    • @michael.hor257k 我更新了 XSL 版本,谢谢。不过,我不确定您所说的元素类型保持不变是什么意思。有些会,有些不会,这取决于引用的类型是否是微不足道的派生。 (更具体地说,取决于引用的类型是否具有简单的内容并且是其基本类型的微不足道的扩展。)这是 jonnyr 要求的,尽管他可能想要调整哪些类型被剥离的标准。
    • 我认为给定的示例应该产生给定的输出 - 但我很容易错了,因为我已经忘记了 OP 想要什么。
    • @michael.hor257k 我声称我提供的样式表会将问题中给出的输入转换为问题中指定的形式。我仍然不明白你为什么不这么认为。此样式表还将避免剥离非平凡的派生类型,这也是要求的(作为未来考虑)。
    • 你的输出是&lt;xsd:element name="ElementName1" type="ComplexType1"/&gt;。我认为输出应该是&lt;xsd:element name="ElementName1" type="ActualType1" /&gt;。我很确定在 OP 修改他的问题之前 的预期输出。正如我所说,我不确定他现在想要什么,因为他没有回应我的澄清请求。
    猜你喜欢
    • 1970-01-01
    • 2013-01-17
    • 2021-08-24
    • 1970-01-01
    • 2015-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多