使用XSLT从XML模式中删除未使用的元素

Chr*_*isC 13 xslt recursion schema

我正在寻找一种方法(如果它甚至可能)使用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>
Run Code Online (Sandbox Code Playgroud)

我想要做的是设置一个XSL,我提供起始元素(在这种情况下RootElement),它将复制所有依赖元素,但省略未使用的元素.在上面的例子中,如果我传入RootElement,我希望看到RootElementChildElement包含但UnusedElement省略.

(当我说"提供起始元素"时,我很乐意破解样式表并xsl:template match="RootElement"在必要时输入.)

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

(当然,如果它可以在任何导入的模式中执行相同的操作会更好!)

我已经广泛搜索了Google,但却找不到任何相关内容 - 我不确定这是否意味着它不可能.

谢谢!

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

Dim*_*hev 4

这种转变

<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>
Run Code Online (Sandbox Code Playgroud)

当应用于提供的 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>
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

  • 这是一项勇敢的努力,但在我看来,如果模式文档具有目标名称空间,或者它包含/导入其他模式文档,那么它就不起作用。使用 XSLT 处理完全通用的 XSD 文档很困难 - 如果您知道您只使用 XSD 语言的子集,则很有可能,但如果 XSD 的使用不受限制,则非常具有挑战性。(另请注意,元素声明可能看起来“未使用”,但仍会影响严格通配符中允许的内容 (`&lt;xs:any processContents="strict"/&gt;`) (4认同)
  • @Chris:您可能考虑的一件事是不从原始 XSD 文档开始,而是从使用 Saxon 模式处理器的 -scmout 选项生成的 SCM 文档开始。这基本上以规范的形式为您提供了“架构组件”的 XML 表示,您不必担心 xs:import/xs:include、组、本地与全局声明、名称空间前缀和XSD 模式文档的所有其他可变性。 (2认同)