Compartir a través de


Compatibilidad con enlaces del elemento Choice

Este tema es específico de una tecnología heredada. Ahora, los servicios Web XML y los clientes de servicios Web XML deben crearse con Windows Communication Foundation.

.NET Framework proporciona compatibilidad de enlace para el elemento <choice> .

Si los tipos de elementos choice individuales son distintos, así como sus nombres, Xsd.exe solo aplica atributos XmlElementAttribute a un miembro público. Si solo son distintos los nombres, Xsd.exe aplica además un atributo XmlChoiceIdentifierAttribute y agrega lógica adicional para elegir la opción.

Explicación

El elemento <choice> contiene dos o más elementos secundarios, cada uno de los cuales representa un elemento o grupo de elementos. Este elemento indica que, en un documento de instancia determinado, solo una de dichas entidades puede aparecer en la posición especificada. Las opciones deben diferenciarse por el nombre de elemento. También pueden diferenciarse por el tipo de elemento y, si la opción es una agrupación (como un elemento <group>), por el número de elementos.

Las combinaciones ambiguas de grupos generan unos resultados imprevisibles.

Diferenciación por tipo

El caso más simple surge cuando los tipos de los elementos individuales son distintos, así como sus nombres. Considere la siguiente definición de <choice>:

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

En C#, Xsd.exe traduciría este contenido de esquema XML al siguiente código:

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

En el código generado, al campo se le asigna el tipo objeto, pero también presenta dos atributos XmlElementAttribute. Uno de los atributos indica que el tipo debe serializarse como una instancia int; el otro, indica que el tipo debe serializarse como una instancia System.Decimal. En este caso, la clase XmlSerializer utiliza el tipo asignado al objeto en ese momento. Con la siguiente asignación a un objeto int, se utiliza el elemento <numberA>:

Item = 1;

Siempre que las opciones tengan distintos tipos de datos de esquema XML, Xsd.exe enlazará cada tipo de datos a una clase distinta. Como System.Object is es el tipo raíz de la jerarquía de tipos de .NET Framework, el campo generado siempre pertenece a un tipo base común. La clase objeto es el tipo base común más genérico.

Cuando todas las opciones se derivan de un tipo de datos definido en un esquema XML común, como ocurre a través de la construcción <extension>, el tipo del campo es un enlace de ese tipo de datos. Por ejemplo, supongamos que un elemento <choice> permite elegir entre un elemento <a> de DerivedTypeA y un elemento <b> de DerivedTypeB , y supongamos también que ambos tipos extienden el tipo BaseType. En C#, se genera el siguiente código fuente:

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

Diferenciación por nombre

Si los tipos de opción no son distintos, al crear un documento de instancia, la opción del nombre de elemento se realiza mediante el atributo XmlChoiceIdentifierAttribute. Considere la siguiente definición de <choice>:

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

Xsd.exe traduciría este contenido de esquema XML al siguiente código:

[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,
}

El campo Item tiene un atributo XmlChoiceIdentifier, además de los dos atributos XmlElement. El parámetro del atributo XmlChoiceIdentifier es el nombre de una instancia de enumeración. El tipo de enumeración correspondiente contiene las opciones de elemento. La instancia de enumeración aparece con un atributo XmlIgnore para que no pueda serializarse su valor.

El desarrollador debe escribir entonces el código necesario para asignar un valor a la instancia de enumeración. La siguiente línea realiza esto último para un objeto denominado i:

i.ItemElementName = ItemChoiceType.stringA;

Para obtener información, vea la clase XmlChoiceIdentifierAttribute.

Example

El siguiente documento de esquemas XML de entrada muestra los distintos usos de la agrupación <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>

Las clases de C# generadas a partir del documento del esquema XML anterior:

[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,
}

Documento de esquemas XML principal generado a partir de un ensamblado compilado con el código fuente de C# anterior: (No se muestra un segundo archivo .xsd que se genera para definir elementos globales arbitrarios para tipos complejos.)

<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>

Atributos posibles Compatibilidad con enlaces

id

La utilidad Xsd.exe omite el atributo id, que está pensado para proporcionar un identificador único.

maxOccurs

En el caso del elemento <choice>, Xsd.exe interpreta los valores del atributo maxOccurs que son iguales a 0 como 1, y los valores de maxOccurs mayores que 1 como unbounded.

Para un valor de 1, Xsd.exe genera el código como explicado en Differentiating by Type y Differentiating by Name.

Si el valor es unbounded, Xsd.exe realiza el mismo enlace, pero en este caso, el campo generado para la opción es una matriz de un tipo adecuado. Si todas las opciones tienen el mismo tipo, el segundo campo (identificado por el atributo XmlChoiceIdentifier) es una matriz del tipo de enumeración generado. Cada uno de los elementos de la segunda matriz elige el nombre del elemento correspondiente de la primera matriz.

Vea el atributo Compatibilidad con enlaces del atributo MaxOccurs.

minOccurs

Cuando se genera código fuente a partir de un documento de esquemas XML, Xsd.exe omite el atributo minOccurs que se aplica al elemento <choice>.

Cuando se genera un documento de esquemas XML a partir de clases, Xsd.exe genera un elemento <choice> con un valor para el atributo minOccurs de 1 si la opción representa un único objeto, o un valor de 0 si la opción representa una matriz.

Vea el atributo Compatibilidad con enlaces del atributo MinOccurs.

Elementos primarios posibles: <choice>, <complexType>, <extension>, <group>, <restriction>, <sequence>

Posibles elementos secundarios: <annotation>, <any>, <element>, <group>, <sequence>, <choice>

Vea también

Referencia

XmlSchemaChoice