【问题标题】:Remove unused elements from XML schema using XSLT使用 XSLT 从 XML 模式中删除未使用的元素
【发布时间】:2011-04-13 21:46:23
【问题描述】:

我正在寻找一种方法(如果可能的话)使用 XSD 文档的 XSL 转换来删除未使用的元素。这在我的工作中经常出现,公司会定义一个包含绝对所有内容的 XSD,但随后他们会希望为其中的单个根元素创建一个缩减版本。

为了进一步解释,我可能有一个如下所示的 XSD:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:element name="RootElement">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="ChildElement"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="ChildElement"/>
    <xs:element name="UnusedElement"/>
</xs:schema>

我希望能够设置一个 XSL,在其中提供起始元素(在本例中为 RootElement),它将复制所有相关元素但忽略未使用的元素。在上面的示例中,如果我传入 RootElement,我希望看到 RootElementChildElement 包含但 UnusedElement 省略。

(当我说“提供起始元素”时,我很高兴打开样式表并在需要的地方输入xsl:template match="RootElement"。)

这显然必须是递归的,因此将导航定义在起始元素下方的整个结构,并且该架构中未使用的任何元素都将被丢弃。

(当然,如果它可以在任何导入的模式中做同样的事情会更好!)

我在 Google 上进行了广泛的搜索,但在这方面找不到任何东西 - 我不确定这是否意味着不可能。

谢谢!

编辑:实际上我可能应该澄清并说我想删除未使用的元素和类型,因此它将遵循ref="childElement"type="someType" 链接。

【问题讨论】:

  • 好问题,+1。请参阅我的答案以获得完整的解决方案。
  • 谢谢迪米特。您的解决方案很接近(请参阅下面的我的 cmets),但它仍然存在一些问题(条带类型定义,不跨越导入的模式)。可能我的示例 XML 被过度简化了。对于声明性语言,这实际上可能不是一个可解决的问题,或者至少不值得努力告诉 XSLT 如何 去做。但是,除非在接下来的一两天内出现意外情况,否则我会将您的回复标记为(最接近的)答案。谢谢!

标签: xslt recursion schema


【解决方案1】:

这种转变

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

 <xsl:param name="ptopElementName" select="'RootElement'"/>

 <xsl:variable name="vTop" select=
 "/*/xs:element[@name=$ptopElementName]"/>

 <xsl:variable name="vNames"
      select="$vTop/descendant-or-self::*/@name"/>

 <xsl:variable name="vRefs"
      select="$vTop/descendant-or-self::*/@ref"/>

 <xsl:variable name="vTypes"
      select="$vTop/descendant-or-self::*/@type"/>

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

 <xsl:template match="xs:element">
  <xsl:if test=
    "@name=$vNames
    or
     @name=$vRefs
    or
     ancestor-or-self::*[@name=$ptopElementName]">
   <xsl:call-template name="identity"/>
  </xsl:if>
 </xsl:template>

 <xsl:template match="xs:complexType|xs:simpleType">
  <xsl:if test=
   "@name=$vTypes
    or
     ancestor-or-self::*[@name=$ptopElementName]">
   <xsl:call-template name="identity"/>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:element name="RootElement">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="ChildElement"/>
            </xs:sequence>
        </xs:complexType></xs:element>
    <xs:element name="ChildElement"/>
    <xs:element name="UnusedElement"/>
</xs:schema>

产生想要的、正确的结果:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
   <xs:element name="RootElement">
      <xs:complexType>
         <xs:sequence>
            <xs:element ref="ChildElement"/>
         </xs:sequence>
      </xs:complexType>
   </xs:element>
   <xs:element name="ChildElement"/>
</xs:schema>

【讨论】:

  • 一项勇敢的努力,但在我看来,如果模式文档具有目标命名空间,或者如果它包含/导入其他模式文档,它就好像不起作用。使用 XSLT 完全通用地处理 XSD 文档是很困难的 - 如果您知道您只使用 XSD 语言的一个子集,这很有可能,但如果 XSD 的使用不受限制,则非常具有挑战性。 (另外,请注意,元素声明可能看起来“未使用”,但仍会影响严格通配符中允许的内容 (&lt;xs:any processContents="strict"/&gt;)
  • @Michael-Kay:是的,我完全意识到这个解决方案非常受限于 OP 的规定要求。我需要好好更新我生疏的 XSD 知识,才能声称该解决方案甚至涵盖了所有主要情况。此外,在我看来,引用名称和类型是可传递的,因此需要在许多步骤中完成以构建“引用/引用”关系的传递闭包——当然,这里没有这样做。即使是赏金也会有很多工作。
  • 感谢 Dimitre,这当然是一个非常酷的解决方案(而且响应速度很快)。不幸的是,Michael 关于目标命名空间的事情是正确的——我的示例是一个非常简化的版本,而我的实际模式中包含目标命名空间。有趣的是,它还删除了 XML 声明和所有类型定义(不确定类型删除是否是由于同一件事)。
  • Michael,谢天谢地,我们只使用 XSD 规范的一个相当简单的子集,基本上只是元素、元素引用和复杂类型/简单类型扩展其他类型。我不相信架构的任何可扩展部分使用 xs:any 或任何东西。我不确定任何简单的解决方案都可以帮助解决这个问题......!我们的另一个大问题是使用导入将模式拆分为多个文件。 “清理”它们是一个更大的问题!我可能不得不求助于代码,例如Java...?
  • @Chris:您可能会考虑的一件事是不要从原始 XSD 文档开始,而是从使用 Saxon 模式处理器的 -scmout 选项生成的 SCM 文档开始。这基本上为您提供了规范形式的“模式组件”的 XML 表示,您不必担心 xs:import/xs:include、组、本地与全局声明、命名空间前缀和XSD 模式文档的所有其他可变性。
猜你喜欢
  • 2016-06-13
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 2018-05-12
  • 2019-11-17
  • 2010-09-24
  • 2015-11-16
  • 1970-01-01
相关资源
最近更新 更多