Share via


MaxOccurs Attribute Binding Support

The .NET Framework provides partial binding support for the maxOccurs attribute.

For most elements that may specify a maxOccurs attribute, Xsd.exe interprets a value of 0 as 1, producing a non-array field, and a value greater than 1 as unbounded, producing an array field. The behavior varies between elements.

Explanation

The maxOccurs and minOccurs attributes constrain how many times in succession the specified entity can appear in the corresponding position in an XML instance document.

These attributes appear only within complex type definitions. Therefore, for an <element> or <group> element to have these attributes, the element must be a local declaration or a reference to a global declaration, not the global declaration itself.

For binding classes with XML Schema complex types, the .NET Framework does not provide a direct programming language equivalent to the maxOccurs or minOccurs attribute.

When generating source code from an XML Schema document or performing the reverse translation, Xsd.exe interprets the maxOccurs attribute differently based on the XML Schema definition language element in which it appears. The following table explains the interpretations by element:

Element Interpretation

<element>

Possible values:

  • 1: Xsd.exe produces a field of the type corresponding to the element's data type.

  • 0: Xsd.exe fails to process a value of 0, instead treating the value as the default 1.

  • unbounded: Xsd.exe produces a field that is an array of the type corresponding to the element's data type.

  • Any integer greater than 1: As with a value of unbounded, Xsd.exe produces a field that is an array of the type corresponding to the element's data type. You can enforce a value greater than 1 by validating an XML document with the XmlValidatingReader class against an XML Schema document represented by the SOM.

<group>

For the <group> element, a maxOccurs value of 0 is interpreted by Xsd.exe as 1, and a maxOccurs value greater than 1 is interpreted as unbounded.

However, by default Xsd.exe treats a maxOccurs="unbounded" value for the <group> element as if each of the child elements was specified with maxOccurs="unbounded". For example, if each of the children of the <group> element is an <element> element, then each field produced in the ensuing class is an array of the appropriate type.

To properly import schemas containing groups with maxOccurs greater than 1, it is recommended to use the /order command line option with Xsd.exe. When this option is used, the entire group is imported as a single array with multiple XmlElementAttribute attributes applied, one for each element in the group. The type of the array is determined by the types of the elements – the type will be the derived-most type that all elements can be assigned to. That is, if a group contains elements of types Type1 and Type2 that both derive from TypeBase, the array will be of type TypeBase. If there is no common base type, the array will be of type Object. For a related example, see the <sequence> example at the bottom of this topic.

<all>

Any value for the maxOccurs attribute other than 1 is invalid. Xsd.exe reports an error for an invalid value.

<any>

Possible values:

  • 1: Xsd.exe produces a field of type System.Xml.XmlElement, with an attribute System.Xml.Serialization.XmlAnyElementAttribute. This attribute allows a class to represent arbitrary XML elements without binding them to non-XML types identified by other possible class members.

  • 0: Xsd.exe fails to process a value of 0, instead treating the value as the default 1.

  • unbounded: Xsd.exe produces an XmlElement array, with an XmlAnyElement attribute.

  • Any integer greater than 1: As with a value of unbounded, Xsd.exe produces an XmlElement array, with an XmlAnyElement attribute. You can enforce a value greater than 1 by validating an XML document with the XmlValidatingReader class against an XML Schema document represented by the SOM.

<choice>

The <choice> element contains two or more child elements, each representing an element or group of elements. It indicates that, in a given instance document, only one of those entities can appear in the specified position. The choices must differ by element name; optionally, they differ by type and, for a group, by number. For more information, see the <choice> element.

For the <choice> element, as for the <element> and <any> elements, a maxOccurs value of 0 is interpreted by Xsd.exe as 1, and a maxOccurs value greater than 1 is interpreted as unbounded.

For a value of 1, Xsd.exe produces a field of the common type or a common base type. For each of the choices, an attribute of type XmlElementAttribute is applied to the field. If the choices do not differ by type, Xsd.exe generates an attribute of type XmlChoiceIdentifierAttribute, specifying a second field with an enumeration type that represents each of the choices. This mechanism is explained in detail, along with examples, with the <choice> element.

For a value of unbounded, Xsd.exe performs the same binding, except the generated field for the choice is an array of an appropriate type. If all the choices have the same type, the second field (identified by the XmlChoiceIdentifier attribute) is an array of the generated enumeration type. Each element in the second array chooses the element name for the corresponding element in the first array.

<sequence>

For the <sequence> element, as for most of the preceding elements, a maxOccurs value of 0 is interpreted by Xsd.exe as 1, and a maxOccurs value greater than 1 is interpreted as unbounded.

However, Xsd.exe treats a maxOccurs="unbounded" value for the <sequence> element as if each of the child elements was specified with maxOccurs="unbounded". For example, if each of the children of the <sequence> element is an <element> element, then each field produced in the ensuing class is an array of the appropriate type. Xsd.exe would bind this field structure to a <sequence maxOccurs="1"> element containing a given number of <element maxOccurs="unbounded"> elements if it performed a reverse translation to a new XSD document.

