Posts tagged ‘XML Serialization’

Handling a custom name space (xmlns) in an XML with Xml Serialization

I have an xml that has a name space. This gave me to problems I had to resolve.

  1. How do I deserialize this xml with that name space value?
  2. How do I serialize the object to only have this one name space?

Deserializing an Xml with a Name Space

Below is an Xml file. Notice that the PrimaryNode has a name space that isn’t the default.

<?xml version="1.0" encoding="utf-8"?>
<PrimaryNode xmlns="http://some/random/namespace/example>
  <SecondaryNode>
    <TertiaryNode />
    <TertiaryNode />
  </SecondaryNode>
</PrimaryNode>

I had an object created as follows.

using System;
using System.Xml.Serialization;
using System.Collections.ObjectModel;

namespace XmlNameSpaceTest.Model
{
    [Serializable()]
    public class PrimaryNode
    {
        private ObservableCollection<SecondaryNode> _Children;

        public PrimaryNode() { }

        [XmlElement("SecondaryNode")]
        public ObservableCollection<SecondaryNode> Children
        {
            get
            {
                if (_Children == null)
                    _Children = new ObservableCollection<SecondaryNode>();
                return _Children;
            }
        }
    }
}

I used this static class for the serialization

using System;
using System.IO;
using System.Xml.Serialization;

namespace XmlNameSpaceTest.Model
{
    public class Serializer
    {
        #region Functions
        public static void SerializeToXML<T>(T t, String inFilename)
        {
            XmlSerializer serializer = new XmlSerializer(t.GetType());
            TextWriter textWriter = new StreamWriter(inFilename);
            serializer.Serialize(textWriter, t);
            textWriter.Close();
        }

        public static T DeserializeFromXML<T>(String inFilename)
        {
            XmlSerializer deserializer = new XmlSerializer(typeof(T));
            TextReader textReader = new StreamReader(inFilename);
            T retVal = (T)deserializer.Deserialize(textReader);
            textReader.Close();
            return retVal;
        }
        #endregion
    }
}

But it failed to deserialize because of the name space. It gave me this exception (which I trimmed to only show the important parts as it was very long).

System.InvalidOperationException was unhandled
  Message=There is an error in XML document (2, 2).
  Source=System.Xml
  StackTrace:
       <-- snipped -->
  InnerException: System.InvalidOperationException
       Message=<PrimaryNode xmlns='http://some/random/namespace/example'> was not expected.
       Source=bgwwvhdx
       StackTrace:
            at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderPrimaryNode.Read7_PrimaryNode()

The solution was simple. I had to add the XmlRoot tag above the class.

    [Serializable()]
    [XmlRoot(Namespace="http://some/random/namespace/example")]
    public class PrimaryNode
    {
        ... snipped...
    }

This solved problem 1. The Xml now deserialized just fine.

Serializing an Xml so it only contains a single Name Space

When I serialized the object, there were two default name spaces, but neither were the custom name space that the Xml needed.

<?xml version="1.0" encoding="utf-8"?>
<PrimaryNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <SecondaryNode>
    <TertiaryNode />
    <TertiaryNode />
  </SecondaryNode>
</PrimaryNode>

Here is what I had to do.

1. Add a XmlSerializerNamespaces property with only the one name space added.

    [Serializable()]
    [XmlRoot(Namespace="http://some/random/namespace/example")]
    public class PrimaryNode
    {
        ... snipped...

        private XmlSerializerNamespaces _Namespaces;

        public XmlSerializerNamespaces NameSpaces
        {
            get
            {
                if (_Namespaces == null)
                {
                    _Namespaces = new XmlSerializerNamespaces();
                    _Namespaces.Add("", "http://schemas.microsoft.com/wix/2006/wi");
                }
                return _Namespaces;
            }
        }
    }

2. Then I had to change my Serializer class. I needed to overload the Serialize function by adding a version of it that accepts the XmlSerializerNamespaces object as the third parameter.

        public static void SerializeToXML<T>(T t, String inFilename, XmlSerializerNamespaces namespaces)
        {
            XmlSerializer serializer = new XmlSerializer(t.GetType());
            TextWriter textWriter = new StreamWriter(inFilename);
            serializer.Serialize(textWriter, t, namespaces);
            textWriter.Close();
        }

3. Then, you’ve probably realized already, when serializing the object to Xml, we use this new function and pass it the PrimaryNode.NameSpaces as the third parameter.

This solved the second problem.

I hope this post helps you.