views:

284

answers:

3

I'm working on a set of classes that will be used to serialize to XML. The XML is not controlled by me and is organized rather well. Unfortunately, there are several sets of nested nodes, the purpose of some of them is just to hold a collection of their children. Based on my current knowledge of XML Serialization, those nodes require another class.

Is there a way to make a class serialize to a set of XML nodes instead of just one. Because I feel like I'm being as clear as mud, say we have the xml:

<root>
    <users>
        <user id="">
            <firstname />
            <lastname />
            ...
        </user>
        <user id="">
            <firstname />
            <lastname />
            ...
        </user>
    </users>
    <groups>
        <group id="" groupname="">
            <userid />
            <userid />
        </group>
        <group id="" groupname="">
            <userid />
            <userid />
        </group>
    </groups>
</root>

Ideally, 3 classes would be best. A class root with collections of user and group objects. However, best I can figure is that I need a class for root, users, user, groups and group, where users and groups contain only collections of user and group respectively, and root contains a users, and groups object.

Anyone out there who knows better than me? (don't lie, I know there are).

+5  A: 

Are you not using the XmlSerializer? It's pretty damn good and makes doing things like this real easy (I use it quite a lot!).

You can simply decorate your class properties with some attributes and the rest is all done for you..

Have you considered using XmlSerializer or is there a particular reason why not?

Heres a code snippet of all the work required to get the above to serialize (both ways):

[XmlArray("users"),
XmlArrayItem("user")]
public List<User> Users
{
 get { return _users; }
}
Rob Cooper
I am using the XMLSerializer, but best I can figure, you can only apply a single element name to a class or property. I have several intermediary classes that all they do is hold collections of other objects. The result is the proper XML, but a pain in the butt to instantiate myself.
Wes P
Added code to demo :)
Rob Cooper
@Rob Cooper: +1 for beating me to the code punch.
sixlettervariables
Nice. Thanks Rob! I've given you a +1 in my head...
Wes P
lol! Thanks guys :) Happy to help! If you get stuck again on serialization make sure you ask, I have had some real fun (if thats what you call it) with it recently (see profile for some of my Q's) :) Happy coding!
Rob Cooper
XML Serializer is what you need - it will work for you!
Cheeso
A: 

You would only need to have Users defined as an array of User objects. The XmlSerializer will render it appropriately for you.

See this link for an example: http://www.informit.com/articles/article.aspx?p=23105&amp;seqNum=4

Additionally, I would recommend using Visual Studio to generate an XSD and using the commandline utility XSD.EXE to spit out the class hierarchy for you, as per http://quickstart.developerfusion.co.uk/quickstart/howto/doc/xmlserialization/XSDToCls.aspx

paulwhit
A: 

I wrote this class up back in the day to do what I think, is similar to what you are trying to do. You would use methods of this class on objects that you wish to serialize to XML. For instance, given an employee...

using Utilities; using System.Xml.Serialization;

[XmlRoot("Employee")] public class Employee { private String name = "Steve";

 [XmlElement("Name")]
 public string Name { get { return name; } set{ name = value; } }

 public static void Main(String[] args)
 {
      Employee e = new Employee();
      XmlObjectSerializer.Save("c:\steve.xml", e);
 }

}

this code should output:

<Employee>
  <Name>Steve</Name>
</Employee>

The object type (Employee) must be serializable. Try [Serializable(true)]. I have a better version of this code someplace, I was just learning when I wrote it. Anyway, check out the code below. I'm using it in some project, so it definitly works.

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

namespace Utilities
{
    /// <summary>
    /// Opens and Saves objects to Xml
    /// </summary>
    /// <projectIndependent>True</projectIndependent>
    public static class XmlObjectSerializer
    {
        /// <summary>
        /// Serializes and saves data contained in obj to an XML file located at filePath <para></para>        
        /// </summary>
        /// <param name="filePath">The file path to save to</param>
        /// <param name="obj">The object to save</param>
        /// <exception cref="System.IO.IOException">Thrown if an error occurs while saving the object. See inner exception for details</exception>
        public static void Save(String filePath, Object obj)
        {
            // allows access to the file
            StreamWriter oWriter =  null;

            try
            {
                // Open a stream to the file path
                 oWriter = new StreamWriter(filePath);

                // Create a serializer for the object's type
                XmlSerializer oSerializer = new XmlSerializer(obj.GetType());

                // Serialize the object and write to the file
                oSerializer.Serialize(oWriter.BaseStream, obj);
            }
            catch (Exception ex)
            {
                // throw any errors as IO exceptions
                throw new IOException("An error occurred while saving the object", ex);
            }
            finally
            {
                // if a stream is open
                if (oWriter != null)
                {
                    // close it
                    oWriter.Close();
                }
            }
        }

        /// <summary>
        /// Deserializes saved object data of type T in an XML file
        /// located at filePath        
        /// </summary>
        /// <typeparam name="T">Type of object to deserialize</typeparam>
        /// <param name="filePath">The path to open the object from</param>
        /// <returns>An object representing the file or the default value for type T</returns>
        /// <exception cref="System.IO.IOException">Thrown if the file could not be opened. See inner exception for details</exception>
        public static T Open<T>(String filePath)
        {
            // gets access to the file
            StreamReader oReader = null;

            // the deserialized data
            Object data;

            try
            {
                // Open a stream to the file
                oReader = new StreamReader(filePath);

                // Create a deserializer for the object's type
                XmlSerializer oDeserializer = new XmlSerializer(typeof(T));

                // Deserialize the data and store it
                data = oDeserializer.Deserialize(oReader.BaseStream);

                //
                // Return the deserialized object
                // don't cast it if it's null
                // will be null if open failed
                //
                if (data != null)
                {
                    return (T)data;
                }
                else
                {
                    return default(T);
                }
            }
            catch (Exception ex)
            {
                // throw error
                throw new IOException("An error occurred while opening the file", ex);
            }
            finally
            {
                // Close the stream
                oReader.Close();
            }
        }
    }
}
Bruce