XML Schema How to Restrict Attribute by Enumeration
I have the following XML Tag
<price currency="euros">20000.00</price>
How do I restrict the currency attribute to one the following:
- euros
- pounds
- dollars
AND the price to a double?
I just get an error when I try to a type on both, here's what I've got so far:
<xs:element name="price">
<xs:complexType>
<xs:attribute name="currency">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="pounds" />
<xs:enumeration value="euros" />
<xs:enumeration value="dollars" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
Solution 1:
The numerical value seems to be missing from your price definition. Try the following:
<xs:simpleType name="curr">
<xs:restriction base="xs:string">
<xs:enumeration value="pounds" />
<xs:enumeration value="euros" />
<xs:enumeration value="dollars" />
</xs:restriction>
</xs:simpleType>
<xs:element name="price">
<xs:complexType>
<xs:extension base="xs:decimal">
<xs:attribute name="currency" type="curr"/>
</xs:extension>
</xs:complexType>
</xs:element>
Solution 2:
New answer to old question
None of the existing answers to this old question address the real problem.
The real problem was that xs:complexType
cannot directly have a xs:extension
as a child in XSD. The fix is to use xs:simpleContent
first. Details follow...
Your XML,
<price currency="euros">20000.00</price>
will be valid against either of the following corrected XSDs:
Locally defined attribute type
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="price">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute name="currency">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="pounds" />
<xs:enumeration value="euros" />
<xs:enumeration value="dollars" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
Globally defined attribute type
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="currencyType">
<xs:restriction base="xs:string">
<xs:enumeration value="pounds" />
<xs:enumeration value="euros" />
<xs:enumeration value="dollars" />
</xs:restriction>
</xs:simpleType>
<xs:element name="price">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute name="currency" type="currencyType"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
Notes
- As commented by @Paul, these do change the content type of
price
fromxs:string
toxs:decimal
, but this is not strictly necessary and was not the real problem. - As answered by @user998692, you could separate out the
definition of currency, and you could change to
xs:decimal
, but this too was not the real problem.
The real problem was that xs:complexType
cannot directly have a xs:extension
as a child in XSD; xs:simpleContent
is needed first.
A related matter (that wasn't asked but may have confused other answers):
How could price
be restricted given that it has an attribute?
In this case, a separate, global definition of priceType
would be needed; it is not possible to do this with only local type definitions.
How to restrict element content when element has attribute
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="priceType">
<xs:restriction base="xs:decimal">
<xs:minInclusive value="0.00"/>
<xs:maxInclusive value="99999.99"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="price">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="priceType">
<xs:attribute name="currency">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="pounds" />
<xs:enumeration value="euros" />
<xs:enumeration value="dollars" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
Solution 3:
you need to create a type and make the attribute of that type:
<xs:simpleType name="curr">
<xs:restriction base="xs:string">
<xs:enumeration value="pounds" />
<xs:enumeration value="euros" />
<xs:enumeration value="dollars" />
</xs:restriction>
</xs:simpleType>
then:
<xs:complexType>
<xs:attribute name="currency" type="curr"/>
</xs:complexType>