Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSD: A <xs:choice> equivalent for attributes

Tags:

xml

xsd

I wish to create an XML document in which one of its elements must be defined with one of two known attributes, but not both.

For example, I would like to define a "webAddress" element as follows:

 <xs:element name="webAddress">
     <xs:complexType>
         <xs:attribute name="hostName" type="xs:string"/>
         <xs:attribute name="hostAddress" type="xs:string"/>
     </xs:complexType>
 </xs:element>

but I only want a user to be able to define either a hostName attribute (e.g., hostName= ") or a hostAddress (e.g., hostAddress="") attribute, but not both. It appears that the construct accomplishes this for elements. Is there a functional equivalent for attributes, or is there a better way to approach this?

If found that we can't do this with W3C XML Schema. We can use an embedded schematron rule but can we do it on choice element by checking element and attribute together? For example something like this:

<xs:choice>
     <xs:element name="webAddress">
         <xs:complexType>
             <xs:attribute name="hostName" type="xs:string"/>
         </xs:complexType>
     </xs:element>
     <xs:element name="webAddress">
         <xs:complexType>
             <xs:attribute name="hostAddress" type="xs:string"/>
         </xs:complexType>
     </xs:element>
  </xs:choice>
like image 208
Nick Avatar asked Jan 23 '26 14:01

Nick


1 Answers

You could use "type" substitution, e.g.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <!-- Some abstract type - it might define some common parts too. It is abstract and cannot be used directly for instance -->
    <xs:complexType name="abstractType" abstract="true"/>

    <!-- First "children" type of abstract type-->
    <xs:complexType name="hostNameType">
        <xs:complexContent>
            <!-- it is derived from abstractType and adds attribute hostName -->
            <xs:extension base="abstractType">
                <xs:attribute name="hostName" type="xs:string" use="required" />
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <!-- Second "children" type of abstract type -->
    <xs:complexType name="hostAddressType">
        <xs:complexContent>
            <!-- it is also derived from abstractType and adds attribute hostAddress -->
            <xs:extension base="abstractType">
                <xs:attribute name="hostAddress" type="xs:string" use="required" />
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <!-- Element of abstractType -->
    <xs:element name="webAddress" type="abstractType" />

</xs:schema>

In instance document you have to specify type which is actually used:

<?xml version="1.0" encoding="UTF-8"?>
<!-- by xsi:type you defined which "concrete" type is really used -->
<webAddress xsi:type="hostNameType" hostName="String" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>

or

<?xml version="1.0" encoding="UTF-8"?>
<webAddress xsi:type="hostAddressType" hostAddress="xxxx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>

But the definition is a bit verbose and also it is not obvious on the first sight what type "webAddress" really could be. But it could be a way for you.

like image 198
Jirka Š. Avatar answered Jan 25 '26 08:01

Jirka Š.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!