2

I want to serialise XML documents from a third-party service that either come in as any of the two formats (I added indenting for easier readability):

1.

<STADMessage>Invalid Request, no content provided!</STADMessage>

2.

<STADMessage>
    <Message>Invalid Request, see log for detail using reference: ASDFL210359872305982035</Message>
</STADMessage>

Right now I'm hacking the XML document before it gets serialised with the following code

xmlDocument.Replace("<STADMessage><Message>", "<STADMessages><Message>")
           .Replace("</Message></STADMessage>", "</Message></STADMessages>");

Snippet of the serialised class

[XmlElement(ElementName = "STADMessage", IsNullable = true)]
public string STADMessage { get; set; }

[XmlArray(ElementName = "STADMessages", IsNullable = true)]
[XmlArrayItem("Message", typeof(string))]
public List<string> STADMessages { get; set; }

Is there a cleaner way?

1
  • Ugh, that's so ugly of them to do that on their end. You should put in a ticket with their development team, and teach them what standardization is. Commented Oct 30, 2018 at 0:01

1 Answer 1

1

If you can get them to change it to a proper structure as @FrankerZ recommends, that would be ideal. If you can't, I hope this helps.

You can account for the variation using a custom serialization object that deserializes differently based on the incoming node type.

Change your STADMessage property's type to the custom type (I'll call it STADMessage for the heck of it):

[XmlElement(ElementName = "STADMessage", IsNullable = true)]
public STADMessage STADMessage { get; set; }

And here's the STADMessage class:

public class MySTADMessage : IXmlSerializable
{
    public string Message { get; set; }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        // IsNullable = true is ignored, apparently.  You won't get an actual
        // null for properties deserialized this way because the serializer
        // already created an instance of this class.
        if (reader.GetAttribute("nil", XmlSchema.InstanceNamespace) == "true")
            return;

        reader.ReadStartElement();

        while (reader.NodeType == XmlNodeType.Whitespace)
            reader.Read();

        if (reader.NodeType == XmlNodeType.Text)
        {
            Message = reader.ReadContentAsString();
        }
        else if (reader.NodeType == XmlNodeType.Element)
        {
            if (reader.Name != "Message")
                throw new Exception("Unexpected element name.");

            reader.ReadStartElement();
            if (reader.NodeType == XmlNodeType.Text)
            {
                Message = reader.ReadContentAsString();
            }
            else
            {
                throw new Exception("Unexpected node type.");
            }
            reader.ReadEndElement();
        }
        else
        {
            throw new Exception("Unexpected node type.");
        }
        reader.ReadEndElement();
    }

    public void WriteXml(XmlWriter writer)
    {
        // Not having the extra Message element is simpler.
        writer.WriteString(Message);
    }
}

It's crude, it doesn't quite implement IXmlSerializable correctly by today's standards, and it probably doesn't account for everything, but it should get you started.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.