views:

151

answers:

2

I am trying to figure out how to do XML serialization.

This is how I want my XML document too look like in the end

<course>
    <name></name>
    <backgroundColor></backgroundColor>
    <fontColor></fontColor>
    <sharingKey></sharingKey>
    <task id="">
        <taskName></taskName>
        <description></description>
    </task>
    <task id="">
        <taskName></taskName>
        <description></description>
    </task>
</course>

So far mine looks like

<?xml version="1.0" encoding="utf-8"?>
<Course xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
  <name>name</name>
  <backgroundColor>test</backgroundColor>
  <fontColor>test2</fontColor>
  <sharingKey>9324bfab-6cc7-49e5-84f7-56130b8dc099</sharingKey>
  <task id="first Task" />
  <task id="Second task" />
</Course>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace ConsoleApplication1
{
    [XmlRoot("Course")]
    public class MyWrapper 
    {
        public MyWrapper()
        {
            TaskList = new List<Tasks>();
        }

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

        [XmlElement("backgroundColor")]
        public string BackgroundColor { get; set; }

        [XmlElement("fontColor")]
        public string  FontColor { get; set; }

        [XmlElement("sharingKey")]
        public Guid SharingKey { get; set; }

        [XmlElement("task")]
        public List<Tasks> TaskList { get; set; }

    }


    public class Tasks
    {
        [XmlAttribute("id")]
        public string Id { get; set; }
    }

}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

            Tasks task = new Tasks();
            task.Id = "first Task";

            Tasks task2 = new Tasks();
            task2.Id = "Second task";

            MyWrapper wrap = new MyWrapper();
            wrap.BackgroundColor = "test";
            wrap.FontColor = "test2";
            wrap.Name = "name";
            wrap.SharingKey = Guid.NewGuid();

            wrap.TaskList.Add(task);
            wrap.TaskList.Add(task2);

            SerializeToXML(wrap);
        }

        static public void SerializeToXML(MyWrapper list)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(MyWrapper));


       TextWriter textWriter = new StreamWriter(@"C:\New folder\test.xml");
        serializer.Serialize(textWriter, list);
        textWriter.Close();
    }
}

}

So my question is with the "id" for the task.

All I have is another class with this in it

[XmlAttribute("id")]
public string Id { get; set; }

How did it know to put this attribute in the task tag?

What happens if I wanted to have another property

[XmlElement()]
public string TaskName {get; set;}

Say I wanted to have an attribute with this element how would I make sure that the attribute would be with TaskName not with Task?

A: 

Basically: XML elements can have two kinds of properties, attributes and elements. You defined an XML element task and an attribute on task called id, thus the serializer adds the attribute to task.

Now, suppose you want to add elements to reside within task -- this is also okay, as I said, XML elements can contain other elements, or have attributes. Simply define any elements you want to contain within task...within task.

If you want to have an attribute attached to a different element, you need to create a new XML element (here that corresponds to a class) and literally set it as an attribute type using the [XmlAttribute("id")] syntax.

Perhaps there's a disconnect for you here -- when you define the simplest form of element, we can call that a simpleType, and it can have values that are Strings or Integers or any kind of relatively primitive type (dates are valid, too). But if you want that same element to also have attributes, it suddenly needs to become a complexType, since it has complexContent -- it may contains both simple content, and properties, like, say, an attribute.

Take a look at how to write XML Schemas - w3schools have some excellent tutorials - I think that you'll gain a much better understanding of this whole mix of simple and complex content. Effectively, by defining an XML serialization for your classes you are also defining an XML schema; and you can in fact compile your code into such a schema. Understanding to construct the schemas will let you understand how to construct your code to generate the appropriate schemas, and additionally, understand your serialization output.

Mark E
Hmm so if you want this "so called" complex type you always have to make a new class? I jsut find that will be so messy if you got large xml files. You might like 50 classes with a couple lines in it. Then you got to hunt down all of these complex types and try to get a picture of it.
chobo2
@chobo2: Right. An alternative is to start from the other end of the problem, define a schema, and let the schema generate your code. For Java there's something called JAXB which will do this for you...I'll look up the C# equivalent now.
Mark E
@chobo2: http://stackoverflow.com/questions/765422/jaxb-equivalent-in-c has some good links on generating C# from XML Schemas. If you're concerned with the verbosity from generating a lot of C# classes you might find that the schema more concisely describes the same thing.
Mark E
+1  A: 
[XmlElement("task")]
public List<Tasks> TaskList { get; set; }

This part of your code told it to serialize every Tasks object in an element called "task". The serializer looks at the properties on the Tasks class and finds the Id property which you marked with [XmlAttribute("id")] so it gets serialized as an attribute to the "task" element for the object.

I'm not sure I understand your second question. You cannot add an attribute to the element because its type is a string. Instead you would have to create a new class to wrap the concept of a task name which would have a name property and whatever other properties you wanted to add to it.

Brian Ensink
Oh I did not know that it matter what type it was but if I where writing the xml document manually nothing would stop me from doing <TaskName attr="hi"> </TaskName> So for C# serialization I would need to make a new class and wrap around that? Can I see an example to me that seems like stuff can get confusing fast if you need to wrap every around another thing.
chobo2
It is no different than what you have already done with your MyWrapper class. If you have a composite type just create a class to represent it. In your case a task name is a string and id number so create a class called TaskName that contains a string and id number.
Brian Ensink
Well I mean confusing in the way that every time you need a new composite type you need make a new class. So if you got many composite types your going to have to X amount of classes to see the entire code.
chobo2
I don't see any problem with that. In your code you have a concept of a task name that is a string and a number. Your code should reflect that by making a class to encapsulate both of those values (regardless of xml serialization), in fact this is one of the main points of object oriented programming.
Brian Ensink