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.
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 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
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}"); } |
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> |
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> |
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.
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.