【问题标题】:How to verify that one XSD schema is a subset of another XSD schema?如何验证一个 XSD 架构是另一个 XSD 架构的子集?
【发布时间】:2012-12-26 12:02:50
【问题描述】:

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

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

在测试期间,我们打算验证每个子组件的子 XSD 架构确实是关联蓝图 XSD 架构的子集,但我们没有自动执行此验证的方法。这些 XSD 架构相当大且丑陋,需要手动进行此测试。如果有一种“针对 XSD 文件 2 验证 XSD 文件 1”命令会很不错,类似于 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 环境中进行测试,但也计划在其他环境中执行该系统(因此首选跨平台解决方案)。

【问题讨论】:

  • 如果子集 XSD 会自动生成,那么至少按照设计它们是主集的子集,你还会问这个问题吗?
  • 好问题。如果子模式是从蓝图模式生成的,那将解决我的一些问题;但是,我们仍然希望针对子集模式 B 验证子集模式 A(如果可能),以帮助自动化一些互操作性问题(即哪个子组件可以安全地与另一个子组件通信,而不会有无效 XML 文件的风险)。
  • 不同的子组件开发团队手工创建了所有模式(由于它们的复杂性和每个子组件的定制需求)。他们还倾向于使用不同的开发工具套件,除非我们的项目要求使用特定工具。
  • 不幸的是,我相信没有生产工具可以做到这一点。最近我看到的是一篇关于“模式嵌入”的论文,这就是你正在做的事情。 docs.google.com/viewer?url=http://www.vldb2005.org/program/…作者可能有一个工具或知道一个。
  • @13ren,QTAssistant 实际上做了大部分它在这个问题中描述的事情,以及this related one,自 1997 年以来,在与 TOP 50 相关的生产环境中世界上的FI。我在这里试图弄清楚的问题是,按照我们的标准,“一个破碎的过程”......

标签: validation xsd schema subset


【解决方案1】:

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

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

一个复杂的问题是,有两种不同的方法可以查看您要验证的子集/超集关系:(1) 模式 1 接受为有效的每个文档(或元素)也被模式 2 接受为有效(没有参考到所做的类型分配),或(2)针对模式 1 和 2 的验证生成的类型化文档(在规范中称为 post-schema-validation 信息集)彼此之间存在适当的关系:如果元素或属性在树 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”添加到打开任务的队列中,除非它在已经完成的比较列表中。

    • 1234563因此,它们定义的语言是常规语言,并且子集/超集关系对于常规语言是可确定的。
  3. 父类型 T1 和 T2 为每个可能的子元素 C 分配了元素声明和类型定义。让我们称它们为 ED1、ED2、CT1 和 CT2。每个同名的子元素都将具有相同的类型,但不同的子元素可能匹配不同的元素声明。因此,对于任何可能的名称,只有一对类型 CT1 和 CT2,但可能有多对 ED1 和 ED2(分析需要小心以确保它们正确匹配;这可能很难自动化)。

  4. 如果 CT1 = CT2,则不执行任何操作,否则将“比较类型 CT1 和 CT2”放入打开的任务队列,除非已执行比较。

  5. 如果 ED1 和 ED2 在结构上相同,则什么也不做;否则将比较它们的任务放入任务队列(除非已经完成)。

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

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

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

【讨论】:

  • 我喜欢您对<complexType> 的关注,它使顶级与嵌套无关。任何<group ref=../> 都可以复制进来。您还可以解决一些XSD 问题。但是...我认为您在 reg exp 上跳过的时间太短了-恕我直言,这很困难!例如:a|b = b|a, ac|bc = (a|b)c, aa* = a+, a?|b = (a|b)?, all(a,b) = ab|ba, @9876 DFA 会这样做,但我会查看正式语言教科书以了解相等/子集算法,并查看 XSD 的 det/UPA/1-unambig reg exp 是否更容易。使其适应与纯 reg exp 的所有 XSD 背离将是乏味/棘手的 - 尽管在实践中可能很少需要。
【解决方案2】:

谢谢你,@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, diff 引擎针对源模型工作,而不是 PSVI 模型。我们可以自定义它以使用 PSVI,因为后者更接近您的实际需要。我们还可以包括让自定义规则集增强“base”和“revision”之间的比较的能力,换句话说,允许用户覆盖我们当前使用的“=”运算符。

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

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

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

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

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

【讨论】:

    【解决方案3】:

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

    重申问题:

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

    一种可能的解决方案:

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

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

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

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

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

    【讨论】:

      【解决方案4】:

      根据架构验证 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 处理工具完成转换。

      【讨论】:

        猜你喜欢
        • 2012-05-29
        • 2010-11-15
        • 1970-01-01
        • 2011-06-18
        • 1970-01-01
        • 2015-04-20
        • 2011-05-30
        • 1970-01-01
        • 2010-09-24
        相关资源
        最近更新 更多