BizTalk Utilities CV ,   Jobs ,   Code library  
 
Home Page
XmlSerializer
Generic XmlSerializer
Runtime Overrides
Runtime Customization
Customizing Xml Serialization
Advanced XmlSerializer
XmlSerializer Attributes
Runtime exceptions
Serializing Collection Classes
Serializing Arrays
XmlElement Attribute Type
XmlIncludeAttribute
XmlSerializer
Serialization Attributes
Serializable Classes
Deserializing an object
Serializing an object
Serialize Class
Metadata Attributes
<< XML DOM
XQuery >>

By :Mark Wilson
I am the creator of TopXML. I am available for international and local (Australia) contracts. I am a Solution Architect/Business Analyst. I have worked in IT in several countries (NZ, Australia, South Africa, UK) building and training teams for government and very large non-governmental organizations. I am ex-Microsoft Consulting Services. I wrote the first book on Microsoft XML published in 2000 called XML Programming with VB and ASP. Most recently I have been building tools for the SEO industry. Ask me for a 37 point SEO health-checkup for your website.
First posted :03/24/2008
Times viewed :1079

 

Choice Model Groups

In all cases we discussed so far, mapping a .NET class to an XML complexType was easy because the schema provided an unambiguous mapping from one type system to the other. Now, there are cases where the schema-type-to-.NET-type mapping is ambiguous, because the XML schema type defines ambiguous child element with the <choice> model group. Generally, a model group defines usage rules for a group of elements, or in XML terminology particles. The rules of a model group define which particles can occur in a group, in which order they occur and how many times. The <choice> model group defines a group of mutually exclusive particles. We have to examine this group a little bit deeper, because there is no true counterpart to the choice model group in object oriented programming languages. In a programming language each field of a class is present in each instance. The <choice> group on the other hand defines a set of “fields” and only one of them may be present in any given instance. It is up to the parsing logic in the application processing the XML to interpret the semantic differences between the elements. In the following section we learn how we design classes to bridge the two type systems and process XML types defined with the <choice> model group.

Mapping a Single-Value <choice>

First let’s look at the simple case where a <choice> defines a single occurrence of a single element. The following schema describes a Car element with exactly four elements. The first three are always Make, Model and Year. Every Car has exactly one out of two additional elements because the <choice> occurs exactly once (minOccurs=1, maxOccurs=1) and either element within the groups occurs exactly once. The fourth element can be either a LeasePayment or a FinancePayment element.

7           Listing 10.3 A schema with a <choice> model group and two plossible instances of the Car_T type

<xs:schema id="Car"

      targetNamespace="http://tempuri.org/Car.xsd"

      xmlns="http://tempuri.org/Car.xsd"

      xmlns:xs=http://www.w3.org/2001/XMLSchema …>

     

  <xs:complexType name="Car_T" mixed="false">

    <xs:sequence minOccurs="1" maxOccurs="1">

      <xs:element name="Make" type="xs:string" />

      <xs:element name="Model" type="xs:string" />

      <xs:element name="Year" type="xs:int" />

      <xs:choice minOccurs="1" maxOccurs="1">

        <xs:element minOccurs="1" maxOccurs="1" name="LeasePayment"

          type="xs:int" />

        <xs:element minOccurs="1" maxOccurs="1" name="FinancePayment"

          type="xs:int" />

      </xs:choice>

    </xs:sequence>

  </xs:complexType>

 

  <xs:element name="Car" type="Car_T"></xs:element>

</xs:schema>

<Car>

  <Make>Ford</Make>

  <Model>Explorer</Model>

  <Year>2002</Year>

  <FinancePayment>699</FinancePayment>

</Car>

<Car>

  <Make>Ford</Make>

  <Model>Expedition</Model>

  <Year>2002</Year>

  <LeasePayment>429</LeasePayment>

</Car>

Identifying The Choice Particle

We could design a .NET class that maps to the Car type if the two elements were of different types. One technique would be to declare a field of type object and attach XmlElement attributes to resolve the two element names to the same field payment, but attaching two XmlElement attributes in only possible if the two different elements are of different types. LeasePayment and FinancePayment on the other hand are of the same type, which negates applying two XmlElements, because Serialize() cannot look at the type object the payment field refers to in order to figure out if the field refers to a LeasePayment or a FinancePayment. Equally, if we only provide a single field for the two payment types,  Deserialize() can only store the amount in the XML stream, but not which type of payment type the XML stream specified to.

What we need to solve this problem is a second field to store the auxiliary information, which we will call the “choice field”. In the example above the choice field would hold information about the payment. The type of the choice field is an enumeration of the elements in the <choice> that we need to disambiguate. The Serialize() method can now consult the choice field whether to generate a FinancePayment or a LeasePayment element when it processes a Car object. Likewise, Deserialize() can set the choice field to convey whether the data was deserialized from a LeasePayment or a FinancePayment. But wait, how does the XmlSerializer know about the choice field? We have to identify a choice field by attaching an XmlChoiceIdentifierAttribute to the field we need to disambiguate. The XmlSerializer detects the attribute when it analyzes the type and links the choice field to the data field.

Mapping a Class to a Single-Value Choice

