0

I am trying to deserialise an xml file to c# classes. I used an online tool to generate the classes for me as the structure of the XML file is quite complex. This worked well except for the population of repeated items into a List property in the main class.

I am using DotNet 4.5, C# in WPF.

A simplified version of the xml file is as follows:

<orderMessage xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:gs1:ecom:order:xsd:3">
  <order xmlns="">
    <creationDateTime>2017-07-10T00:00:00</creationDateTime>
    <documentStatusCode>ORIGINAL</documentStatusCode>
    <documentActionCode>ADD</documentActionCode>
  </order>
  <order xmlns="">
    <creationDateTime>2017-07-10T00:00:00</creationDateTime>
    <documentStatusCode>ORIGINAL</documentStatusCode>
    <documentActionCode>ADD</documentActionCode>
  </order>
</orderMessage>

The classes that I am using are as below:

[XmlRoot(ElementName = "order")]
public class Order
{
    [XmlElement(ElementName = "creationDateTime")]
    public string CreationDateTime { get; set; }
    [XmlElement(ElementName = "documentStatusCode")]
    public string DocumentStatusCode { get; set; }
    [XmlElement(ElementName = "documentActionCode")]
    public string DocumentActionCode { get; set; }
    [XmlAttribute(AttributeName = "xmlns")]
    public string Xmlns { get; set; }
}

[XmlRoot(ElementName = "orderMessage", Namespace = "urn:gs1:ecom:order:xsd:3")]
public class OrderMessage
{
    [XmlElement(ElementName = "order")]
    public List<Order> Order { get; set; }
    [XmlAttribute(AttributeName = "xsd", Namespace = "http://www.w3.org/2000/xmlns/")]
    public string Xsd { get; set; }
    [XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
    public string Xsi { get; set; }
    [XmlAttribute(AttributeName = "xmlns")]
    public string Xmlns { get; set; }
}

The deserialization code is as follows:

        XmlSerializer serializer = new XmlSerializer(typeof(OrderMessage));

        StreamReader reader = new StreamReader(filename);
        OrderMessage newOrderMessage;
        try
        {
            newOrderMessage = (OrderMessage)serializer.Deserialize(reader);
        }
        catch (Exception e)
        {
            throw e;
        }
        reader.Close();

When I run the code it runs without error but I end up with an empty list. There were other structures in the xml (that were not repeated structures - therefore no list property) that populated without problem that I have omitted.

I have looked at a number of questions similar to mine but they seem to suggest the same method I am using.

I am unable to change the XML as it is from a third party.

I would greatly appreciate it if anyone could point me in the right direction.

BTW - I know that catching an error and then throwing it is of no use whatsoever but I just did that to add a breakpoint so I could look at the inner exceptions if there were any. I will make the error handling more meaningful once I have the process working.

james33
  • 109
  • 1
  • 7
  • I am not sure but I think its happening because there is no Parent to the which represents a list. It should be something like Test Order 1 Test Order 2 – Varun Mehta Jul 12 '17 at 15:49
  • @VarunMehta I tried that but it still did the same thing – james33 Jul 12 '17 at 15:50
  • Did you rename your Property and Xml Element Name to Orders ? XmlElement(ElementName = "orders")] public List Orders { get; set; } – Varun Mehta Jul 12 '17 at 15:51
  • Since you wont be able to change your XML this solution might not work anyways but would know whats wrong – Varun Mehta Jul 12 '17 at 15:53
  • @VarunMehta I hadn't done that but I just tried that now and the list populated with a single order item but all of the properties were null – james33 Jul 12 '17 at 15:56

1 Answers1

2

The issue is your Order property - the namespace will be inherited from OrderMessage, so it is urn:gs1:ecom:order:xsd:3 when it should be empty. You must specify this explicitly.

You can also remove a bunch of the namespace related attributes from your model. This is all you need:

[XmlRoot("orderMessage", Namespace = "urn:gs1:ecom:order:xsd:3")]
public class OrderMessage
{
    [XmlElement("order", Namespace = "")]
    public List<Order> Orders { get; set; }
}

public class Order
{
    [XmlElement("creationDateTime")]
    public string CreationDateTime { get; set; }

    [XmlElement("documentStatusCode")]
    public string DocumentStatusCode { get; set; }

    [XmlElement("documentActionCode")]
    public string DocumentActionCode { get; set; }
}

As an aside, throw e; in your deserialisation code is probably not what you want to do (see this question). Given you're not actually handling the exception, you can remove the try / catch entirely in this case.

You should also enclose your StreamReader in a using block to ensure it is disposed after use.

Charles Mager
  • 25,735
  • 2
  • 35
  • 45