如何验证一个XSD架构是另一个XSD架构的子集?
我们正在使用一系列“蓝图”XSD架构(定义子组件可用的所有可能输入或输出)来创建系统系统应用程序。正在实现许多子组件,这些子组件使用XML文件在它们之间传递数据。每个子组件创建相关蓝图XSD架构的子集(以指示它选择实现哪些可能的输入或输出)。任何针对子集XSD架构验证的XML数据文件也必须针对蓝图XSD架构进行验证,但反之则不然(因为子集XSD架构可能不包含蓝图XSD架构中的所有“可选”或“选择”XML元素,并且它可以选择进一步限制现有XML标记上的允许数据值)。系统将针对该子组件的子集XSD架构验证子组件的所有XML输入(标记任何错误输入并隔离数据相关问题的来源)。
在测试期间,我们打算验证每个子组件的子集XSD架构是否真的是关联蓝图XSD架构的子集,但我们没有自动执行此验证的方法。这些XSD架构相当庞大且难以手动进行此类测试。有一种“验证XSD文件1对XSD文件2”命令会很好,类似于Java如何根据XSD架构执行XML文件验证。我们要确认每个子组件的子集XSD架构都不允许任何违反蓝图XSD架构的XML输入/输出组合。使用这种模式到模式功能,验证子组件A的输出XML是否适合用作子组件B的输入也是非常有用的(我们可以轻松地针对XSD模式验证单个输出XML,但是我们要确认子组件A的所有可能的XML输出都将针对子组件B的XSD架构进行验证。)
有用的信息:此应用程序是一个Java 6应用程序的集合,这些应用程序作为OSGi包实现,并使用Maven 2.2.1编译/执行。使用任何特定的开发IDE都没有要求。该系统正在Microsoft Windows XP环境中进行测试,但也有计划在其他环境中执行此系统(因此首选跨平台解决方案)。
答案 0 :(得分:2)
确保所需关系的最简单方法是通过限制蓝图模式的类型来派生子集模式的类型。听起来好像那艘船已经航行了。
像其他人一样,我不知道任何开箱即用的工具(尽管如果Petru Gardea说QT助手可以,那么值得跟进)。
一个复杂的问题是,有两种不同的方法可以查看要验证的子集/超集关系:(1)模式1接受为有效的每个文档(或元素)也被模式2接受为有效(无参考) (2)通过验证生成的类型文档(在规范中称为后模式验证信息集)对于模式1和2彼此保持适当的关系:如果元素或属性在树1中有效,它在树2中有效;树1中分配给它的类型是树2中分配给它的类型的限制;如果模式1和模式2是独立开发的,那么它们的类型通过派生相关的可能性很小,所以我想你是第一个接受这个问题的方法。
但问题无论是哪种形式都是可以判定的。对于任何模式(我小心使用这个术语),根据定义,有一定数量的类型和有限数量的元素名称被声明;因此,存在有限数量(可能很大)的元素名称/类型对。
算法可以是这样的。
从预期的根元素开始。 (如果有多个可能的根元素,那么在一般情况下,您需要为每个元素运行此检查。)如果预期的根元素是E,在模式1中使用类型T1并在模式2中键入T2,则将任务“比较类型T1和T2”放在打开的任务队列中。已完成的任务列表将为空。
比较两种复杂类型T1和T2:
检查为T1和T2声明的属性集,以获取其名称之间的子集/超集关系。确保预期超集中不需要属性或预期子集中没有可选属性。
为T1和T2声明的每个属性A都将被分配一个类型(称为ST1和ST2)。如果ST1 = ST2,什么都不做;否则,将任务“比较简单类型ST1和ST2”添加到打开任务的队列中,除非它已在已完成的比较列表中。
现在检查T1和T2中可能存在的子序列 - 正如13ren在评论中建议的那样,这是易处理的,因为内容模型本质上是使用元素名称集作为字母表的正则表达式;因此,他们定义的语言是规则的,子集/超集关系对于常规语言是可判定的。
每个可能的子元素C都由父类型T1和T2分配元素声明和类型定义。我们称它们为ED1,ED2,CT1和CT2。每个具有相同名称的子项都具有相同的类型,但不同的子项可以匹配不同的元素声明。所以对于任何可能的名称,只有一对类型CT1和CT2,但可能有多对ED1和ED2(分析需要小心,以确保它们正确匹配;这可能很难自动化)。
如果CT1 = CT2,则不执行任何操作,否则将“比较类型CT1和CT2”置于打开的任务队列中,除非已经执行了比较。
如果ED1和ED2结构相同,则什么都不做;否则将比较它们的任务放入任务队列(除非它已经完成)。
要比较两个简单类型ST1和ST2,比较它们的词法空间(如果你想要在模式上定义子集/超集关系的第一个)或它们的值空间(如果你想要第二个)。如果ST1和ST2都是相同基元类型的限制,您可以轻松地比较它们对基于有效面的限制的集合。模式方面可能会使问题复杂化,但由于它定义了一组正则表达式,因此子集/超集关系对它来说是可判定的。
要比较两个元素声明,您需要比较元素声明的每个属性,并检查所需的子集/超集关系。
正如您所看到的,它非常复杂和乏味,您真的想要自动化这种分析,而且它也很复杂,很容易理解为什么它不能作为开箱即用的功能广泛提供。但是代码肯定会很有趣。
答案 1 :(得分:0)
谢谢你,@ 13ren,因为你的“嘟嘟”:)
这是一个很长的评论,而不是答案。我将从我之前与13ren的交流开始,more precise, it provides to a user all that is needed to define such an analysis model.
我的意思是在QTAssistant(this one)中我们有一个XSD比较函数;对于XSD感知,它已经做了很多文本或XML感知的diff工具无法做到的事情(例如,它不关心有多少XSD文件,它们的版本之间的布局如何变化等)对于提供的UI,与PSVI相比,diff引擎对源模型起作用。我们可以将其定制为使用PSVI,因为后者距离您实际需要的距离更近一步。我们还可以包括使用自定义规则集来增强“base”和“revision”之间的比较的能力,换句话说,允许用户覆盖我们当前使用的“=”运算符。
我认识到我们没有开箱即用的任何东西允许覆盖xsd:pattern facets的比较;对于人类易于识别的东西也是如此,例如xsd:positiveInteger
与xsd:integer + xsd:minInclusive=1
。或者将xsd:all
与xsd:choice
或xsd:sequence
进行比较;为此,我们不解析XSD约束的选择器和字段,这与正则表达式非常相似,并不容易处理。
假设目标是找到尽可能多的“差异”而不是完全排除它们,那么QTAssistant还有三个有用的功能:
我们必须在比较中提供的另一件事(您可能需要考虑)不仅与XSD / XML的等效性有关,而且与从XSD生成的工件(例如通过JAXB的Java类)等效;最重要的是,可扩展性模式,那些使用通配符的模式(xsd:any和anyAttribute)。
我们(QTAssistant)目前有兴趣通过一些更具体的要求与我们合作(我们需要从代表XSD的交换开始,我会假设的NDAs等),带外,看看我们是否确实可以使它工作。如果您想继续,请随时通过与我的SO资料相关的网站的支持地址与我联系。
答案 2 :(得分:0)
由于目前没有针对另一个模式验证/检查模式的可用解决方案,看起来我们必须使用变通方法。以下是我的尝试。
重述问题:
确定子集模式中定义的所有数据类型是否存在,并且是否在“蓝图”模式中定义的(不太严格)范围内。
可能的解决方案:
因此,利用这些知识,我们可以构建一个解决方案:
创建子集模式的所有可能的XML实例(以编程方式执行此步骤可能是一个挑战),并根据“蓝图”模式验证这些XML实例。
但您如何知道子集架构是“蓝图”架构的子集?好吧,既然您创建了子集模式的所有可能的XML实例,它就会覆盖子集模式中的所有数据类型。并且针对“蓝图”模式验证这些XML实例,本质上是检查数据类型是否存在并且所有数据类型都在“蓝图”模式中定义的范围内。因此,确定您的子集架构确实是“蓝图”架构的子集。
我知道这不是一个理想的解决方案,但希望这有帮助,因为没有简单的方法可以做你想要的。
答案 3 :(得分:0)
根据模式验证XML的工具已经知道如何执行此操作,因为在<xs:complexContent><xs:restriction>
的情况下,新定义的类型必须是受限制类型的子集。
如果您想要使用此功能,您可以让子模式定义限制蓝图模式中类型的复杂类型。
但是,如果在没有这一点的情况下创建子模式,则可能仍然可以通过修改子模式以匹配下面的模式来实现,然后通过模式处理器发送它们以进行验证。
蓝图架构示例,blueprintschema.xsd:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root" type="rootType"/>
<xs:complexType name="rootType">
<xs:sequence>
<xs:element name="child1" minOccurs="0"/>
<xs:element name="child2" minOccurs="0"/>
<xs:element name="child3" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
作为蓝图架构子集的子架构示例:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root" type="rootType"/>
<xs:complexType name="rootType">
<xs:sequence>
<xs:element name="child2"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
转换为重新定义构造后的子模式示例:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:redefine schemaLocation="blueprintschema.xsd">
<xs:complexType name="rootType">
<xs:complexContent>
<xs:restriction base="rootType">
<xs:sequence>
<xs:element name="child2"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
<xs:element name="root" type="rootType"/>
</xs:schema>
模式处理器将告诉您重新定义的“rootType”是否实际上是原始蓝图“rootType”的子集
由于模式只是XML,因此可以使用普通的XML处理工具完成转换。