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.
- How do I deserialize this xml with that name space value?
- 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.