XmlElementAttribute attributes applied, one for each element in the group. The type of the array is determined by the types of the elements – the type will be the derived-most type that all elements can be assigned to. That is, if a group contains elements of types Type1 and Type2 that both derive from TypeBase, the array will be of type TypeBase. If there is no common base type, the array will be of type Object. For a related example, see the <sequence> example at the bottom of this topic.

When generating an XML Schema document from a set of classes in an assembly, Xsd.exe reverses the preceding conversions, producing a maxOccurs value of 1 from a single instance and a maxOccurs value of unbounded from an array.

While Xsd.exe binds a maxOccurs value of unbounded to an array, it binds a maxOccurs value of 1 to the designated parent element, if any, of an array.

A schema data type, with a name that begins with ArrayOf, is created to represent the array's parent element if the default System.Xml.Serialization.XmlArrayAttribute is applied to the array. If an System.Xml.Serialization.XmlElementAttribute instead is applied to an array, the array elements appear in an instance document as children of the element that binds to the class. For more information on array bindings, see Controlling XML Serialization Using Attributes.

More on array bindings. To understand the translation of a value greater than 1 to an array, consider the difference between declaring an object of a certain type and assigning a value (literally a memory location in the stack or the heap) to that object. Start with the following XSD element:

<xsd:element minOccurs="5" maxOccurs="5" name="items" type="xsd:token" />

Manually writing code, you would not express the array size of five in the type declaration, which would be: public string[] items. Instead you would express the array size when assigning a value: items = new string[5].

The only kinds of source code Xsd.exe produces from an XML schema are type and field declarations and metadata that can be applied to types and fields as attributes. Assigning values to objects extends beyond that scope.

The place to enforce a value greater than 1 is by validating an XML document with the XmlValidatingReader class against an XML Schema document represented by the Schema Object Model (SOM). The SOM uses the XmlSchemaParticle.MaxOccurs and XmlSchemaParticle.MaxOccursString properties, both of which apply to all elements that can contain a maxOccurs attribute.

Example

Input XML schema <choice> element found within a complex type definition:

<xsd:choice maxOccurs="unbounded">
    <xsd:element name="stringA" type="xsd:string"/>
    <xsd:element name="stringB" type="xsd:string"/>
</xsd:choice>

Relevant passages from the C# class generated from the preceding XML Schema document, plus the enumeration representing the element choices, (assuming a target namespace of http://example.org/):

    [System.Xml.Serialization.XmlElementAttribute("stringA", typeof(string))]
    [System.Xml.Serialization.XmlElementAttribute("stringB", typeof(string))]
    [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")]
    public string[] Items;
        
    [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")]
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public ItemsChoiceType[] ItemsElementName;
...
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://example.org/", IncludeInSchema=false)]
public enum ItemsChoiceType {
    stringA,
    stringB,
}

The complex type generated from a class compiled from the preceding C# source code is effectively equivalent to the original complex type.

<sequence>

Example

Input XML Schema document containing a sequence with maxOccurs greater than1:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
      xmlns="http://example.org/" targetNamespace="http://example.org/" elementFormDefault="qualified">
  <xsd:element name="ComplexInstance">
   <xsd:complexType>
     <xsd:sequence maxOccurs="unbounded">
       <xsd:element name="Field1" type="xsd:token"/>
       <xsd:element name="Field2" type="xsd:int" />
     </xsd:sequence>
   </xsd:complexType>
  </xsd:element>
</xsd:schema>

C# class generated from the preceding XML Schema document without any command line options:

[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://example.org/")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://example.org/", IsNullable=false)]
public class ComplexInstance {        
    [System.Xml.Serialization.XmlElementAttribute("Field1", DataType="token")]
    public string[] Field1;
        
    [System.Xml.Serialization.XmlElementAttribute("Field2")]
    public int[] Field2;
}

XML Schema complex type generated from an assembly compiled from the preceding C# source:

<xs:complexType name="ComplexInstance">
  <xs:sequence>
    <xs:element minOccurs="0" maxOccurs="unbounded" name="Field1" type="xs:token" />
    <xs:element minOccurs="0" maxOccurs="unbounded" name="Field2" type="xs:int" />
  </xs:sequence>
</xs:complexType>

As you can see, the resulting schema is not equivalent to the original schema. To properly import a schema having sequences with maxOccurs greater than1, use the /order command line option, resulting in the following:

[System.Xml.Serialization.XmlTypeAttribute

(Namespace="http://example.org/")]

[System.Xml.Serialization.XmlRootAttribute

(Namespace="http://example.org/", IsNullable=false)]

public partial class ComplexInstance

{

/// <remarks/>

[System.Xml.Serialization.XmlElementAttribute

("Field1", typeof(string), DataType="token", Order=0)]

[System.Xml.Serialization.XmlElementAttribute("Field2",

typeof(int), Order=0)]

public object[] Items;

}

Possible containing elements: <all>, <any>, <choice>, <element>, <group>, <sequence>

See Also

Reference

XmlSchemaParticle.MaxOccurs
XmlSchemaParticle.MaxOccursString
XmlSchemaAll
XmlSchemaAny
XmlSchemaChoice
XmlSchemaElement
XmlSchemaGroupRef
XmlSchemaSequence