Liquid XML Data Binder 2019
xs:choice
Liquid XML Objects (C#, Visual Basic .Net) > Using the Generated Code > XML Schema Handling > xs:choice

 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

Generated Code

Visual Studio Extension