【问题标题】:XML Schema for sequence of elements with same name but different attribute values?具有相同名称但属性值不同的元素序列的 XML 模式?
【发布时间】:2015-09-22 20:40:46
【问题描述】:

如何为这样的实例文​​档指定 XML 架构:

<productinfo>
  <!-- other stuff -->
  <informationset type="Manufacturer">
    <!-- content not relevant -->
  </informationset>
  <informationset type="Ingredients">
    <!-- content not relevant -->
  </informationset>
</productinfo>

也就是说,一个“productinfo”元素包含两个“信息集”子元素的序列,第一个具有@type="Manufacturer",第二个具有@type="Ingredients"

【问题讨论】:

    标签: xml xsd


    【解决方案1】:

    注意正如 Serge 指出的那样,这个答案是不正确的。

    使用 xerces 进行测试会出现此错误:type.xsd:3:21: cos-element-consistent: Error for type '#AnonType_productinfo'. Multiple elements with name 'informationset', with different types, appear in the model group. cos-element-consistent 的规范中有更多详细信息。

    但是有一个解决方案,类似于下面 Marc 的回答,但仍然使用类型。如果它们在由其他类型扩展的超类型的 minOccurs/maxOccurs 列表中,则可能会多次出现具有不同类型的相同内容。也就是说,就像 java 或 C# 中的多态类列表一样。这克服了上面的问题,因为虽然该元素名称可以在 xml 中出现多次,但它在 xsd 中只出现一次。

    这里是示例 xsd 和 xml - 这次用 xerces 进行了测试!:

    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="productinfo">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="informationset" type="supertype" minOccurs="2" maxOccurs="2"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    
      <xs:complexType name="supertype">
      </xs:complexType>
    
      <xs:complexType name="Manufacturer">
        <xs:complexContent>
          <xs:extension base="supertype">
          </xs:extension>
        </xs:complexContent>
      </xs:complexType>
    
      <xs:complexType name="Ingredients">
        <xs:complexContent>
          <xs:extension base="supertype">
          </xs:extension>
        </xs:complexContent>
      </xs:complexType>
    
    </xs:schema>
    
    <productinfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <informationset xsi:type="Manufacturer"></informationset>
      <informationset xsi:type="Ingredients"></informationset>
    </productinfo>
    

    注意:您无法控制不同类型的顺序,或每种类型出现的次数(每种可能出现一次、多次或根本不出现) - 就像java 或 C# 中的多态类列表。但是您至少可以指定整个列表的确切长度(如果您愿意的话)。

    例如,我已将上面的示例限制为恰好两个元素,但未设置顺序(即 Manufacturer 可能是第一个,或者 Ingredients 可能是第一个);并且未设置重复次数(即它们都可以是制造商,或两者都是成分,或两者之一)。


    您可以使用 XML Schematype,如下所示:

    <productinfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <informationset xsi:type="Manufacturer"></informationset>
      <informationset xsi:type="Ingredients"></informationset>
    </productinfo>
    

    XSD 为每个定义了单独的复杂类型:

    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="productinfo">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="informationset" type="Manufacturer"/>
            <xs:element name="informationset" type="Ingredients"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    
      <xs:complexType name="Manufacturer">
      </xs:complexType>
      <xs:complexType name="Ingredients">
      </xs:complexType>
    </xs:schema>
    

    这是xsi:type 的特例。一般来说,不要以为可以在同名元素中指定属性有不同的值,因为它们是同一个元素的不同定义。

    我不是 100% 清楚确切的原因 - 有人知道规范的相关部分吗?

    【讨论】:

    • 如果我打开您提供的 xsd,我会得到“同名且在同一范围内的元素必须具有相同类型”错误...
    • 是的,你是对的。感谢您的检查和回复。我最初只用xmllint(接受它)测试了上述内容;但是使用更严格的xerces 进行测试会产生与您得到的类似的错误:type.xsd:3:21: cos-element-consistent: Error for type '#AnonType_productinfo'. Multiple elements with name 'informationset', with different types, appear in the model group. 在规范中查找此内容会提供更多详细信息w3.org/TR/2004/REC-xmlschema-1-20041028/…
    • 奇怪的是,我对不正确的答案投了赞成票,但是带有“具有相同名称和相同范围的元素...”的评论让我在这里进行了搜索。
    【解决方案2】:

    您可以尝试这样的事情 - 为您的“信息集”元素创建一个单独的 complexType,并将属性限制为有效字符串列表:

    <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" 
               xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="productinfo">
        <xs:complexType>
          <xs:sequence>
            <xs:element maxOccurs="unbounded" 
                        name="informationset" type="informationSetType" />
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    
      <xs:complexType name="informationSetType">
        <xs:simpleContent>
          <xs:extension base="xs:string">
            <xs:attribute name="type" type="validAttributeType" use="required" />
          </xs:extension>
        </xs:simpleContent>
      </xs:complexType>
    
      <xs:simpleType name="validAttributeType">
        <xs:restriction base="xs:string">
          <xs:enumeration value="Manufacturer" />
          <xs:enumeration value="Ingredients" />
        </xs:restriction>
      </xs:simpleType>
    </xs:schema>
    

    当然,如果您愿意,您可以扩展该有效属性名称列表 - 只需将更多元素添加到限制枚举列表中。

    马克

    【讨论】:

      【解决方案3】:

      使用断言架构组件

      感谢XML Schema 1.1,有一种方法可以强制执行您的要求,而无需导入xsi 命名空间并将多态性破解到您的XML 文档中。 XML Schema 1.1 带来了两个新组件assertionstype alternatives,提供xs:assertxs:alternative 元素。它们有一个@test 属性,其中条件和约束被指定为XPath 2.0 表达式


      尽管xs:alternative 显然是为了解决您的问题,但就我而言,我还没有成功地根据元素的位置分配替代类型。 (模式解析器对节点上下文的理解似乎与我基于经过验证的 XML 文档结构所期望的不同。


      无论如何,您可以使用xs:assert 强制执行您的约束:

      <xs:element name="productinfo">
        <xs:complexType>
          <xs:sequence minOccurs="2" maxOccurs="unbounded">
            <xs:element name="informationset">
              <xs:complexType>
                <xs:attribute name="type" use="required">
                  <xs:simpleType>
                    <xs:restriction base="xs:string">
                      <xs:enumeration value="Manufacturer" />
                      <xs:enumeration value="Ingredients" />
                    </xs:restriction>
                  </xs:simpleType>
                </xs:attribute>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
          <xs:assert test="informationset[1]/@type='Manufacturer'" xpathDefaultNamespace="##targetNamespace"/>
          <xs:assert test="informationset[2]/@type='Ingredients'" xpathDefaultNamespace="##targetNamespace"/>
        </xs:complexType>
      </xs:element>
      

      如果架构的命名空间为空,则可能不需要使用属性@xpathDefaultNamespace,但如果架构定义了一个,则必须设置为##targetNamespace,否则元素名称的评估将失败.

      注意:显然,要使其工作,必须使用支持 XML Schema 1.1 的验证器。例如,当使用 OxygenXML 时,您只需在 XML / XML Parser / XML Schema 首选项页面中将默认 XML 模式版本设置为 1.1。使用 Xerces 作为验证器时,必须激活 additional featurehttp://apache.org/xml/features/validation/cta-full-xpath-checking。否则它将无法评估您提出的大部分 XPath,因为默认情况下它使用的子集不足。


      【讨论】:

        【解决方案4】:

        可能http://xsd.stylusstudio.com/2001Aug/post03013.htm 就是您要查找的内容。

        【讨论】:

        • 单独的链接是considered a poor answer,因为它本身没有意义,并且不能保证目标资源将来仍然存在。请尝试至少包含您链接到的信息摘要。
        【解决方案5】:

        在VS中,报错:同名同作用域的元素必须具有相同的类型。
        我觉得 XSD 不能满足你的要求,你可以尝试从另一个方向解决它。例如,使用 xslt 来验证 XML。 XSLT 是基于 xpath 和基于规则的,它可以检查 xml 中的每个地方。
        XSD + XSLT 是一个很好的解决方案,XSD 用于模式检查,XSLT 用于信息检查。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多