8

如何验证一个 XSD 架构是另一个 XSD 架构的子集?

我们正在使用一组“蓝图”XSD 模式(定义子组件可用的所有可能输入或输出)来创建一个系统系统应用程序。正在实现许多子组件,这些子组件使用 XML 文件在它们之间传递数据。每个子组件创建相关蓝图 XSD 模式的子集(以指示它选择实现的可能输入或输出)。针对子集 XSD 架构验证的任何 XML 数据文件也必须针对蓝图 XSD 架构进行验证,但反之则不正确(因为子集 XSD 架构可能不包含来自蓝图 XSD 架构的所有“可选”或“选择”XML 元素,并且它可以选择进一步限制现有 XML 标记上允许的数据值)。

在测试期间,我们打算验证每个子组件的子集 XSD 模式确实是关联蓝图 XSD 模式的子集,但我们没有自动执行此验证的方法。这些 XSD 架构相当大且丑陋,需要手动进行此测试。如果有一种“针对 XSD 文件 2 验证 XSD 文件 1”命令会很不错,类似于 Java 如何针对 XSD 模式执行 XML 文件的验证。我们想要确认每个子组件的子集 XSD 架构将不允许任何违反蓝图 XSD 架构的 XML 输入/输出组合。有了这种模式到模式的能力,

有用信息:此应用程序是作为 OSGi 包实现并使用 Maven 2.2.1 编译/执行的 Java 6 应用程序的集合。没有使用任何特定开发 IDE 的要求。该系统正在 Microsoft Windows XP 环境中进行测试,但也计划在其他环境中执行该系统(因此首选跨平台解决方案)。

4

4 回答 4

2

确保所需关系的最简单方法是通过限制蓝图模式的类型来派生子模式的类型。不过,听起来那艘船已经航行了。

像这里的其他人一样,我不知道有任何开箱即用的工具(尽管如果 Petru Gardea 说 QT Assistant 可以,那么值得跟进)。

一个复杂的问题是,有两种不同的方法可以查看您要验证的子集/超集关系:(1)模式 1 接受为有效的每个文档(或元素)也被模式 2 接受为有效(不参考类型分配),或(2)针对模式 1 和 2 的验证(在规范中称为后模式验证信息集)生成的类型化文档彼此之间存在适当的关系:如果元素或属性在树 1,在树 2 中有效;树 1 中分配给它的类型是树 2 中分配给它的类型的限制;等等。如果模式 1 和 2 是独立开发的,那么它们的类型通过推导相关联的可能性很小,所以我想你已经想到了第一种方法来解决这个问题。

但是,无论哪种形式,这个问题都绝对是可以确定的。对于任何模式(我正在仔细使用该术语),根据定义,都声明了有限数量的类型和有限数量的元素名称;因此,元素名称/类型对的数量有限(可能很大)。

该算法可以是这样的。

  1. 从预期的根元素开始。(如果有多个可能的根元素,那么在一般情况下,您需要对它们中的每一个都运行此检查。)如果预期的根元素是 E,在模式 1 中的类型为 T1,在模式 2 中的类型为 T2,那么将任务“比较类型 T1 和 T2”放在打开任务的队列中。已完成的任务列表将为空。

  2. 比较两种复杂类型 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 在结构上相同,则什么也不做;否则将比较它们的任务放入任务队列(除非它已经完成)。

  3. 要比较两个简单类型 ST1 和 ST2,请比较它们的词汇空间(如果您想要模式上子集/超集关系的第一个定义)或它们的值空间(如果您想要第二个)。如果 ST1 和 ST2 都是相同原始类型的限制,您可以轻松地比较一组有效的基于方面的限制。模式方面可能会使事情复杂化,但是因为它定义了一组正则表达式,所以子集/超集关系是可以确定的。

  4. 要比较两个元素声明,您需要比较元素声明的每个属性并检查所需的子集/超集关系。

正如您所看到的,它足够复杂和乏味,以至于您真的想要自动执行此分析,而且它也足够复杂,很容易看出为什么它没有作为开箱即用的功能广泛提供。但是编码肯定会很有趣。

于 2013-01-16T03:00:08.620 回答
0

由于目前没有针对另一个模式验证/检查模式的可用解决方案,看起来我们必须使用变通方法。下面是我的尝试。

重述问题:

确定子模式中定义的所有数据类型是否存在并且是否在“蓝图”模式中定义的(不太严格的)范围内。

