Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deserialize an element as an XmlNode?

When using Xml serialization in C#, I want to deserialize a part of my input XML to an XmlNode.

So, given this XML:

<Thing Name="George">
  <Document>
    <subnode1/>
    <subnode2/>
  </Document>
</Thing>

I want to deserialize the Document element to an XmlNode.

Below is my attempt which given the XML above, sets Document to the 'subnode1' element rather than the 'Document' element.

How would I get the code to set the Document property to the Document element?

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

[Serializable]
public class Thing
{
  [XmlAttribute] public string Name {get;set;}
  public XmlNode Document { get; set; }
}

class Program
{
  static void Main()
  {
    const string xml = @"
<Thing Name=""George"">
  <Document>
    <subnode1/>
    <subnode2/>
  </Document>
</Thing>";
    var s = new XmlSerializer(typeof(Thing));
    var thing = s.Deserialize(new StringReader(xml)) as Thing;
  }
}

However, when I use an XmlSerializer to deserialize the XML above to an instance of Thing, the Document property contains the child element 'subnode1', rather than the 'Document' element.

How can I get the XmlSerializer to set Document to an XmlNode containing the 'Document' element?

(NB: I can get to the Document element by specifying a property of type XmlElement[] and marking it [XmlAnyElement], but that is set to the array of all unrecognised elements rather than just a single one named 'Document')

like image 590
mackenir Avatar asked Apr 19 '10 10:04

mackenir


1 Answers

Try marking the Document property with the [XmlAnyElement] attribute.

[Serializable]
public class Thing
{
    [XmlAttribute] 
    public string Name {get;set;}

    [XmlAnyElement]
    public XmlNode Document { get; set; }
}

This will have one unfortunate side effect in that you will find more than just subnode1 and subnode2 (all whitespaces get deserialized too... ugh), so you will need to filter them out:

class Program
{
    static void Main()
    {
        const string xml = @"
<Thing Name=""George"">
  <Document>
    <subnode1/>
    <subnode2/>
  </Document>
</Thing>";
        var s = new XmlSerializer(typeof(Thing));
        var thing = s.Deserialize(new StringReader(xml)) as Thing; 

        foreach (XmlNode node in thing.Document)
        {
            // should filter to only subnode1 and subnode2.
            if (node.Name != "" && node.Name != "#whitespace")
            {
              Console.WriteLine(node.Name);
            }
        }

        Console.ReadLine();
    }
}

Hope this helps!

like image 70
code4life Avatar answered Sep 30 '22 00:09

code4life