Поддержка привязки элемента Choice

Этот раздел посвящен технологии прежних версий. Веб-службы XML и клиенты веб-служб XML должны создаваться с использованием Windows Communication Foundation.

Платформа .NET Framework обеспечивает поддержку привязки для элемента <choice>.

Если отдельные элементы выбора отличаются как по типам, так и по именам, программа Xsd.exe применяет к открытому члену только атрибут XmlElementAttribute. Если они отличаются только по имени, программа Xsd.exe дополнительно применяет атрибут XmlChoiceIdentifierAttribute и вставляет дополнительную логику для выбора.

Объяснение

Элемент <choice> содержит не менее двух дочерних элементов, каждый из которых представляет элемент или группу элементов. Он указывает, что, в определенном документе экземпляра, в указанной позиции может появляться только одна из этих сущностей. Варианты выбора могут различаться по имени элемента. Они могут также отличаться типами элементов и, если вариант выбора является группированием (например, элемент <group>), количеством элементов.

Неоднозначные сочетания групп приводят к непредсказуемым результатам.

Различение по типу

Самый простой случай возникает, когда различаются как типы, так и имена индивидуальных элементов. Рассмотрим следующее определение элемента <choice>:

<xsd:choice>
    <xsd:element name="numberA" type="xsd:int"/>
    <xsd:element name="numberB" type="xsd:decimal"/>
</xsd:choice>

На языке C# программа Xsd.exe преобразует содержимое этой схемы XML в следующий код:

[System.Xml.Serialization.XmlElementAttribute("numberA", typeof(int))]
[System.Xml.Serialization.XmlElementAttribute("numberB", typeof(System.Decimal))]
public object Item;

В созданном коде полю назначен тип object, однако оно также имеет два атрибута XmlElementAttribute. Один атрибут указывает, что этот тип следует сериализовать как экземпляр int; другой указывает, что тип следует сериализовать как экземпляр System.Decimal. В этом случае класс XmlSerializer использует тип, назначенный объекту в это время. С приведенным ниже присвоением объекту int используется элемент <numberA>:

Item = 1;

Если варианты выбора имеют различные типы данных схемы XML, программа Xsd.exe выполняет привязку каждого типа данных к отдельному классу. Так как System.Object является корневым классом в иерархии типов платформы .NET Framework, созданное поле всегда принадлежит к базовому типу. Класс Object является самым универсальным общим базовым типом.

Если все варианты выбора являются производными от общего типа данных, определенного в схеме XML, например через конструкцию <extension>, то тип поля является привязкой этого типа данных. Например, допустим, что элемент <choice> предлагает выбор между элементом <a> типа DerivedTypeA и элементом <b> типа DerivedTypeB, и оба типа являются расширением типа BaseType. В C# создается следующий исходный код:

[System.Xml.Serialization.XmlElementAttribute("a", typeof(DerivedTypeA))]
[System.Xml.Serialization.XmlElementAttribute("b", typeof(DerivedTypeB))]
public BaseType Item;

Различение по имени

Если типы вариантов выбора не различаются, при создании документа экземпляра с помощью атрибута XmlChoiceIdentifierAttribute создается выбор по имени элемента. Рассмотрим следующее определение элемента <choice>:

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

Программа Xsd.exe преобразует содержимое этой схемы XML в следующий код:

