0

I need help serializing XML in C#/.net.

Given something like this in C#:

public class Action {
    public string Name;
    public string Type;
}

public class TestObject {
    public List<Action> Actions;
}

I want to serialize the list of actions as elements, each with a unique name:

<TestObject>
    <Action0>
        <Name>A</Name>
        <Type>Dog</Name>
    </Action0>
    <Action1>...</Action1>
    <Action2>...</Action2>
    ...
</TestObject>

I've been looking into using IXmlSerializable on a custom List object to replace TestObject. But I'm not sure how to proceed.

Is this on the right track?

public class ActionCollection<T> : List<T>, IXmlSerializable ...

public class TestObject : ActionCollection<Action> { ...

The other possibility that comes to mind is - some way to customize the serialization of each Action to override the element name using C# code that could add the digit?

2
  • Why? This looks like an xy problem. What's the motivation for naming each Action element differently, when they are stored in a list? Commented May 18, 2020 at 15:41
  • Great question! This is the export format required. I didn't define it and can't change it - just need to produce the expected output. I can change the C# code of how I store it - but the output has to have those "sequential" names. Commented May 18, 2020 at 15:43

1 Answer 1

1

Using Xml Linq :

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

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            TestObject tests = new TestObject() {
                Actions = new List<Action>() {
                    new Action() { Name = "A", Type = "Dog"},
                    new Action() { Name = "C", Type = "Cat"},
                    new Action() { Name = "E", Type = "Elephant"}
                    }
            };

            string root = "<TestObject></TestObject>";

            XDocument doc = XDocument.Parse(root);
            XElement testObject = doc.Root;

            int index = 0;
            foreach (Action action in tests.Actions)
            {
                XElement newAction = new XElement("Action" + index.ToString(), new object[] {
                    new XElement("Name", action.Name),
                    new XElement("Type", action.Type)
                });
                testObject.Add(newAction);
                index++;
            }

            doc.Save(FILENAME);

        }
    }
    public class Action
    {
        public string Name;
        public string Type;
    }

    public class TestObject
    {
        public List<Action> Actions;
    }
}

Using a Custom Xml Serializer

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

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            TestObject tests = new TestObject() {
                Actions = new List<Action>() {
                    new Action() { Name = "A", Type = "Dog"},
                    new Action() { Name = "C", Type = "Cat"},
                    new Action() { Name = "E", Type = "Elephant"}
                    }
            };

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            XmlWriter writer = XmlWriter.Create(FILENAME,settings);

            XmlSerializer serializer = new XmlSerializer(typeof(TestObject));
            serializer.Serialize(writer, tests);

        }
    }
    public class Action
    {
        public string Name;
        public string Type;
    }

    public class TestObject : IXmlSerializable
    {
        public List<Action> Actions;

        public void WriteXml(XmlWriter writer)
        {
            List<XElement> testObjects = new List<XElement>();

            int index = 0;
            foreach (Action action in Actions)
            {
                XElement newAction = new XElement("Action" + index.ToString(), new object[] {
                    new XElement("Name", action.Name),
                    new XElement("Type", action.Type)
                });
                testObjects.Add(newAction);
                index++;
            }
            string obj = string.Join("", testObjects.Select(x => x.ToString()));
            writer.WriteRaw("\n" + obj + "\n");

        }
        public void ReadXml(XmlReader reader)
        {

        }

        public XmlSchema GetSchema()
        {
            return (null);
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

I like this approach, but it would require rebuilding the whole XML tree (I left out that each "Action" is a fairly large object with nested child objects).
I created a custom serializer class. See modification above.
Thank you, @jdweng. Your simple example of IXmlSerializable was perfect!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.