XSD循环导入 [英] XSD circular import

查看:132
本文介绍了XSD循环导入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



A.xsd

 < xs:schema xmlns =ns1targetNamespace =ns1> 
< xs:import namespace =ns2schemaLocation =B.xsd/>
< xs:element name =MyElementtype =xs:string/>
< / xs:schema>

B.xsd

 < xs:schema xmlns =ns2targetNamespace =ns2xmlns:ns1 =ns1> 
< xs:import namespace =ns1schemaLocation =A.xsd/>
< xs:complexType name =MyComplex>
< xs:sequence>
< xs:element ref =ns1:MyElementminOccurs =0/>
< xs:sequence>
< xs:complexType>
< / xs:schema>

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



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

 < xs :schema xmlns =ns1targetNamespace =ns1> 
< xs:element name =MyElementtype =xs:string/>
< / xs:schema>

A.xsd变为

 < xs:schema xmlns =ns1targetNamespace =ns1> 
< xs:import namespace =ns2schemaLocation =B.xsd/>
< / xs:schema>

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

 < xs:schema xmlns =ns2targetNamespace =ns2xmlns:ns1 =ns1> 
< xs:import namespace =ns1schemaLocation =C.xsd/>
< xs:complexType name =MyComplex>
< xs:sequence>
< xs:element ref =ns1:MyElementminOccurs =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:无法将名称'ns1:MyElement'解析为(n)'元素声明' 零件。 

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



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

解决方案

关于一般问题:



你问圆形进口是否有效?如果通过循环,则表示存在一系列模式文档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]的名称空间,然后我相信这样的循环显然是合法的(在某些情况下是不可避免的)。 / p>

我建议的解决方法是:


  1. 在任何声明任何内容的模式文档中,根据需要使用xs:import,但不要在导入时指定架构位置。这些引用中的循环是无害的。

  2. 调用模式处理器时,请为其提供要读取的所有模式文档的完整列表,如果可能,请通过选项或配置告诉它读取任何其他模式文档。

  3. 如果您的模式文档在验证时不接受多个模式文档作为输入,那么您必须有一个模式文档引用您想要的所有内容阅读,或者如果您不相信自己在调用时获取模式文档列表,那么添加一个顶级驱动程序文档,该文档除了包含和导入您想要读取的其他模式文档之外什么都不做,具有特定模式地点信息。

在您的情况下,这意味着从(原始形式)A.xsd中删除xs:import / @ schemaLocation属性B.xsd,并添加一个表格的驱动文件

 < xs:schema xmlns:xs =http:// www.w3.org/2001/XMLSchema\"> 
< xs:import namespace =ns1schemaLocation =A.xsd/>
< xs:import namespace =ns2schemaLocation =B.xsd/>
< / xs:schema>

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

关于具体问题:



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



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


I need to parse a XSD with XSOM but this XSD contains circular imports.

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 can’t parse the schema because it detects elements that have already been defined due to circular imports. So I tried to break the circular import by externalizing the elements that are defined by A and used in B.

C.xsd contains element from A that are used by B. Note that these elements are not used in A. Don’t ask me why these have been defined in A.

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

A.xsd becomes

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

B.xsd (import C.xsd instead of A.xsd) becomes

<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 can parse the XSD. But now I can’t create the schema with the following code:

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

I use the standard implementation bundled with the JDK 1.7. I get the exception:

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

The issue is that the resource resolver is called for the B namespace but not for the A namespace which makes sense. Since the namespace A is shared by A.xsd and C.xsd, the resource resolver can’t find the elements defined in C.xsd.

Are circular imports valid? Is it possible to break a circular import so it can be parsed by XSOM and then loaded by the SchemaFactory?

解决方案

On the general question:

You ask "Are circular imports valid?" If by circularity you mean that there is a chain of schema documents S[1], S[2], ..., S[n] where schema document S[1] refers to schema document S[2] by name, S[2] to S[3], ... S[n-1] to S[n], and S[n] to S[1] then I don't believe the XSD 1.0 spec or the XSD 1.1 say clearly one way or the other. (Some WG members tried to persuade the WG to improve the clarity of its thinking on this and related topics, but failed.) Some implementations support circular import (and other forms of circularity), but I don't think it is possible to argue from the spec that your implementation is doing anything wrong.

If on the other hand you mean merely that there is a cycle such that for 0 <= i <= n-1, S[i] imports the namespace of S[i+1] and S[n] imports the namespace of S[1], then I believe that such cycles are clearly legal (and in some cases unavoidable).

The workaround I recommend is:

  1. In any schema document that declares anything, use xs:import as needed, but do not specify a schema location on the import. Cycles in such references are harmless.
  2. When invoking the schema processor, give it the full list of all the schema documents you want it to read, and if possible tell it via options or configuration not to read any other schema documents.
  3. If your schema document does not accept multiple schema documents as input at validation time, so you must have a single schema document that refers to everything you want to be read, or if you don't trust yourself to get the list of schema documents right at invocation time, then add a top-level driver document that does nothing but include and import the other schema documents you want to be read, with specific schema location information.

In your case, that would mean deleting the xs:import/@schemaLocation attribute from (the original forms of) A.xsd and B.xsd, and adding a driver document of the form

<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>

The effect is to ensure that there are never cycles in schema documents' references to other schema documents; that eliminates a very large class of cases where XSD implementations are inconsistent with each other (and in some cases with themselves -- sometimes the same processor produces dramatically different results on the same inputs when the invocation names the inputs in a different order).

On the specific question:

In your example, there is no requirement that ns2 be imported by either A.xsd or C.xsd, because neither of them includes any references to any components in namespace ns2. So the cycle in your example seems gratuitous.

In your second example, you give some code which does not succeed in loading the schema. But I don't see any reference in that code to any specific schema document at all; unless there is something relevant you're not showing us, it's no wonder the validator can't find a declaration for {ns1}MyElement.

这篇关于XSD循环导入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