合并时如何防止双元素包含xsd中的文件?

时间:2014-07-07 09:57:26

标签: xslt xslt-2.0

我正在处理一个处理某些XSD的样式表。 主XSD文件包括另外2个。其中2个还包括另一个。 所有XSD在根元素中具有相同的属性和名称空间。这些文件仅用于维护目的。

样式表:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet 
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:exa="http://www.example.com/"
  exclude-result-prefixes="xsl xs exa">

  <xsl:output method="xml" indent="yes" encoding="iso-8859-1" />

  <!-- global variable to merge schema with it's includes 
       to be used for further processing the schema -->

  <xsl:variable name="with_includes">
    <xsl:apply-templates select="/xs:schema" mode="include"/>
  </xsl:variable>

  <!-- copy the main schema root element including attributes
       then process all nodes in it -->

  <xsl:template match="xs:schema" mode="include">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates select="node()" mode="include"/>
    </xsl:copy>
  </xsl:template>

  <!-- all schemas have the same namespaces and targetnamespace defined 
       so do not copy namespaces -->

  <xsl:template match="node()" mode="include">
    <xsl:copy-of select="." copy-namespaces="no"/>
  </xsl:template>

  <!-- when matching an include, process all the nodes in the schema -->

  <xsl:template match="xs:include" mode="include">
    <xsl:apply-templates select="doc(@schemaLocation)/xs:schema/node()" mode="include"/>
  </xsl:template>

  <!-- only here to show the result -->

  <xsl:template match="/xs:schema">
    <xsl:copy-of select="$with_includes"/>
  </xsl:template>

</xsl:stylesheet>

一些非常基本的示例模式来演示这个问题:

Schema A.xsd:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema 
  attributeFormDefault="unqualified"
  elementFormDefault="qualified"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://www.example.com/example"
  xmlns:exa="http://www.example.com/example">

  <xs:include schemaLocation="B.xsd"/>
  <xs:include schemaLocation="C.xsd"/>

  <xs:element name="a" type="exa:t_a"/>

  <xs:complexType name="t_a">
    <xs:sequence>
      <xs:element name="b" type="exa:t_b"/>
      <xs:element name="c" type="exa:t_c"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>

Schema B.xsd:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema 
  attributeFormDefault="unqualified"
  elementFormDefault="qualified"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://www.example.com/example"
  xmlns:exa="http://www.example.com/example">

  <xs:include schemaLocation="C.xsd"/>

  <xs:complexType name="t_b">
    <xs:sequence>
      <xs:element name="c1" type="exa:t_c"/>
      <xs:element name="c2" type="exa:t_c"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>

架构C.xsd

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema 
  attributeFormDefault="unqualified"
  elementFormDefault="qualified"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://www.example.com/example"
  xmlns:exa="http://www.example.com/example">

  <xs:simpleType name="t_c">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="20"/>
    </xs:restriction>
  </xs:simpleType>

</xs:schema>

如果我使用上面的样式表,我会在结果中得到simpleType t_c两次。我正在寻找一种方法来防止这种情况。

是的,我使用撒克逊人。

1 个答案:

答案 0 :(得分:4)

对包含进行重复数据删除相对简单,但如果您需要处理周期则会变得更加复杂 - 在XSD中允许使用xs:includes的循环,尽管1.0规范并不完全清楚。如果您不关心周期,只需使用递归函数通过传递扩展构建所有包含的列表,最好调用resolve-uri()以针对其基URI解析每个@schemaLocation,然后从列表中删除重复项使用distinct-values()。如果需要消除循环,则需要将参数传递给递归函数,指示到达文档的路径,如果文档已经在列表中,则忽略该文档。如果您有我的书的副本,那么在xsl:call-template的部分中有一个循环检测示例。但你也可能觉得这本书太贵了; - (