Shay Lugassy
Shay Lugassy

Reputation: 119

C# - Deserializing XML - XmlText gets Null instead of string itself

I'm trying to parse an XML message from a string. The string I get is this -

<Instance_Updated>
  <Instance>
    <Field Name="INSTANCE_LABEL">00010541</Field>
    <Field Name="MAT_ID">TEST</Field>
    <Field Name="DEVICE_ID">TEST</Field>
  </Instance>
  <Item>
    <Field Name="MATERIAL_ID">TEST</Field>
    <Field Name="TITLE">TEST</Field>
    <Field Name="ON_AIR_DURATION">A</Field>
  </Item>
</Instance_Updated>

The InstanceUpdated class itself is:

    [XmlType("Instance_Updated"), Serializable]
    public class InstanceUpdated : SnellMessage
    {
        public InstanceUpdated()
        {
            InstanceFields = new List<Field>()
            {
                new Field() { Name = "INSTANCE_LABEL" },
                new Field() { Name = "MAT_ID" },
                new Field() { Name = "DEVICE_ID" }
            };

            ItemFields = new List<Field>()
            {
                new Field() { Name = "MATERIAL_ID" },
                new Field() { Name = "TITLE" },
                new Field() { Name = "ON_AIR_DURATION" }
            };
        }

        [XmlArray("Instance")]
        [XmlArrayItem("Field")]
        public List<Field> InstanceFields { get; set; }

        [XmlArray("Item")]
        [XmlArrayItem("Field")]
        public List<Field> ItemFields { get; set; }
   }

    [XmlType("Field"), Serializable]
    public class Field
    {
        [XmlAttribute("Name")]
        public string Name { get; set; }

        [XmlText]
        public string Value { get; set; }
    }

When i try to parse the message -

InstanceUpdated instanceUpdatedMessage = SnellMessage.Deserialize<InstanceUpdated>(i_RootMessage.ToString()); 

In a 'Field' object I get NULL value instead of the string itself.

For example: I assume the Value property of the Field 'INSTANCE_LABEL' should be '00010541' but inside i get a NULL value.

Why is that?

Upvotes: 1

Views: 667

Answers (1)

dbc
dbc

Reputation: 116786

The problem is not that the values of Field.Value are coming back null. The problem is that you are allocating the InstanceFields and ItemFields lists in the constructor for InstanceUpdated, after which XmlSerializer appends the deserialized fields from the XML file. If you re-serialize the XML, you will see each field has been duplicated:

  <Instance>
    <Field Name="INSTANCE_LABEL" />
    <Field Name="MAT_ID" />
    <Field Name="DEVICE_ID" />
    <Field Name="INSTANCE_LABEL">00010541</Field>
    <Field Name="MAT_ID">TEST</Field>
    <Field Name="DEVICE_ID">TEST</Field>
  </Instance>

Sample repo fiddle.

For an explanation of why this happens, see XML Deserialization of collection property with code defaults.

Your workarounds include:

  • Move the collection initializations out of the constructor and into some factory.

  • Serialize a surrogate array property. Since arrays are read-only, the array must be set back once fully populated, e.g.:

    [XmlIgnore]
    public List<Field> InstanceFields { get; set; }
    
    [XmlArray("Instance")]
    [XmlArrayItem("Field")]
    public Field [] InstanceFieldsArray
    {
        get
        {
            if (InstanceFields == null)
                return null;
            return InstanceFields.ToArray();
        }
        set
        {
            (InstanceFields = InstanceFields ?? new List<Field>()).Clear();
            InstanceFields.AddRange(value ?? Enumerable.Empty<Field>());
        }
    }
    

    Sample fixed fiddle.

Upvotes: 1

Related Questions