Search code examples
c#.netxmlxml-namespacesxml-deserialization

XML contains element with the namespace as empty URI breaks deserialization


I have an XML with the following structure:

<?xml version="1.0" encoding="utf-8"?>
<ClientInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">
  <Error>0</Error>
  <ErrorMsg />
  <doc>
    <NewDataSet xmlns="">
      <Table>
        <SEGMENT>123456</SEGMENT>
      </Table>
    </NewDataSet>
  </doc>
</ClientInfo>

Please notice the NewDataSet xmlns="" tag. I'm trying to deserialize this XML with the following class ClientInfo:

[XmlRoot(ElementName = "Table")]
public partial class Table
{
    [XmlElement(ElementName = "SEGMENT")]
    public string SEGMENT { get; set; }
}

[XmlRoot(ElementName = "NewDataSet")]
public partial class MyDataSet
{
    [XmlElement(ElementName = "Table")]
    public Table Table { get; set; }
}

[XmlRoot(ElementName = "doc")]
public class Doc
{

    [XmlElement(ElementName = "NewDataSet")]
    public MyDataSet MyDataSet { get; set; }
}

[Serializable, XmlRoot(ElementName = "ClientInfo", Namespace = "http://tempuri.org/")]
public partial class ClientInfo
{

    [XmlElement(ElementName = "Error")]
    public int Error { get; set; }

    [XmlElement(ElementName = "ErrorMsg")]
    public object ErrorMsg { get; set; }

    [XmlElement(ElementName = "doc")]
    public Doc Doc { get; set; }
}

As a result, MyDataSet from the resulting object xmlResult.Doc.MyDataSet.Table.SEGMENT returns null.

Without xmlns="" everything works fine. Now this attribute is to stay. Can't really make people get rid of it. How can I make the app work with this thing in XML?


Solution

  • Approach 1: Add the namespace to Doc

    A quick approach to resolve the issue is adding the namespace with empty string to the XmlElement attribute for the NewDataSet property as below:

    [XmlRoot(ElementName = "doc")]
    public class Doc
    {
        [XmlElement(ElementName = "NewDataSet", Namespace="")]
        public MyDataSet MyDataSet { get; set; }
    }
    

    Approach 2: Remove the "xmlns" attribute and overwrite the Name

    Similar to Gehan's answer on Unable to remove empty "xmlns" attribute from XElement using c#, you need to remove the "xmlns" attribute and overwrite the Name for each XmlNode as below:

    After performing the steps above, and deserialize the XML to an object.

    XDocument doc = XDocument.Parse(xml);
    XNamespace df = doc.Root.Name.Namespace;
    
    foreach (var node in doc.Descendants())
    {
        if (node.Name.NamespaceName == String.Empty)
        {
            node.Attributes("xmlns").Remove();
    
            node.Name = df + node.Name.LocalName;
        }
    }
    
    using (TextReader sr = new StringReader(doc.ToString()))
    {
        var serializer = new System.Xml.Serialization.XmlSerializer(typeof(ClientInfo));
        ClientInfo xmlResult = (ClientInfo)serializer.Deserialize(sr);
        Console.WriteLine(xmlResult.Doc.MyDataSet.Table.SEGMENT);
    }