一个可能的解决方案:

  1. 第一条(显而易见的)信息是 Schema 允许我们创建 XML 实例(这甚至意味着什么?!参见 2.)。
  2. 我们拥有的另一条(不太明显)信息是 XML 模式本身可以是一个“子集实例”——我的意思是:如果您要从 XML 实例对模式进行逆向工程,那么您就有一个子集模式(如果您没有“列表”或选择元素或其他“限制”,则此陈述并不总是正确的,那么反向工程子集模式将精确映射到“蓝图”模式)。

因此,利用这些知识,我们可以构建一个解决方案:

创建子模式的所有可能的 XML 实例(以编程方式执行此步骤可能是一个挑战),并根据“蓝图”模式验证这些 XML 实例。

但是你怎么知道子集模式是“蓝图”模式的子集?好吧,由于您创建了子模式的所有可能的 XML 实例,它涵盖了子模式中的所有数据类型。并且根据“蓝图”模式验证这些 XML 实例,本质上是检查数据类型是否存在,以及所有数据类型是否都在“蓝图”模式中定义的范围内。因此,确定您的子集架构确实是“蓝图”架构的子集。

我知道这不是一个理想的解决方案,但希望这会有所帮助,因为没有简单的方法可以满足您的要求。

于 2014-01-20T21:11:20.487 回答
0

谢谢@13ren,谢谢你的“哔”声:)

这是一个很长的评论,而不是一个答案。我将从我之前与 13ren 的交流开始,more precise, it provides to a user all that is needed to define such an analysis model.我的意思是在 QTAssistant(这个)中我们有一个 XSD 比较功能;作为 XSD 感知,它已经做了很多文本或 XML 感知 diff 工具不能做的事情(例如,它不关心有多少 XSD 文件,它们的版本之间的布局变化等)对于提供的 UI, diff 引擎针对源模型工作,而不是 PSVI 模型。我们可以自定义它以使用 PSVI,因为后者更接近您的实际需要。我们还可以包括让自定义规则集增强“base”和“revision”之间的比较的能力,换句话说,允许用户覆盖我们当前使用的“=”运算符。

我认识到我们没有任何开箱即用的东西允许覆盖 xsd:pattern facets 的比较;也不是人类容易识别的东西,例如xsd:positiveIntegervs. xsd:integer + xsd:minInclusive=1。或者比较 anxsd:all到 a xsd:choiceor xsd:sequence; 同样,我们不会解析出 XSD 约束的选择器和字段,这些约束很像正则表达式,不容易处理。

假设目标是找到尽可能多的“差异”而不是完全排除它们,QTAssistant 还有三个有用的功能:

  • 对于给定的根元素,它会创建简单 XPath 的完整列表。它可以用作发现“流氓”数据的快速方法。开箱即用的这种比较方法不考虑结构模式,即如果 XPath1 和 XPath2 表示实例 XML 中的两个兄弟,那么 XPath1 必须在 XPath2 之前)等。
  • 它带有一个内置的查询 XSD 分析器。SQL 可用于查询集合的 XSD 元模型以“发现”一些事物,这些事物指出了比较工具可能被设计为忽略的事物(出于可行性考虑),因此需要向人类报告以做出决定。
    • XSD 重构 (XSR)。它是业内(至少我知道的)唯一一个从头开始构建并考虑 XSD 重构和分析的引擎。我认为,如果您可以排除 xsi:type 以及理想情况下也可以使用替换组(在这个问题上我仍然需要考虑),我们可以提供我们所谓的“规范化转换”——一个花哨的词通过依赖 PSVI 模型将模式集转换为俄罗斯娃娃设计风格。这里有很多事情可以发挥作用:id 属性的使用、多余序列的折叠、单个选项 xsd:choices 的替换等 - 这就是我们在开发中但尚未发布的原因。

我们在比较中必须提供的另一件事(您可能需要考虑)不仅与 XSD/XML 的等价性有关,而且与从 XSD 生成的工件(例如通过 JAXB 的 Java 类)的等价性有关。最重要的是,可扩展性模式,那些使用通配符(xsd:any 和 anyAttribute)的模式。

我们(QTAssistant)目前有兴趣通过一些更具体的要求与您合作(我们需要从交换代表性 XSD、我假设的 NDA 等开始),看看我们是否真的可以做到工作。如果您想继续,请随时通过与我的 SO 个人资料相关联的网站的支持地址与我联系。

于 2013-01-18T15:55:54.627 回答
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 处理工具来完成转换。

于 2014-01-21T00:32:50.917 回答