【问题标题】:Creating a 'flexible' XML schema创建一个“灵活”的 XML 模式
【发布时间】:2011-02-05 05:44:13
【问题描述】:

我需要为一个非常灵活的 XML 文件创建一个模式。它必须满足以下要求:

  1. 验证我们需要存在的一些元素,并了解它们的确切结构
  2. 验证一些可选的元素,我们知道它们的确切结构
  3. 允许任何其他元素
  4. 按任意顺序允许它们

快速示例:

XML

<person>
    <age></age>
    <lastname></lastname>
    <height></height>
</person>

我对 XSD 的尝试:

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="person">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="firstname" minOccurs="0" type="xs:string"/>
        <xs:element name="lastname" type="xs:string"/>
        <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

现在我的 XSD 满足要求 1 和 3。但是,如果 firstname 和 lastname 都是可选的,则它不是有效的架构,因此它不满足要求 2,并且顺序是固定的,这不符合要求 4。

现在我只需要一些东西来验证我的 XML。我对任何方式的建议持开放态度,无论是在 .NET 3.5 中以编程方式,还是在其他类型的架构等。

谁能想出一个解决方案来满足所有 4 个要求?

【问题讨论】:

    标签: xml xsd schema


    【解决方案1】:

    如果名称元素是可选的,则无法满足您的要求 3,因为您的架构将违反唯一粒子属性规则(基本上,处理器将不知道是根据名字还是任何来验证名字)。

    就验证而言,您并不局限于单一模式。如果您可以在不同的命名空间中使用两个模式,您可以这样做:

    架构一 - 允许任何事情:

    <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="document">
        <xs:complexType>
          <xs:sequence>
            <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded" />
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
    

    模式二 - 为某些元素添加特定验证:

    <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://other" xmlns="http://other">
        <xs:element name="firstname" type="xs:string"/>
        <xs:element name="lastname" type="xs:string"/>
    </xs:schema>
    

    然后确保您的实例文档的 xsi:include 引用这两个架构。

    【讨论】:

    • 但仍然如何满足要求1?如果我使用多个模式,如何要求 lastname 元素始终存在?
    【解决方案2】:

    我今天想了很多这个问题。我正在考虑这条xs:all 规则使 XML 数据库存储具有非结构化“CMS”(如数据)的文档,同时验证数据有多难。

    然后我突然想到,XHTML 允许以您标记页面所需的任何顺序非常灵活地安排嵌套元素。

    下面是 XHTML 1.1 模式的摘录:

      <xs:group name="InlForm.class">
        <xs:choice>
          <xs:element ref="input"/>
          <xs:element ref="select"/>
          <xs:element ref="textarea"/>
          <xs:element ref="label"/>
          <xs:element ref="button"/>
        </xs:choice>
      </xs:group>
    
      <xs:group name="Inline.extra">
        <xs:choice/>
      </xs:group>
    
      <xs:group name="Ruby.class">
        <xs:sequence>
          <xs:element ref="ruby"/>
        </xs:sequence>
      </xs:group>
    
      <!--
       Inline.class includes all inline elements,
       used as a component in mixes
      -->
      <xs:group name="Inline.class">
        <xs:choice>
          <xs:group ref="InlStruct.class"/>
          <xs:group ref="InlPhras.class"/>
          <xs:group ref="InlPres.class"/>
          <xs:group ref="I18n.class"/>
          <xs:group ref="Anchor.class"/>
          <xs:group ref="InlSpecial.class"/>
          <xs:group ref="InlForm.class"/>
          <xs:group ref="Ruby.class"/>
          <xs:group ref="Inline.extra"/>
        </xs:choice>
      </xs:group>
    
      <xs:group name="Heading.class">
        <xs:choice>
          <xs:element ref="h1"/>
          <xs:element ref="h2"/>
          <xs:element ref="h3"/>
          <xs:element ref="h4"/>
          <xs:element ref="h5"/>
          <xs:element ref="h6"/>
        </xs:choice>
      </xs:group>
    

    它们本质上是递归嵌套组的选择。我想写这篇文章的人是在一个安全的机构里度过余生,每天接受几次强制服药。

    我希望这会有所帮助。我认为这说明了超级灵活模式是如何在 XSD 1.0 中“真正”完成的。

    编辑 - 有效!您可以创建所有其他组的“主”组,并使用此示例ListItem 元素定义来允许以任何顺序连续嵌套元素。确保 ListItem 也包含在一个组中,以便递归工作。

      <xs:element name="ListItem">
        <xs:complexType>
          <xs:sequence>
            <xs:group ref="content:any.mix"  minOccurs="1" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    

    所以我的any.mix 组看起来像这样:

      <xs:group name="any.mix">
        <xs:choice>      
          <xs:group ref="content:item.class" />
          <xs:group ref="content:media.class" />
          <xs:group ref="content:data.class" />
          <xs:group ref="content:list.class" />      
        </xs:choice>
      </xs:group>
    

    每个“类”组都包含更多的组选择,依此类推,直到它们最终命中元素,如果您愿意,也可以是叶级实际标签。

    组本身不应有循环引用; “技巧”在于any.mix 组的无限出现,即它是一个具有无限根选择的选择树。

    卢克

    【讨论】:

    • 为了完整起见,我应该补充两点 a) 它不是你所有梦想的答案,为了满足上述所有要求,你可能需要添加额外的包含元素,我花了一个小时,放弃了,所以这个答案是为了解决“超级灵活”部分 b)如果你知道你的验证器是 XSD 1.1(稀有)那么xs:all 现在等同于xs:sequence 具有松散的顺序,即他们删除了可怕的“仅一个子元素”规则毁了我们所有人的 XSD。
    猜你喜欢
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-19
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    相关资源
    最近更新 更多