Attribute/element co-occurrence constraint in XML

2020-05-24 04:49发布

Is it possible to create an XML Schema which imposes a co-occurrence constraint to an attribute/element pair?

<primitive-list>
    <primitive name="P1">
        <definition><!-- primitive specification --></definition>
    </primitive>
    <primitive name="P2">
        <definition><!-- primitive specification --></definition>
    </primitive>

    <!-- other common primitives are specified here-->

<primitive-list>

<composite-list>
    <composite name="C1">
        <primitive ref="P1" />
        <primitive ref="P2" />
        <primitive>
            <definition><!-- inline primitive specification --></definition>
        </primitive>        
    </composite>

    <!-- Other compisites are specified here-->

</composite-list>

The schema should imply that:

  • If a primitive element is specified inside a primitive-list element, then it should contain the name attribute and the embedded definition element, but not the ref attribute.
  • If a primitive element is specified in the composite element, then it should contain either the ref attribute or the definition element. The name is allowed in neither cases.

I am pretty sure that it is possible since the element element in XML Schema itself behaves just like that. So anybody who is in possession of that sacred knowledge please share :-)

Thank you in advance.

标签: xml schema xsd
3条回答
狗以群分
2楼-- · 2020-05-24 05:34

Ok, here is a sample, this gets you close, the only thing not handled is the primitive and ref attribute on the composite. Looking at what I can find, it does almost seem to be impossible to do this via a schema. I'm not 100% sure though, but in all cases where I have seen this done, a schema like this is used for high level validation and process code is then used to validate the individual items.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://www.iowacomputergurus.com/stackoverflow/samples/xsdexample"
    elementFormDefault="qualified"
    xmlns="http://www.iowacomputergurus.com/stackoverflow/samples/xsdexample"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>

  <xs:complexType name="PrimitiveType">
    <xs:sequence>
      <xs:element name="definition" type="xs:string" minOccurs="1" maxOccurs="1" />
    </xs:sequence>
    <xs:attribute name ="name" use="required" type="xs:string" />
  </xs:complexType>

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
          <xs:element name="primitive-list" minOccurs="1" maxOccurs="1">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="primitive" type="PrimitiveType" minOccurs="1" maxOccurs="unbounded" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
          <xs:element name="composite-list" minOccurs="1" maxOccurs="1">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="composite">
                  <xs:complexType>
                    <xs:sequence>
                      <xs:element name="primitive" minOccurs="1" maxOccurs="unbounded">
                        <xs:complexType>
                          <xs:sequence>
                            <xs:element name="definition" minOccurs="0" maxOccurs="1" />
                          </xs:sequence>
                          <xs:attribute name="ref" use="optional" type="xs:string" />
                        </xs:complexType>
                      </xs:element>
                    </xs:sequence>
                    <xs:attribute name="name" type="xs:string" use="required" />
                  </xs:complexType>
                </xs:element>
              </xs:sequence>
            </xs:complexType>
          </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>  
</xs:schema>
查看更多
混吃等死
3楼-- · 2020-05-24 05:38

After searching on the Internet and digging in some books I figured out how to implement that.

First of all we need to define a generic type which accommodates all attributes and elements from both kinds of the primitive element. It is assumed that the definition element is defined somewhere else.

<xs:complexType name="primitive" abstract="true">
    <xs:sequence>
        <xs:element ref="definition" minOccurs="0" maxOccurs="unbounded" />
    </xs:sequence>
    <xs:attribute name="name" type="xs:Name" />
    <xs:attribute name="ref" type="xs:Name" />
</xs:complexType>

Then we define two primitive subtypes to be used in the primitive-list and composite respectively.

<xs:complexType name="public-primitive">
    <xs:complexContent>
        <xs:restriction base="primitive">
            <xs:sequence>
                <xs:element ref="definition" minOccurs="1" maxOccurs="unbounded" />
            </xs:sequence>
            <xs:attribute name="name" type="xs:Name" use="required" />
            <xs:attribute name="ref" use="prohibited" />
        </xs:restriction>
    </xs:complexContent>
</xs:complexType>

<xs:complexType name="private-primitive">
    <xs:complexContent>
        <xs:restriction base="primitive">
            <xs:sequence>
                <xs:element ref="definition" minOccurs="0" maxOccurs="unbounded" />
            </xs:sequence>
            <xs:attribute name="name" use="prohibited" />
        </xs:restriction>
    </xs:complexContent>
</xs:complexType>

Now we can define the primitive-list and composite elements in terms of these complex types as follows:

<xs:element name="primitive-list">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="primitive" type="public-primitive" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

<xs:element name="composite">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="primitive" type="private-primitive" maxOccurs="unbounded">
                <xs:key name="definition-ref--co-occurrence--constraint">
                    <xs:selector xpath="." />
                    <xs:field xpath="definition|@ref" />
                </xs:key>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:element>

Let's take a look at the original schema requirements and see how they are enforced:

  • If a primitive element is specified inside a primitive-list element, then it should contain the name attribute and the embedded definition element, but not the ref attribute.

This requirement is enforced by the definition of the public-primitive type alone.

  • If a primitive element is specified in the composite element, then it should contain either the ref attribute or the definition element. The name is allowed in neither cases.

This requirement is enforced by the definition of the private-primitive type and by the xs:key element specified in the primitive element defined inside of the composite element. The xs:key guaranties that either ref or definition is present but not both.

查看更多
▲ chillily
4楼-- · 2020-05-24 05:41

Yes, this is possible. When creating your XML Schema, you will be creating a complex type for each scenario, based on where in the XML tree the element is defined.

If I get a moment later on i can try to actually get an example out here for you, I just don't have the time to get it all formatted perfectly for posting here.

I personally highly recommend looking at this w3schools tutorial, as it should get you what you need.

查看更多
登录 后发表回答