Solved

DeSerialization - Element child nodes to string

Posted on 2011-09-07
5
1,192 Views
Last Modified: 2012-05-12
Hello Experts,

Assume I want to deserialize the following XML:

<ROOT>
<STATUS>101</STATUS>
<PAYLOAD>
<PERSON>
<FIRSTNAME>xxx</FIRSTNAME>
<....>xxx</....>
</PERSON>
</PAYLOAD>
</ROOT>

Open in new window


I would like to deserialize this xml, but let the payload element outerxml (element + childnodes) to be stored as a string in the PayLoad property.

    [XmlRoot(ElementName="ROOT")]
    public class Example
    {
        private string status;
        private string payLoad;

        [XmlElement(ElementName = "PAYLOAD")]
        public string PayLoad
        {
            get { return payLoad; }
            set { payLoad= value.}
        }
        [XmlElement(ElementName = "STATUS")]
        public string Status
        {
            get { return status; }
            set { status = value; }
        }

    }

Open in new window


Example use:

Example MyExample = serializer.Deserialize(xmlstring);

Console.WriteLine(MyExample.PayLoad);

//Writes:
//<PAYLOAD><PERSON><FIRSTNAME>xxx</FIRSTNAME><....>xxx</....></PERSON></PAYLOAD>

Open in new window


Is this possible?

Thank you,
amr-it
0
Comment
Question by:amr-it
  • 3
  • 2
5 Comments
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 36496705
You could do something like this:
XmlSerializer MyExample = new XmlSerializer(typeof(Example));

MyExample.UnknownElement += new XmlElementEventHandler(deserializer_UnknownElement);

Example MyExample = serializer.Deserialize(xmlstring) AS Example;

...

static void deserializer_UnknownElement(object sender, XmlElementEventArgs e)
{
    Example obj = e.ObjectBeingDeserialized as Example;

    if (e.Element.Name == "PAYLOAD")
    {
        obj.PayLoad = e.Element.OuterXml;
    }
}

Open in new window

0
 
LVL 1

Author Comment

by:amr-it
ID: 36500900
Thank you kaufmed for your comment.
I forgot to mention that my serializer and deserializer methods are located in a helper class and are designed to be generic (handling many different types), meaning if possible, I don't want to cast to the Example type. I got it to work doing something very similair to what you have proposed and I would assume that the above would work.

But, is there any way to define this in the class design so that the deserializer directly knows how to handle it?
0
 
LVL 75

Accepted Solution

by:
käµfm³d   👽 earned 500 total points
ID: 36502347
You could define a method in your class which takes in a delegate parameter and then assign the delegate as the handler for the event mentioned above. The signature of the delegate would need to match the signature as demonstrated above. Then each delegate would take care of managing the types it works with.

I don't know your specific code, but here is a demonstration of what I'm talking about:
using System;
using System.Xml;
using System.Xml.Serialization;

namespace _27295319
{
    class Program
    {
        /// <summary>
        /// Entry point for application.
        /// </summary>
        /// <param name="args">The args.</param>
        /// \date 9/8/2011 8:41 AM
        static void Main(string[] args)
        {
            SerializerClass deserailzer = new SerializerClass(typeof(Example));

            deserailzer.SetUnknownElementHandler(deserializer_UnknownElement);
            Example obj = deserailzer.Deserialize(System.IO.File.OpenRead("input.xml")) as Example;
        }

        /// <summary>
        /// The handler that will be attached to the SerializerClass' internal XmlSerializer.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Xml.Serialization.XmlElementEventArgs"/> instance containing the event data.</param>
        /// \date 9/8/2011 8:42 AM
        static void deserializer_UnknownElement(object sender, XmlElementEventArgs e)
        {
            Example obj = e.ObjectBeingDeserialized as Example;

            if (obj != null && e.Element.Name == "PAYLOAD")
            {
                obj.PayLoad = e.Element.OuterXml;
            }
        }
    }

    /// <summary>
    /// Example class which handles deserialization of an object.
    /// </summary>
    /// \author Kenneth Kaufmann
    /// \date 9/8/2011 8:41 AM
    public class SerializerClass
    {
        private XmlSerializer deserializer;
        private XmlElementEventHandler unknownElementHandler;   // Keep track of the handler that was added so we can remove
                                                                //  it later if we need to

        /// <summary>
        /// Initializes a new instance of the <see cref="SerializerClass"/> class.
        /// </summary>
        /// <param name="typeToSerialize">The type to serialize.</param>
        /// \date 9/8/2011 8:40 AM
        public SerializerClass(Type typeToSerialize)
        {
            deserializer = new XmlSerializer(typeToSerialize);
        }

        /// <summary>
        /// Attaches a handler for the UnknownElementHandler.
        /// </summary>
        /// <param name="handler"></param>
        public void SetUnknownElementHandler(XmlElementEventHandler handler)
        {
            if (unknownElementHandler != null) deserializer.UnknownElement -= unknownElementHandler;

            unknownElementHandler = handler;
            deserializer.UnknownElement += unknownElementHandler;
        }

        /// <summary>
        /// Deserializes the specified source data.
        /// </summary>
        /// <param name="sourceData">The source data.</param>
        /// <returns></returns>
        /// \date 9/8/2011 8:41 AM
        public object Deserialize(System.IO.Stream sourceData)
        {
            return deserializer.Deserialize(sourceData);
        }
    }

    [XmlRoot(ElementName = "ROOT")]
    public class Example
    {
        private string status;
        private string payLoad;

        public string PayLoad
        {
            get { return payLoad; }
            set { payLoad = value; }
        }

        [XmlElement(ElementName = "STATUS")]
        public string Status
        {
            get { return status; }
            set { status = value; }
        }
    }
}

Open in new window

0
 
LVL 1

Assisted Solution

by:amr-it
amr-it earned 0 total points
ID: 36528798
Thank you for your response. I ended up with a better solution, creating a generic class so it can be used for serialization.

    [XmlRoot(ElementName="ROOT")]
    public class Example<T> where T : new()
    {
        private string status;
        private T apiPayLoad = new T();

        [XmlElement(ElementName="APIPAYLOAD")]
        public T APIPayLoad
        {
            get { return apiPayLoad; }
            set { apiPayLoad = value; }
        }

        [XmlElement(ElementName = "STATUS")]
        public string Status
        {
            get { return status; }
            set { status = value; }
        }

    }

Open in new window



Usage:

        public static T DeserializeFromXml<T>(string xml)
        {
            T result;
            XmlSerializer ser = new XmlSerializer(typeof(T));
            ser.UnknownElement += new XmlElementEventHandler(ser_UnknownElement);
            using (TextReader tr = new StringReader(xml))
            {
                result = (T)ser.Deserialize(tr);
            }
            return result;
        }

Open in new window


Example<Person> PersonPayLoad = DeserializeFromXML<Example<Person>>(xml);

Open in new window

0
 
LVL 1

Author Closing Comment

by:amr-it
ID: 36555754
Comment for accepting own solution + expert:
Hopefully this generic solution also can be used for someone.
0

Featured Post

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The Client Need Led Us to RSS I recently had an investment company ask me how they might notify their constituents about their newsworthy publications.  Probably you would think "Facebook" or "Twitter" but this is an interesting client.  Their cons…
Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

766 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question