Liquid XML Data Binder 2020
Liquid XML Objects (C#, Visual Basic .Net) / Using the Generated Code / XML Schema Handling / xs:choice
In This Topic
    xs:choice
    In This Topic

     Sample Schema

    Consider the following schema, Root must contain one of the child nodes A,B,C or D.

    Choice.xsd
    Copy Code
    <?xml version="1.0" encoding="utf-8" ?>
    <!--Created with Liquid Studio 2018 (https://www.liquid-technologies.com)-->
    <xs:schema elementFormDefault="qualified" 
               targetNamespace="http://www.liquid-technologies.com/sample/choice" 
               xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xs:element name="Root">
            <xs:complexType>
                <xs:choice>
                    <xs:element name="A" type="xs:string" />
                    <xs:element name="B" type="xs:int" />
                    <xs:element name="C">
                        <xs:complexType>
                            <xs:sequence>
                                <xs:element name="Child" type="xs:string" />
                            </xs:sequence>
                        </xs:complexType>
                    </xs:element>
                    <xs:element name="D" type="xs:int" minOccurs="0" maxOccurs="unbounded" />
                </xs:choice>
            </xs:complexType>
        </xs:element>
    </xs:schema>
    

    D's cardinality is 0-n, so zero D's is an acceptable value for Root. In other words its valid for Root to be empty.

    Generated Code

    The following code is generated for the choice.

    Generated Code
    Copy Code
        public partial class RootElm
        {
            public RootChc Chc { get; set; } = new RootChc();
    
            public partial class RootChc
            {
                public System.String A { get; set; }
                public System.Int32? B { get; set; }
                public CElm C { get; set; }
                public List<System.Int32> D { get; } = new List<System.Int32>();
            }
    
            public partial class CElm
            {
                public CSeq Seq { get; set; } = new CSeq();
    
                public partial class CSeq
                {
                    public System.String Child { get; set; } = "";
                }
            }
        }
    
    The Lx... attributes, qualifying namespaces and comments have been removed for clarity.

    The class RootChc represents the xs:choice, so only one of the properties in RootChc can be set.

    Also note that all properties within the RootChc class are represented in their optional form (as its a choice all but one of the options should be empty).

    Also see Cardinality

    Writing Sample Code 

    We can use the following code to build instances of the Root Element

    Sample Code
    Copy Code
    LxSerializer<RootElm> serializer = new LxSerializer<RootElm>();
    LxWriterSettings writerSettings = new LxWriterSettings();
    writerSettings.ErrorHandler = WriterErrorHandler;
    
    RootElm elmWithA = new RootElm();
    elmWithA.Chc.A = "test";
    serializer.Serialize(@"..\..\ChoiceA_Output.xml", elmWithA, writerSettings); // OK
    
    RootElm elmWithD = new RootElm();
    elmWithD.Chc.D.Add(1);
    elmWithD.Chc.D.Add(2);
    serializer.Serialize(@"..\..\ChoiceD_Output.xml", elmWithD, writerSettings);  // OK
    
    RootElm elmWithAB = new RootElm();
    elmWithAB.Chc.A = "test";
    elmWithAB.Chc.B = 2;
    serializer.Serialize(@"..\..\ChoiceAB_Output.xml", elmWithAB, writerSettings); // Error via WriterErrorHandler : 2 choice populated
    
    Error Handler Code
    Copy Code
    public static void WriterErrorHandler(string msg, LxErrorSeverity severity, LxErrorCode errorCode, object targetObject)
    {
        Console.WriteLine($"{severity} : {errorCode} : {msg}");
    }
    

    Sample Output

    Output : ChoiceA_Output.xml

    ChoiceA_Output.xml
    Copy Code
    <?xml version="1.0" encoding="utf-8"?>
    <Root xmlns="http://www.liquid-technologies.com/sample/choice">
      <A>test</A>
    </Root>
    

    Output : ChoiceD_Output.xml

    ChoiceD_Output.xml
    Copy Code
    <?xml version="1.0" encoding="utf-8"?>
    <Root xmlns="http://www.liquid-technologies.com/sample/choice">
      <D>1</D>
      <D>2</D>
    </Root>
    

    Output : ChoiceAB_Output.xml

    ChoiceAB_Output.xml
    Copy Code
    <?xml version="1.0" encoding="utf-8"?>
    <Root xmlns="http://www.liquid-technologies.com/sample/choice">
      <A>test</A>
      <B>2</B>
    </Root>
    
    Error Output
    Copy Code
    Error : ExtraChoiceValues : A choice may only contain 1 value. The object /Root contains more than one option.
    

    When the sample runs an error is raised, if the error handler allows the serialization to continue (i.e. does not throw an exception), then the serializer will write out all the options in the object model. In this sample, Root now contains 2 child elements A and B, which makes it invalid.

    Reading Sample Code

    The following code will read back in the files created above.

     

    Sample Code
    Copy Code
    LxSerializer<RootElm> serializer = new LxSerializer<RootElm>();
    LxReaderSettings readerSettings = new LxReaderSettings();
    readerSettings.ErrorHandler = ReaderErrorHandler;
    
    RootElm elmWithA = serializer.Deserialize(@"..\..\ChoiceA_Output.xml", readerSettings); // OK
    Debug.Assert(elmWithA.Chc.A == "test");
    
    RootElm elmWithD = serializer.Deserialize(@"..\..\ChoiceD_Output.xml", readerSettings);  // OK
    Debug.Assert(elmWithD.Chc.D.Count == 2);
    Debug.Assert(elmWithD.Chc.D[0] == 1);
    Debug.Assert(elmWithD.Chc.D[1] == 2);
    
    RootElm elmWithAB = serializer.Deserialize(@"..\..\ChoiceAB_Output.xml", readerSettings); // Error via ReaderErrorHandler : 2 choice populated
    Debug.Assert(elmWithAB.Chc.A == "test");
    Debug.Assert(elmWithAB.Chc.D.Count == 0);
    
    Error Handler Code
    Copy Code
    public static void ReaderErrorHandler(string msg, LxErrorSeverity severity, LxErrorCode errorCode, TextLocation location, object targetObject)
    {
        Console.WriteLine($"{severity} : {errorCode} : {location} : {msg}");
    }
    

    When the valid XML files ChoiceA_Output.xml and ChoiceD_Output.xml are read they produce an object model identical to the one serialized out in the code above.

    However when the invalid XML file ChoiceAB_Output.xml is read an 'UnknownElement' error is raised, and additional element B is discarded.

    Error Output
    Copy Code
    Error : UnknownElement : 4:11 : No suitable type could be found to process the element B.
    

     

    It is possible to retain the child element B within the model value  by setting the 'Handle unknown nodes', see Unexpected Elements for more details.

    See Also