XSLT 2.0:处理嵌套的XSD

时间:2011-03-28 19:47:54

标签: xslt import xsd nested

我需要将一些(未指定的)嵌套导入的XSD收集到一个临时树变量中。转换从schema_1.xsd开始,后者又导入其他几个XSD。

像这样:schema_1.xsd的内容:

<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema.xsd">
  <import namespace="http://www.someplace.com" schemaLocation="schema_2.xsd"/>
  <import namespace="http://www.someplace.com" schemaLocation="schema_3.xsd"/>
  <element name="TopElement1">
    <complexType>
      <sequence>
        <element name="ChildElement1"/>
        <element name="ChildElement2"/>
        <element name="ChildElement3"/>
      </sequence>
    </complexType>
  </element>
</schema>

和schema_2.xsd的内容:

<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema.xsd">
  <import namespace="http://www.someplace.com" schemaLocation="schema_3.xsd"/>
  <import namespace="http://www.someplace.com" schemaLocation="schema_4.xsd"/>
  <element name="TopElement2">
    <complexType>
      <sequence>
        <element name="ChildElement4" minOccurs="0"/>
        <element name="ChildElement5"/>
      </sequence>
    </complexType>
  </element>
</schema>

依此类推(我想包括第三个XSD有点多余?)。

我需要做的是构建一个包含所有嵌套XSD中所有节点的整个临时树,包括第一个XSD的内容,即schema_1.xsd。从XSD可以看出,一些导入可能会发生两次。优选地,任何模式应该仅被复制到期望的变量一次。更糟糕的是,我知道可能存在循环引用,这显然会对解决方案空间产生进一步的限制。

我需要在XSLT中的变量中访问生成的临时树。也许是这样:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:variable name="root">
    <!-- magic -->
  </xsl:variable>
  <xsl:template match="/">
    <!-- processing $root/fullStructure --> 
  </xsl:template>
</xsl:stylesheet>

$ root的实际内容我想看起来像这样:

<fullStructure>
  <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema.xsd">
    <import namespace="http://www.someplace.com" schemaLocation="schema_2.xsd"/>
    <import namespace="http://www.someplace.com" schemaLocation="schema_3.xsd"/>
    <element name="TopElement1">
      <complexType>
        <sequence>
          <element name="ChildElement1"/>
          <element name="ChildElement2"/>
          <element name="ChildElement3"/>
        </sequence>
      </complexType>
    </element>
  </schema>
  <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema.xsd">
    <import namespace="http://www.someplace.com" schemaLocation="schema_3.xsd"/>
    <import namespace="http://www.someplace.com" schemaLocation="schema_4.xsd"/>
    <element name="TopElement2">
      <complexType>
        <sequence>
          <element name="ChildElement4" minOccurs="0"/>
          <element name="ChildElement5"/>
        </sequence>
      </complexType>
    </element>
  </schema>
  <!-- copy-of for schema_3.xsd and schema_4.xsd is omitted for the sake of brevity. -->
</fullStructure>

此树的大小仅受导入数量和可用计算资源的限制。当然,导入节点不再是必需的,但是,它们也没有问题,所以盲目复制完全没问题。

重大更新

根据Dimitre Novatchev的要求,我已经包含了几个有效的XSD,以及对所需结果的描述。另外,我删除了一些多余的评论。由于LarsH的反馈,我也做了一些小的更新。

有人可以给我指向正确的方向吗?万分感谢!

1 个答案:

答案 0 :(得分:2)

此样式表:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:local="http://localhost"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 exclude-result-prefixes="local xs">
    <xsl:template match="/">
        <fullStructure>
            <xsl:copy-of select="local:explode(.)"/>
        </fullStructure>
    </xsl:template>
    <xsl:function name="local:explode" as="node()*">
        <xsl:param name="pNodes" as="node()*"/>
        <xsl:sequence select="local:explode($pNodes/root(.),())"/>
    </xsl:function>
    <xsl:function name="local:explode" as="node()*">
        <xsl:param name="pTodo" as="node()*"/>
        <xsl:param name="pDone" as="node()*"/>
        <xsl:sequence
             select="if (empty($pTodo))
                     then $pDone
                     else local:explode(
                             document(
                                ($pTodo except $pDone)
                                   /xs:schema/xs:import/@schemaLocation
                             ),
                             $pTodo | $pDone
                          )"/>
    </xsl:function>
</xsl:stylesheet>

使用此输入:

<schema xmlns="http://www.w3.org/2001/XMLSchema"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema.xsd">
    <import namespace="http://www.someplace.com"
            schemaLocation="schema2.xsd"/>
    <element name="TopElement1">
        <complexType>
            <sequence>
                <element name="ChildElement1"/>
                <element name="ChildElement2"/>
                <element name="ChildElement3"/>
            </sequence>
        </complexType>
    </element>
</schema>

这个schema2.xsd文件:

<schema xmlns="http://www.w3.org/2001/XMLSchema"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema.xsd">
    <element name="TopElement2">
        <complexType>
            <sequence>
                <element name="ChildElement4" minOccurs="0"/>
                <element name="ChildElement5"/>
            </sequence>
        </complexType>
    </element>
</schema>

输出:

<fullStructure>
    <schema xmlns="http://www.w3.org/2001/XMLSchema"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema.xsd">
        <import namespace="http://www.someplace.com"
                schemaLocation="schema2.xsd"/>
        <element name="TopElement1">
            <complexType>
                <sequence>
                    <element name="ChildElement1"/>
                    <element name="ChildElement2"/>
                    <element name="ChildElement3"/>
                </sequence>
            </complexType>
        </element>
    </schema>
    <schema xmlns="http://www.w3.org/2001/XMLSchema"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema.xsd">
        <element name="TopElement2">
            <complexType>
                <sequence>
                    <element name="ChildElement4" minOccurs="0"/>
                    <element name="ChildElement5"/>
                </sequence>
            </complexType>
        </element>
    </schema>
</fullStructure>