如何使用 XSD 基于属性值约束 XML 元素内容类型

How to constrain XML element content type based on an attribute value using XSD

提问人:Miguel Díaz Pestana 提问时间:11/8/2023 更新时间:11/10/2023 访问量:41

问:

我有以下xml文件:

<doc id="JOURNAL/otai/04.03/product/root">
   <field name="name1">8043501d8766ee1199370022482955e0</field>
   <field name="name2">false</field>
   <field name="name3">2023-10-09T093500Z</field>
</doc>

我需要创建一个 XSD 文件,用于检查 xml 文件的有效性,以及根据 name 属性的值检查每个字段元素的内容类型。

例如:

  • 8043501d8766ee1199370022482955e0 的内容类型为 string
  • false 的内容为 boolean 类型。
  • 2023-10-09T093500Z 的内容类型为 date

如果字段节点内容类型与这些类型不匹配,则 XSD 应引发错误,例如,任何应引发错误,因为“whatever”不能强制转换为布尔值,依此类推。

在验证输入 xml 时,XSD 应该如何执行这些检查?

谢谢!

我尝试了很多方法,但没有一个奏效。我正在玩 Type Alternative Schema Component,但我无法让它工作。

这是我尝试过的:

<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Technologies Online Tools 1.0 (https://www.liquid-technologies.com) -->
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="doc">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="field">
          <xs:complexType>
            <xs:simpleContent>
              <xs:extension base="xs:string">
                <xs:attribute name="name" use="required" >
                    <xs:simpleType>
                        <xs:restriction base="xs:string">
                            <xs:enumeration value="name1"/>
                                                        <xs:enumeration value="name2"/>
                                                        <xs:enumeration value="name3"/>
                        </xs:restriction>
                    </xs:simpleType>
                </xs:attribute>
                <xs:attribute name="copyTo" type="xs:string" use="optional" />
              </xs:extension>
            </xs:simpleContent>
          </xs:complexType>
          <xs:alternative test="@name='name2'">
            <xs:element name="field" type="xs:boolean"/>
          </xs:alternative>
        </xs:element>
      </xs:sequence>
      <xs:attribute name="id" type="xs:string" use="required" />
    </xs:complexType>
  </xs:element>
</xs:schema>

如果我尝试验证 xml,则会出现以下错误:

s4s-elt-must-match.1:'field' 的内容必须匹配 (annotation?, (simpleType | complexType)?, (unique | key | keyref)*))。从以下位置开始发现一个问题:替代。

我希望 XSD 根据 name 属性的值验证 field 元素的内容。

例如,将 name2 作为 name 属性值的字段元素只有在字段元素内容可以解析为布尔值时才有效。

XML XSD

评论


答:

1赞 Yitzhak Khabinsky 11/9/2023 #1

请尝试以下使用条件类型分配 (CTA) 的 XSD 1.1。

XML格式

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified">

    <xs:element name="doc">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="unbounded" ref="field"/>
            </xs:sequence>
            <xs:attribute name="id" use="required"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="field" type="xs:anySimpleType">
        <xs:alternative test="@name eq 'name1'" type="StringType"/>
        <xs:alternative test="@name eq 'name2'" type="BooleanType"/>
        <xs:alternative test="@name eq 'name3'" type="DateTimeType"/>
        <xs:alternative type="xs:error"/>
    </xs:element>

    <xs:complexType name="StringType">
        <xs:simpleContent>
            <xs:extension base="xs:string">
                <xs:attributeGroup ref="GrpAttributes"/>
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>

    <xs:complexType name="BooleanType">
        <xs:simpleContent>
            <xs:extension base="xs:boolean">
                <xs:attributeGroup ref="GrpAttributes"/>
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>

    <xs:complexType name="DateTimeType">
        <xs:simpleContent>
            <xs:extension base="xs:dateTime">
                <xs:attributeGroup ref="GrpAttributes"/>
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>

    <xs:attributeGroup name="GrpAttributes">
        <xs:attribute name="name" type="NameAttrType" use="required"/>
        <xs:attribute name="copyTo" type="xs:string"/>
    </xs:attributeGroup>

    <xs:simpleType name="NameAttrType">
        <xs:restriction base="xs:string">
            <xs:whiteSpace value="preserve"/>
            <xs:maxLength value="100"/>
            <xs:enumeration value="name1"/>
            <xs:enumeration value="name2"/>
            <xs:enumeration value="name3"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

评论

0赞 Miguel Díaz Pestana 11/10/2023
它有效。非常感谢。只有一个问题...学习 XSD 1.1 和此类验证的最佳在线资源是什么?再次感谢你!
0赞 Miguel Díaz Pestana 11/10/2023
你好。我忘了再提一件事:“field”元素可以有一个名为“copyTo”的可选属性,类型为“xs:string”。XSD 将如何更改以适应这种情况?谢谢!
0赞 Yitzhak Khabinsky 11/10/2023
我更新了答案并使用了.一探究竟。attributeGroup
1赞 Michael Kay 11/9/2023 #2

在我看来,从错误消息来看,好像您使用的是 XSD 1.0 处理器而不是 XSD 1.1 处理器。

当你解决这个问题时,你将需要改变你的元素。它应该是这样的xs:alternative

<xs:alternative test="@name='name2'">
  <xs:complexType>
    <xs:simpleContent>
      <xs:extension base="xs:boolean">

此外,字段元素的主要(控制)类型需要包含所有可能性(也许),并且所有特定情况都需要是一般情况的子类型。xs:anyType

评论

0赞 Miguel Díaz Pestana 11/10/2023
好的,我会尝试的。非常感谢!