3

I have an application that uses namespaces to help deserialize objects stored in XML. The XML namespace is also the C# namespace where the object resides. For example, given the following XML snip:

<xml-config xmlns:app="MyAppNS">
  <app:Person>
    <Name>Bill</Name>
    <Car>
      <Make>Honda</Make>
      <Model>Accord</Model>
    </Car>
  </app:Person>

  <app:Person>
    <Name>Jane</Name>
    <Car>
      <Make>VW</Make>
      <Model>Jetta</Model>
    </Car>
  </app:Person>

  <app:Car>
    <Make>Audi</Make>
    <Model>A6</Model>
  </app:Car>
</xml-config>

The configuration is really just a random bag of objects. As you can see, there is a mix of Person and Car objects at the top level. I use the namespace to determine the object type at load time for proper deserialization. Here is the code for loading the document:

public static void LoadFile(String file) {
    XmlDocument doc = new XmlDocument();
    doc.Load(file);

    XmlNode root = doc.DocumentElement;
    foreach (XmlNode child in root.ChildNodes) {
        if (child.NodeType != XmlNodeType.Element) {
            continue;
        }

        Object obj = LoadObject(child);
        // TODO handle object here...
    }
}

private static Object LoadObject(XmlNode node) {
    Object obj = null;

    StringBuilder str = new StringBuilder();
    if ((node.Prefix != null) && (node.Prefix != "")) {
        str.Append(node.NamespaceURI).Append('.');
    }
    str.Append(node.LocalName);

    Assembly assy = Assembly.GetExecutingAssembly();
    Type type = assy.GetType(str.ToString());
    XmlSerializer serdes = new XmlSerializer(type);

    using (XmlNodeReader reader = new XmlNodeReader(node)) {
        obj = serdes.Deserialize(reader);
    }

    return obj;
}

You many see the issue right away, but when this code is used, the resulting Person objects are empty, however there are no errors. The only way to get the deserializer to populate the child elements is to use the same namespace for the child elements:

  <app:Person>
    <app:Name>Bill</app:Name>
    <app:Car>
      <app:Make>Honda</app:Make>
      <app:Model>Accord</app:Model>
    </app:Car>
  </app:Person>

The only other option I have tried is to use fully-qualified type names as the element name (no namespaces), however I haven't had any luck with that. Is there a way to cause the deserializer to accept the non-prefixed children of the XML node?

jheddings
  • 26,717
  • 8
  • 52
  • 65
  • Just for background, in the real implementation, the objects do not always share namespaces (i.e. `Person` and `Car` are not necessarily in the same namespace). This causes problems for the serializer and my methods. – jheddings Oct 07 '12 at 03:21
  • you can do it in LINQ2XML instead of deserializing it – Anirudha Oct 07 '12 at 04:30
  • @Anirudha can you please post an answer using the sample XML I provided? – jheddings Oct 07 '12 at 04:34
  • what data do you want from the xml..a collection of person..i guess or is it something else – Anirudha Oct 07 '12 at 04:38
  • @Anirudha I need to handle objects as they are deserialized individually... At the `// TODO` line preferably. Of course, any sample solution that comes close would be helpful. – jheddings Oct 07 '12 at 04:43

1 Answers1

0

I finally found a method to accomplish this, modifying the answer found here.

I created a custom deserializer that replicates the namespace for the starting node:

public class CustomXmlNodeReader : XmlNodeReader {

    private String _namespace;

    public CustomXmlNodeReader(XmlNode node) : base(node) {
        _namespace = node.NamespaceURI;
    }

    public override String NamespaceURI {
        get { return _namespace; }
    }
}

Using this reader, I am able to load stored objects with the following:

using (XmlNodeReader reader = new CustomXmlNodeReader(node)) {
    obj = serdes.Deserialize(reader);
}

I know this is a bit bad form for XML (forcing the application of a specific namespace), however it suits my needs quite nicely. Answered here in case it helps anyone else.

Community
  • 1
  • 1
jheddings
  • 26,717
  • 8
  • 52
  • 65