Let’s develop a class that maps to the XML type Car described by the schema above. Besides the fields for make, model and year we also have to supply two fields for the payment field: One for the data and one to indicate whether the data refers to a LeasePayment or a FinancePayment element.

First we create a public enumeration called ItemChoiceType with values named after the ambiguous elements in the <choice> model group.

Then we create the Car class with the two fields for the <choice>. The field Item to stores the element data and ItemElementName to identifies whether the data is a LeasePayment or a FinancePayment.

Next, we attach two XmlElementAttribute attributes to the data field so Deserialize() will know to store the data of either XML element in the Item field.

We also attach an XmlChoiceIdentifierAttribute pointing to ItemElementName to clarify the particle Item refers to. Deserialize() will set ItemElementName to reflect which <choice> element was present in the deserialized XML stream, Serialize() will read ItemElementName when it processes Item to determine what element to generate.

using System.Xml.Serialization;

[XmlType(Namespace="http://tempuri.org/Car.xsd",

  IncludeInSchema=false)]

public enum ItemChoiceType                            | #1

{                                                     |

    LeasePayment,                                     |

    FinancePayment,                                   |

}                                                     |

[XmlType(Namespace="http://tempuri.org/Car.xsd")]

[XmlRoot("Car", Namespace="http://tempuri.org/Car.xsd",

  IsNullable=false)]

public class Car_T

{   

  public string Make;

  public string Model;

  public int Year;

  [XmlElement("LeasePayment", typeof(int))]

  [XmlElement("FinancePayment", typeof(int))]

  [XmlChoiceIdentifier("ItemElementName")]

  public int Item;

  [XmlIgnore()]                             | #2

  public ItemChoiceType ItemElementName;    |

}

(annotation) <#1 The enumeration defines a value for each of the ambiguous elements>

(annotation) <#2 We have to attach an XmlIgnoreAttribute attribute to the ItemElementName field because it does not map to the <choice> model group. It is only used by the XmlSerializer.>

TIP: While we can create the class and the enumeration manually, but it is by far easier to let the XSD schema definition tool provided with the Framework SDK generate the complete class definition.

Multi Value Choice Model

The more complicated case to map a <choice> model group to a .NET class arises when the model group can occur more than once in an instance of the schema type, i.e. if the maxOccurs attribute on the group is greater than one. For example if we changed the schema definition from listing 10.3 to the following:

  <xs:choice minOccurs="1" maxOccurs="unbounded">

    <xs:element minOccurs="1" maxOccurs="1" name="LeasingRate;" type="xs:int" />

    <xs:element minOccurs="1" maxOccurs="1" name="FinancePayment" type="xs:int" />

  </xs:choice>

Then there is no restriction how many and in which order payment elements appear in a type, because each payment element is viewed as an instance of the model group, which can appear an “unbounded” number of times, like in the next XML fragment.

<Car>

  <Make>Ford</Make>

  <Model>Explorer</Model>

  <Year>2002</Year>

  <FinancePayment>699</FinancePayment>

  <FinancePayment>799</FinancePayment>

  <LeasePayment>429</LeasePayment>

  <FinancePayment>899</FinancePayment>

</Car>

This may sound a bit complicated, but what we learned in the previous section easily extends to <choice> definitions allowing multiple occurrences. First of all, we need to declare a data field of an array type to store all the data. Then we also make the choice field an array to clarify which particle of the model group the data items corresponds to. Once again, the type of the choice field has to be an enumeration with values for the ambiguous particle names. The items in the choice field array clarify the particle of the item in the choice array at the same position. Finally we attach an XmlChoiceIdentifierAttribute to the data field array to signal the XmlSerializer which two arrays contain the information to map objects of this class to the <choice> model group.

The modifications to the Car T class from the previous example to handle multiple occurrences of the <choice> are as simple as changing the data field and the choice field to array types as shown in the code fragment shown below:

  [XmlElementAttribute("LeasingRate", typeof(int))]

  [XmlElementAttribute("FinancePayment ", typeof(int))]

  [XmlChoiceIdentifierAttribute("ItemsElementNames")]

  public int[] Items;

   

  [XmlIgnoreAttribute()]

  public ItemsChoiceType[] ItemsElementNames;


Rate this article on a scale of 1 to 10

Your vote :  


 

Recent Jobs

A great opportunity to Digital Vide
here is a greate opportunity as a S
A great opportunity as a Network En
A Greate Opportunituy as a SQL Deve
An immediate job opportunity as a B

View all Jobs (Add yours)
View all CV (Add yours)



Information Online

swimming pool contractor
chicago web site design
conference call
Web Hosting
gotomeeting
designer sunglasses
answering service


    Email TopXML  

Front Page Daily Stuff TopXML Forum XML blogs XML Newsgroups BizTalk Biztalk Utilities Biztalk Utilities Tutorial B2B SAP XML Microsoft .NET Dotnet System XML Soapformatter SQLXML XMLserializer XQuery PHP PHP SimpleXML PHP XML Dom PHP XML RPC PHP XSLT Java Java Java XML Xalan Microsoft ASP ASP Schemas XML SQL Server XML XMLDom XSL XSL Tutorial XSLT Stylesheets General Javascript CSS XHTML WAP