1

I have the following classes:

namespace XmlSerializerTest
{
    using System;
    using System.Collections.Generic;
    using System.Xml.Serialization;

    [Serializable]
    [XmlRoot( Namespace = "My:NS" )]
    [XmlType( Namespace = "My:NS" )]
    [XmlInclude( typeof( Command ) )]
    [XmlInclude( typeof( ImSession ) )]
    public class CommandBase
    {
        [XmlAttribute]
        public string Version { get; set; }
    }

    [Serializable]
    [XmlType( Namespace = "My:NS" )]
    [XmlInclude( typeof( ImSession[ ] ) )]
    public class Command : CommandBase
    {
        [XmlArray]
        [XmlArrayItem( typeof( ImSession ) )]
        public object[ ] Content { get; set; }
    }

    [Serializable]
    [XmlType( Namespace = "My:NS" )]
    public class ImSession
    {
        [XmlElement]
        public string ClientId { get; set; }

        [XmlElement]
        public DateTime StartTime { get; set; }

        [XmlArray]
        public List<Matrix.Xmpp.Client.Message> Messages { get; set; }
    }
}

I use the following code to serialize a Command object:

        XmlSerializer ser = new XmlSerializer( typeof( CommandBase ) );

        Command c = new Command
        {
            Version = "TEST",
            Content = new object[ ]
                                  {
                                      new ImSession
                                      {
                                          ClientId = "Client A",
                                          StartTime = DateTime.Today,
                                          Messages = {
                                                         new Matrix.Xmpp.Client.Message( "a@b.com/c" ) { Body = "TEST BODY A" },
                                                         new Matrix.Xmpp.Client.Message( "a@b.com/c" ) { Body = "TEST BODY B" }
                                                     }
                                      },
                                      new ImSession
                                      {
                                          ClientId = "Client B",
                                          StartTime = DateTime.Now,
                                          Messages =
                                                     {
                                                         new Matrix.Xmpp.Client.Message( "c@b.com/a" ) { Body = "TEST BODY C" },
                                                         new Matrix.Xmpp.Client.Message( "c@b.com/a" ) { Body = "TEST BODY D" }
                                                     }
                                      }
                                  }
        };

        ser.Serialize( Console.Out, c );

This results in the following XML, which the same serializer can't properly deserialize:

<?xml version="1.0" encoding="utf-8"?>
<CommandBase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="Command" Version="TEST" xmlns="My:NS">

  <Content>
    <ImSession>
      <ClientId>Client A</ClientId>
      <StartTime>2015-08-11T00:00:00-04:00</StartTime>
      <Messages>
        <Message>
          <message to="a@b.com/c" xmlns="jabber:client">
            <body>TEST BODY A</body>
          </message>
        </Message>
        <Message>
          <message to="a@b.com/c" xmlns="jabber:client">
            <body>TEST BODY B</body>
          </message>
        </Message>
      </Messages>
    </ImSession>
    <ImSession>
      <ClientId>Client B</ClientId>
      <StartTime>2015-08-11T21:55:18.4624832-04:00</StartTime>
      <Messages>
        <Message>
          <message to="c@b.com/a" xmlns="jabber:client">
            <body>TEST BODY C</body>
          </message>
        </Message>
        <Message>
          <message to="c@b.com/a" xmlns="jabber:client">
            <body>TEST BODY D</body>
          </message>
        </Message>
      </Messages>
    </ImSession>
  </Content>
</CommandBase>

What happens when deserializing is that the Messages collection is null. I believe the problem to be the extra "Message" wrapper element around the actual "message" elements. If I change it to be an array of objects, it is no longer null, but contains the correct number of objects, but including that extra wrapper.

How can I get rid of that extra Message element around the message elements?

Note I am using the Matrix XMPP library (available on NuGet) for that Message class.

The XML I want to achieve is:

<?xml version="1.0" encoding="utf-8"?>
<CommandBase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="Command" Version="TEST" xmlns="My:NS">

  <Content>
    <ImSession>
      <ClientId>Client A</ClientId>
      <StartTime>2015-08-11T00:00:00-04:00</StartTime>
      <Messages>
        <message to="a@b.com/c" xmlns="jabber:client">
          <body>TEST BODY A</body>
        </message>
        <message to="a@b.com/c" xmlns="jabber:client">
          <body>TEST BODY B</body>
        </message>
      </Messages>
    </ImSession>
    <ImSession>
      <ClientId>Client B</ClientId>
      <StartTime>2015-08-11T21:55:18.4624832-04:00</StartTime>
      <Messages>
        <message to="c@b.com/a" xmlns="jabber:client">
          <body>TEST BODY C</body>
        </message>
        <message to="c@b.com/a" xmlns="jabber:client">
          <body>TEST BODY D</body>
        </message>
      </Messages>
    </ImSession>
  </Content>
</CommandBase>

Here is deserialization code for the same object:

StringBuilder sb = new StringBuilder( );
ser.Serialize( new StringWriter( sb ), c );
object d = ser.Deserialize( new StringReader( sb.ToString( ) ) );

Inspecting d in the debugger shows that it is, in fact, a Command object, with ImSessions in it, and the Messages array of each has objects in it, which it claims are Matrix.Xmpp.Client.Message, but which have all properties null (matching the xml), except for their private collection of child nodes, which have the actual Message objects in them, with all properties as expected.

dodexahedron
  • 4,584
  • 1
  • 25
  • 37
  • The `` nesting seems to be coming from the `Matrix.Xmpp.Client.Message` class itself. Have you tried serializing and deserializing a single instance of this class? http://www.ag-software.net/matrix-xmpp-sdk/ doesn't seem to be open-source so can you reproduce the problem with a simple replacement class? – dbc Aug 12 '15 at 04:02
  • Yes. The (lower-case) element is coming from Matrix. That class inherits from XElement and calling ToString on it will result in that element exactly as it appears in the xml above. What I'm more curious about is where the extra (capital M) element is coming from and why the runtime can't deserialize the thing it serialized, even with the same XMLSerializer in the same application. Shouldn't it be 1-to-1? – dodexahedron Aug 12 '15 at 12:47
  • By default `XmlSerializer` wraps collections in a container element. If you don't want this, see [Deserializing into a List without a container element in XML](http://stackoverflow.com/questions/5271442/deserializing-into-a-list-without-a-container-element-in-xml). However, I don't think this is the cause of your problem. When I tried to reproduce your problem with a simple POCO in place of `Matrix.Xmpp.Client.Message`, I could not (deserialization worked fine). So I think there's something wrong with `Message`. But give that answer a try just in case. – dbc Aug 12 '15 at 17:58
  • Also, can you update your question with your deserialization code? You only show serialization. – dbc Aug 12 '15 at 18:00
  • Added the deserializer code to the bottom of the post. I'm not worried about the Messages wrapper element. I would expect a wrapper element around the whole collection, but not an extra wrapper around each item in the collection. And even if so, is there a way to override that behavior and leave each element's serialization up to that object itself? – dodexahedron Aug 12 '15 at 23:11

0 Answers0