XSD循环导入

时间:2013-02-12 16:35:49

标签: java xsd xsom

我需要使用XSOM解析XSD,但此XSD包含循环导入。

A.xsd

<xs:schema xmlns=”ns1” targetNamespace=”ns1”>
  <xs:import namespace=”ns2” schemaLocation=”B.xsd”/>
  <xs:element name=”MyElement” type=”xs:string”/>
</xs:schema>

B.xsd

<xs:schema xmlns=”ns2” targetNamespace=”ns2” xmlns:ns1=”ns1”>
  <xs:import namespace=”ns1” schemaLocation=”A.xsd”/>
  <xs:complexType name="MyComplex">
    <xs:sequence>
      <xs:element ref="ns1:MyElement" minOccurs="0"/>
    <xs:sequence>
  <xs:complexType>
</xs:schema>

XSOM无法解析模式,因为它会检测由于循环导入而已定义的元素。所以我试图通过外化由A定义并在B中使用的元素来打破循环导入。

C.xsd包含A使用的元素B.请注意,这些元素未在A中使用。不要问我为什么在A中定义了这些元素。

<xs:schema xmlns=”ns1” targetNamespace=”ns1”>
  <xs:element name=”MyElement” type=”xs:string”/>
</xs:schema>

A.xsd成为

<xs:schema xmlns=”ns1” targetNamespace=”ns1”>
  <xs:import namespace=”ns2” schemaLocation=”B.xsd”/>
</xs:schema>

B.xsd(导入C.xsd而不是A.xsd)变为

<xs:schema xmlns=”ns2” targetNamespace=”ns2” xmlns:ns1=”ns1”>
  <xs:import namespace=”ns1” schemaLocation=”C.xsd”/>
  <xs:complexType name="MyComplex">
    <xs:sequence>
      <xs:element ref="ns1:MyElement" minOccurs="0"/>
    <xs:sequence>
  <xs:complexType>
</xs:schema>

XSOM可以解析XSD。但现在我无法使用以下代码创建架构:

SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
sf.setResourceResolver(new MyResourceResolver());

我使用与JDK 1.7捆绑在一起的标准实现。我得到了例外:

src-resolve: Cannot resolve the name 'ns1:MyElement' to a(n) 'element declaration' component.

问题是资源解析器是为B命名空间调用的,而不是为有意义的A命名空间调用的。由于命名空间A由A.xsd和C.xsd共享,因此资源解析器无法找到C.xsd中定义的元素。

循环进口是否有效?是否可以打破循环导入,以便XSOM解析然后由SchemaFactory加载?

1 个答案:

答案 0 :(得分:6)

关于一般性问题:

你问“圆形进口是否有效?”如果通过循环,则表示存在一系列模式文档S [1],S [2],...,S [n],其中模式文档S [1]按名称引用模式文档S [2],S [2]到S [3],...... S [n-1]到S [n],S [n]到S [1]那么我不相信XSD 1.0规范或XSD 1.1说清楚这样或那样的。 (一些工作组成员试图说服工作组提高其对此及相关主题的思路清晰度,但失败了。)有些实现支持循环导入(和其他形式的循环),但我不认为有可能争论从规范中你的实现做错了什么。

另一方面,如果仅表示存在循环,使得对于0 <= i <= n-1,S [i]导入S [i + 1]和S [n]的名称空间导入S [1]的命名空间,然后我相信这样的循环显然是合法的(在某些情况下是不可避免的)。

我建议的解决方法是:

  1. 在任何声明任何内容的模式文档中,根据需要使用xs:import,但不要在导入时指定模式位置。这些参考文献中的循环是无害的。
  2. 调用模式处理器时,请为其提供您希望其读取的所有模式文档的完整列表,如果可能,请通过选项或配置告诉它不要读取任何其他模式文档。
  3. 如果您的架构文档在验证时不接受多个架构文档作为输入,那么您必须有一个架构文档引用您想要读取的所有内容,或者如果您不相信自己获取列表在调用时直接使用模式文档,然后添加顶级驱动程序文档,该文档除了包含和导入您要读取的其他模式文档外,不会执行任何操作,具有特定的模式位置信息。
  4. 在您的情况下,这意味着从(原始形式)A.xsd和B.xsd中删除xs:import / @ schemaLocation属性,并添加表单

    的驱动程序文档
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:import namespace="ns1" schemaLocation="A.xsd"/>
      <xs:import namespace="ns2" schemaLocation="B.xsd"/>
    </xs:schema>
    

    效果是确保模式文档中对其他模式文档的引用永远不会出现循环;这消除了一大类XSD实现彼此不一致的情况(在某些情况下它们本身 - 当调用以不同的顺序命名输入时,有时相同的处理器在相同的输入上产生截然不同的结果)。 / p>

    关于具体问题:

    在您的示例中,不要求A.xsd或C.xsd导入ns2,因为它们都不包含对命名空间ns2中的任何组件的任何引用。所以你的例子中的循环似乎没有用。

    在第二个示例中,您提供了一些未能成功加载架构的代码。但我在该代码中没有看到任何特定模式文档的引用;除非有相关内容你没有向我们展示,否则验证者无法找到{ns1} MyElement的声明。