【问题标题】:extract paths from xsd从 xsd 中提取路径
【发布时间】:2013-02-20 07:07:43
【问题描述】:

假设我有以下 XML 文档:

<foo>
  <bar/>
  <bang bash="hello">
    <foobar>123</foobar>
  </bang>
</foo>

我想提取本文档中各个叶子的所有路径列表,例如:

foo
foo.bar
foo.bang
foo.bang.@bash
foo.bang.foobar

这个过程有术语吗?

更进一步:假设我有一个 .xsd 用于一个真正异常复杂的 XML 模式。有没有一种简单的方法可以从 .xsd 中提取所有此类路径?

(通过简单的方式,理想情况下,我的意思是某处是否存在执行此操作的库?)

【问题讨论】:

  • 如果包含数据类型信息(foo:complex、foo.bang.bash:String、foo.bang.foobar:int 等),则会获得奖励分
  • 如果您可以使用 .NET,则可以使用 XmlSchemaValidator 的 GetExpectedParticles 方法从根元素下降 - 不过这会很复杂,如前面的 StackOverflow answer 所示
  • 撒克逊人的Schema Component Model API 在这里也可能有用

标签: xml xsd schema


【解决方案1】:

在 SGML 社区中,您正在寻找的值(当它们涉及元素时)被称为“完全限定的通用标识符”或 FQGI;因为 '。'是 XML 中的合法名称字符,在 SGML 参考具体语法中,FQGI 通常用斜线书写,您正在书写点。 (我将在这里延伸术语 FQGI 并用它来表示您感兴趣的字符串,包括表示属性的字符串,而不是表示元素的字符串。)

对于查找所有 FQGI 集合的过程,我不知道任何既定术语,这些 FQGI 可能出现在针对特定模式有效的文档中。请记住,在许多 XML 词汇表中,这是一个无限集;如果您想要一个终止的进程,则需要识别所有可能的 FQGI 的有限子集。

但是您需要遵循的过程相对简单。一个简单的版本是这样运行的:

  1. 如果您感兴趣的架构是跨多个架构文档定义的,请将它们全部合并到一个 XML 文档(具有多个 xs:schema 子项的包装器)或一个架构文档集合中使用 XSLT 或 XQuery 处理。

  2. 确定您希望开始的元素声明和属性声明集。 (在你的例子中,这个集合大概由 foo 的顶级元素声明组成。)对于这个集合中的每个项目,写下它的名称和它的类型。称这组字符串/类型对为 S。

  3. 将集合 S 复制到集合 S'。

  4. 按以下方式创建集合S'':以S''为空开始,然后对于S'中的每个项目,令N为FQGI,T为项目中命名的类型,并且:

    (a) 如果 N 表示一个属性,则什么也不做。

    (b) 如果 N 表示一个元素,则识别可能出现在该元素上的属性集。对于每个这样的属性,确定其类型 T2,并通过连接 N、斜杠、at 符号和属性的扩展名称来创建字符串 N2。将 (N2, T2) 对添加到 S''。

    (c) 如果 N 表示一个元素,则找到 (i) 出现在 T 的内容模型中,(ii) 匹配 T 的内容模型中的通配符,或 (iii) 可替换的元素集合(i) 或 (ii) 中命名的元素。对于每个这样的可能的孩子,识别孩子的类型 T3 并通过连接 N、“/”和可能的孩子的扩展名称来创建一个字符串 N3。将 (N3, T3) 对添加到 S''。

  5. 如果 S'' 为空,您就完成了,您的答案在集合 S 和集合 S' 的并集中。否则,令(a new) S为S和S'的并集,令(a new) S'等于S'',转步骤4。

稍加思考就会告诉您,可以匹配通配符的名称集是无限的,因此步骤 4(c) 中的列表 (ii) 无法完整处理。您可以通过多种方式选择列表的有限子集;您选择哪个取决于您想要 FQGI 列表的用途。

稍加思考就会告诉你,如果词汇表中的任何元素都可以作为它自己的后代出现(如 HTML 的 div 或 li 元素),那么概述的过程将永远不会终止。同样,您可以通过多种方式修剪 4(c) 中生成的对集合以保证终止。

我不知道有什么库可以做到这一点,也许是因为对于有趣的 XML 词汇表来说,可能的 FQGI 集很少是有限的。使用 XQuery 引擎或在 XSLT 样式表中完成这项工作很容易。

【讨论】:

    【解决方案2】:

    A similar question 在 SO 上发布在这里。除了我在相关帖子中描述的解决方案之外,我仍然不知道您的方案有任何开箱即用的解决方案(API 或其他)。

    我是第一个认识到即使是我在 SO 上描述的 the solution 也可能缺乏对某些 XSD 功能的覆盖,或者可能不符合人们对如何生成某些 XPath 的特定期望。它可以支持更新请求中的内容(包括额外的“元数据”,例如 XPath 匹配的节点类型),因为可以使用自定义公式添加计算列以匹配您的模式。

    虽然 CM Sperberg-McQueen 描述的算法确实让您了解它可能涉及的一些事情,但它也包含一个关于头脑简单的方法的温和“免责声明”,这实际上意味着许多XSD 规范涵盖的场景被忽略了。

    除非您的 XSD 真的很简单,否则请认为这是一个预告片!一些“坏”的例子:通过复杂类型(不仅仅是元素引用)的递归 XML 结构(暗示)是棘手的,当类型层次结构在 XSD 的设计中很重且普遍时更是如此;使用抽象类型元素(想想 XML 实例中的 xsi:type 属性)、块属性的使用、表单属性、变色龙 XSD 的使用(现在步骤 1 本身就很有趣,更不用说是否使用了不同的默认值用于模式级别的元素/属性形式)。

    如果您发现其中一些额外的“细节”适用于您的 XSD,那么我建议您忘记 XQuery 或 XSLT,并使用专门的模式对象模型 API(Java 上的 XSOM,.NET 也有一个非常好的一)遍历您的 XSD - 在这里我只是重复了@pgfearo 所说的话(据我所知,SAXON XSD 支持仅在付费版本中提供;而 Apache 和 JAXB RI 为您免费提供 XSOM)。那时你不需要担心很多事情,而且很可能你可以在合理的时间内完成。

    【讨论】:

      【解决方案3】:

      我创建了一个 Java 工具 XsdPathTypeGenerator 来执行此操作。它还提取元素和属性类型。

      给定一个 XSD:

      <?xml version="1.0" encoding="UTF-8"?>
      <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://smitek.co.uk/example/1">
          <xsd:element name="employee">
              <xsd:complexType>
                  <xsd:sequence>
                      <xsd:element name="name" type="xsd:string"/>
                      <xsd:element name="department">
                          <xsd:complexType>
                              <xsd:sequence>
                                  <xsd:element name="name" type="xsd:string"/>
                              </xsd:sequence>
                              <xsd:attribute name="code" type="xsd:integer"/>
                          </xsd:complexType>
                      </xsd:element>
                  </xsd:sequence>
                  <xsd:attribute name="active" type="xsd:boolean"/>
              </xsd:complexType>
          </xsd:element>
      </xsd:schema>
      

      它将创建一个地图

      employee@active=xsd:boolean
      employee/name=xsd:string
      employee/department@code=xsd:decimal
      employee/department/name=xsd:string
      

      它有一定的局限性,这意味着你将它作为一个工具运行而不是将它作为一个库使用,对我来说有点懒惰,但它至少解决了我的问题 :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-01
        • 1970-01-01
        • 2021-08-14
        • 1970-01-01
        • 1970-01-01
        • 2011-09-01
        • 2016-06-19
        相关资源
        最近更新 更多