[System.Xml.Serialization.XmlElementAttribute("stringA", typeof(string))]
[System.Xml.Serialization.XmlElementAttribute("stringB", typeof(string))]
[System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemElementName")]
public string Item;

[System.Xml.Serialization.XmlIgnoreAttribute()]
public ItemChoiceType ItemElementName;
...
public enum ItemChoiceType {
        
    stringA,
        
    stringB,
}

Поле Item имеет атрибут XmlChoiceIdentifier в дополнение к двум атрибутам XmlElement. Параметром атрибута XmlChoiceIdentifier является имя экземпляра перечисления. Соответствующий тип перечисления содержит варианты выбора элемента. Экземпляр перечисления имеет атрибут XmlIgnore, поэтому его значение не может быть сериализовано.

Разработчик должен затем написать код для присвоения значения экземпляру перечисления. В следующей строке это сделано для объекта с именем i.

i.ItemElementName = ItemChoiceType.stringA;

Дополнительные сведения см. в описании класса XmlChoiceIdentifierAttribute.

Example

Следующий входной документ схемы XML демонстрирует различные применения группирования <choice>.

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
            targetNamespace="http://example.org/" xmlns="http://example.org/" elementFormDefault="qualified">
    <xsd:element name="choicesInstance" type="MyChoicesType"/>

    <xsd:complexType name="MyComplexType">
        <xsd:sequence>
            <xsd:element name="field1" type="xsd:string"/>
            <xsd:element name="field2" type="xsd:string"/>
        </xsd:sequence>
    </xsd:complexType>

    <xsd:complexType name="DerivedTypeA">
        <xsd:complexContent>
            <xsd:extension base="MyComplexType">
                 <xsd:attribute name="extraInfoForA" type="xsd:string"/>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="DerivedTypeB">
        <xsd:complexContent>
            <xsd:extension base="MyComplexType">
                 <xsd:attribute name="extraInfoForB" type="xsd:string"/>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="MyChoicesType">
        <xsd:sequence>
            <xsd:element name="name" type="xsd:string"/>
            <xsd:choice>
                <xsd:element name="stringA" type="xsd:string"/>
                <xsd:element name="stringB" type="xsd:string"/>
            </xsd:choice>
            <xsd:choice>
                <xsd:element name="numberA" type="xsd:int"/>
                <xsd:element name="numberB" type="xsd:decimal"/>
            </xsd:choice>
            <xsd:choice>
                <xsd:element name="complexA" type="MyComplexType"/>
                <xsd:element name="complexB" type="MyComplexType"/>
                <xsd:element name="simpleC"  type="xsd:string"/>
            </xsd:choice>
            <xsd:choice>
                <xsd:element name="derivedA" type="DerivedTypeA"/>
                <xsd:element name="derivedB" type="DerivedTypeB"/>
            </xsd:choice>
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

Классы C#, созданные на основе приведенного выше документа схемы XML:

[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://example.org/")]
[System.Xml.Serialization.XmlRootAttribute("choicesInstance", Namespace="http://example.org/", IsNullable=false)]
 public class MyChoicesType {
        
     public string name;
        
    [System.Xml.Serialization.XmlElementAttribute("stringA", typeof(string))]
    [System.Xml.Serialization.XmlElementAttribute("stringB", typeof(string))]
    [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemElementName")]
    public string Item;
        
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public ItemChoiceType ItemElementName;
        
    [System.Xml.Serialization.XmlElementAttribute("numberA", typeof(int))]
    [System.Xml.Serialization.XmlElementAttribute("numberB", typeof(System.Decimal))]
    public object Item1;
        
    [System.Xml.Serialization.XmlElementAttribute("complexA", typeof(MyComplexType))]
    [System.Xml.Serialization.XmlElementAttribute("complexB", typeof(MyComplexType))]
    [System.Xml.Serialization.XmlElementAttribute("simpleC", typeof(string))]
    [System.Xml.Serialization.XmlChoiceIdentifierAttribute("Item2ElementName")]
    public object Item2;
        
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public Item2ChoiceType Item2ElementName;
        
    [System.Xml.Serialization.XmlElementAttribute("derivedA", typeof(DerivedTypeA))]
    [System.Xml.Serialization.XmlElementAttribute("derivedB", typeof(DerivedTypeB))]
    public MyComplexType Item3;
}
    
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://example.org/", IncludeInSchema=false)]
public enum ItemChoiceType {
        
    stringA,
        
    stringB,
}
    
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://example.org/")]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(DerivedTypeB))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(DerivedTypeA))]
public class MyComplexType {
        
    public string field1;
        
    public string field2;
}
    
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://example.org/")]
    public class DerivedTypeA : MyComplexType {
        
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string extraInfoForA;
    }
    
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://example.org/")]
public class DerivedTypeB : MyComplexType {
        
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string extraInfoForB;
}
    
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://example.org/", IncludeInSchema=false)]
public enum Item2ChoiceType {
        
    complexA,
        
    complexB,
        
    simpleC,
}

Основной документ схемы XML, созданный из сборки, скомпилированной на основе предыдущего исходного кода C#. (Не показан второй файл .xsd, который создается для задания произвольных глобальных элементов для сложных типов.)

<xs:schema xmlns:tns="http://example.org/" elementFormDefault="qualified" targetNamespace="http://example.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="choicesInstance" type="tns:MyChoicesType" />
  <xs:complexType name="MyChoicesType">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" name="name" type="xs:string" />
      <xs:choice minOccurs="1" maxOccurs="1">
        <xs:element minOccurs="0" maxOccurs="1" name="stringA" type="xs:string" />
        <xs:element minOccurs="0" maxOccurs="1" name="stringB" type="xs:string" />
      </xs:choice>
      <xs:choice minOccurs="1" maxOccurs="1">
        <xs:element minOccurs="1" maxOccurs="1" name="numberA" type="xs:int" />
        <xs:element minOccurs="1" maxOccurs="1" name="numberB" type="xs:decimal" />
      </xs:choice>
      <xs:choice minOccurs="1" maxOccurs="1">
        <xs:element minOccurs="0" maxOccurs="1" name="complexA" type="tns:MyComplexType" />
        <xs:element minOccurs="0" maxOccurs="1" name="simpleC" type="xs:string" />
        <xs:element minOccurs="0" maxOccurs="1" name="complexB" type="tns:MyComplexType" />
      </xs:choice>
      <xs:choice minOccurs="1" maxOccurs="1">
        <xs:element minOccurs="0" maxOccurs="1" name="derivedB" type="tns:DerivedTypeB" />
        <xs:element minOccurs="0" maxOccurs="1" name="derivedA" type="tns:DerivedTypeA" />
      </xs:choice>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="MyComplexType">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" name="field1" type="xs:string" />
      <xs:element minOccurs="0" maxOccurs="1" name="field2" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="DerivedTypeA">
    <xs:complexContent mixed="false">
      <xs:extension base="tns:MyComplexType">
        <xs:attribute name="extraInfoForA" type="xs:string" />
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
  <xs:complexType name="DerivedTypeB">
    <xs:complexContent mixed="false">
      <xs:extension base="tns:MyComplexType">
        <xs:attribute name="extraInfoForB" type="xs:string" />
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
</xs:schema>

Возможные атрибуты Поддержка привязки

id

Программа Xsd.exe пропускает атрибут id, который предназначен для обеспечения уникального идентификатора.

maxOccurs

Для элемента <choice> значение maxOccurs, равное 0, интерпретируется программой Xsd.exe как 1, а значение maxOccurs, превышающее 1, интерпретируется как unbounded.

Для значения 1 программа Xsd.exe создает код, рассматриваемый в разделах Differentiating by Type и Differentiating by Name.

Для значения unbounded программа Xsd.exe выполняет такую же привязку, но поле, создаваемое для варианта, представляет собой массив соответствующего типа. Если все варианты имеют одинаковый тип, второе поле (идентифицируемое атрибутом XmlChoiceIdentifier) представляет собой массив созданного типа перечисления. Каждый элемент второго массива выбирает имя элемента для соответствующего элемента в первом массиве.

См. описание атрибута Поддержка привязки атрибута MaxOccurs.

minOccurs

При создании исходного кода из документа схемы XML программа Xsd.exe не обрабатывает атрибут minOccurs, примененный к элементу <choice>.

При создании документа схемы XML из классов программа Xsd.exe создает элемент <choice> со значением атрибута minOccurs, равным 1, если выбор представляет одиночный объект, или 0, если выбор представляет массив.

См. описание атрибута Поддержка привязки атрибута MinOccurs.

Возможные родительские элементы: <choice>, <complexType>, <extension>, <group>, <restriction>, <sequence>

Возможные дочерние элементы: <annotation>, <any>, <element>, <group>, <sequence>, <choice>

См. также

Справочник

XmlSchemaChoice