<xsd:schema targetNamespace="Domestic" xmlns:schema="Domestic" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
<xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />
<xsd:element name="Domestic">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ID" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="sqltypes:nvarchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth">
<xsd:maxLength value="15" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ForeignLanguage" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="sqltypes:nvarchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth">
<xsd:maxLength value="50" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Both elements has the minOccurs="0" attribute because the Domestic columns were defined nullable.
minOccurs is an XML Representation Attribute that determines the minimum number of times that an element is required to appear in a content model. If the value of this attribute is 0, then the element is optional.
If we set this attribute to 1, we solved the first issue.
Well, if exists the minOccurs attribute, will exists the analogous maxOccurs
maxOccurs is an XML Representation Attribute that determines the maximum number of times that an element may appear in a content model. The value of this attribute may be a positive integer value or the term 'unbounded' to indicate that there is no maximum number of occurrences.
If we set this attribute to 2, we solved the last issue.
So I modified the schema in this way:
-- Remove the schema from the XML column
ALTER TABLE dbo.Contacts
ALTER COLUMN otherattributes XML;
-- Drop the schema collection
DROP XML SCHEMA COLLECTION dbo.ContactOtherAttributes;
-- Add the modified schema to the schema collection
DECLARE @mySchema NVARCHAR(MAX);
SET @mySchema = N'<xsd:schema targetNamespace="Domestic" xmlns:schema="Domestic" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
<xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />
<xsd:element name="Domestic">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ID" minOccurs="1">
<xsd:simpleType>
<xsd:restriction base="sqltypes:nvarchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth">
<xsd:maxLength value="15" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ForeignLanguage" minOccurs="1" maxOccurs="2">
<xsd:simpleType>
<xsd:restriction base="sqltypes:nvarchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth">
<xsd:maxLength value="50" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>';
CREATE XML SCHEMA COLLECTION dbo.ContactOtherAttributes as @mySchema;
GO
-- Alter the XML column from a well-formed state to a schema-validated one
ALTER TABLE dbo.Contacts
ALTER COLUMN otherattributes XML(dbo.ContactOtherAttributes);
Now if I try to insert an invalid attribute, I will receive an error:
INSERT INTO dbo.Contacts VALUES(7, N'Ron', 1, N'
<Domestic xmlns="Domestic">
<ForeignLanguage>German</ForeignLanguage>
</Domestic>');
/* Output:
Msg 6965, Level 16, State 1, Line 1
XML Validation: Invalid content. Expected element(s):Domestic:ID where element 'Domestic:ForeignLanguage' was specified. Location: /*:Domestic[1]/*:ForeignLanguage[1]
*/
INSERT INTO dbo.Contacts VALUES(8, N'Louis', 1, N'
<Domestic xmlns="Domestic">
<ID>012345678901234</ID>
</Domestic>');
/* Output:
Msg 6908, Level 16, State 1, Line 1
XML Validation: Invalid content. Expected element(s): Domestic:ID. Location: /*:Domestic[1]
*/
INSERT INTO dbo.Contacts VALUES(9, N'Kent', 1, N'
<Domestic xmlns="Domestic">
</Domestic>');
/* Output:
Msg 6908, Level 16, State 1, Line 1
XML Validation: Invalid content. Expected element(s): Domestic:ID. Location: /*:Domestic[1]
*/
INSERT INTO dbo.Contacts VALUES(10, N'Andrew', 1, N'
<Domestic xmlns="Domestic">
<ID>012345678901234</ID>
<ForeignLanguage>Spanish</ForeignLanguage>
<ForeignLanguage>German</ForeignLanguage>
<ForeignLanguage>Italian</ForeignLanguage>
</Domestic>');
/* Output:
Msg 6923, Level 16, State 1, Line 1
XML Validation: Unexpected element(s): Domestic:ForeignLanguage. Location: /*:Domestic[1]/*:ForeignLanguage[3]
*/
While valid XML fragments will be accepted:
INSERT INTO dbo.Contacts VALUES(11, N'Aaron', 1, N'
<Domestic xmlns="Domestic">
<ID>012345678901234</ID>
<ForeignLanguage>Spanish</ForeignLanguage>
</Domestic>');
INSERT INTO dbo.Contacts VALUES(12, N'Tom', 1, N'
<Domestic xmlns="Domestic">
<ID>012345678901234</ID>
<ForeignLanguage>Spanish</ForeignLanguage>
<ForeignLanguage>French</ForeignLanguage>
</Domestic>');
As you can see, using appropriately the minOccurs and maxOccurs XML Representation Attributes is possible to design an XML Schema with a great fine control on the the XML fragments permitted.
I want to thank Itzik, Dejan and Roger again for their invaluable work