【问题标题】:XSD circular importXSD 循环导入
【发布时间】:2013-02-13 03:41:46
【问题描述】:

我需要使用 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 包含 B 使用的来自 A 的元素。注意这些元素在 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 加载?

【问题讨论】:

    标签: java xsd xsom


    【解决方案1】:

    关于一般问题:

    您问“循环导入是否有效?”如果循环性是指存在模式文档链 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 说清楚一种或另一种方式。 (一些 WG 成员试图说服 WG 提高其对此和相关主题的思考的清晰度,但失败了。)一些实现支持循环导入(和其他形式的循环),但我认为不可能争论从规范来看,您的实现做错了什么。

    另一方面,如果您的意思仅仅是存在一个循环,使得对于 0

    我推荐的解决方法是:

    1. 在任何声明任何内容的架构文档中,根据需要使用 xs:import,但不要在导入时指定架构位置。此类引用中的循环是无害的。
    2. 在调用架构处理器时,向其提供您希望它读取的所有架构文档的完整列表,并尽可能通过选项或配置告诉它不要读取任何其他架构文档。
    3. 如果您的架构文档在验证时不接受多个架构文档作为输入,那么您必须有一个架构文档来引用您想要阅读的所有内容,或者如果您不相信自己会获得列表架构文档在调用时立即添加,然后添加一个顶级驱动程序文档,该文档除了包含和导入您想要读取的其他架构文档之外什么都不做,并带有特定的架构位置信息。

    在您的情况下,这意味着从 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 实现彼此不一致的情况(在某些情况下与它们自身不一致 - 有时,当调用以不同的顺序命名输入时,相同的处理器会在相同的输入上产生截然不同的结果)。

    关于具体问题:

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

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

    的声明也就不足为奇了

    【讨论】:

    • 按照您的建议,我创建了一个包含所有导入的额外架构,效果很好。谢谢
    猜你喜欢
    • 2019-11-05
    • 1970-01-01
    • 1970-01-01
    • 2014-04-06
    • 2021-03-27
    • 1970-01-01
    • 1970-01-01
    • 2010-10-19
    相关资源
    最近更新 更多