0

How can I create a extension method to convert my List of T to an XML string. Where my T object's property becomes a xml tag and the property's value becomes the value within the xml tag. My T object has simple string properties, ie no collections or two dimensional object. That is all properties are string, int etc, ie one dimensional..no lists/arrays as a property.

JeffJeffery
  • 155
  • 1
  • 9
  • 1
    Smells like an interview question! – DavidG Oct 06 '15 at 15:07
  • An extension method is probably not the best choice; I would consider a class instead (that is abstracted by an interface). This will allow you to provide a class for XML-serialization and another one for CSV. The problem I see with an extension method is, that it must be implemented in a static class... and functionality that shall be polymorphic in some way, should not be static... just my two cents. – Matze Oct 06 '15 at 15:09
  • lol! it isn't. I am planning to converting my list object into a xml file via File.AppendAllText(".xml") by giving it a file extension. I basically have my data in a one level dimension in my object. I just need to see if there is a easier way to remove all my convertion code into a list extension method But maybe, I can remove the file part. Maybe just a xml output. – JeffJeffery Oct 06 '15 at 15:09
  • 1
    There's an extension method for Xml Serialization on [this page](https://code.msdn.microsoft.com/windowsdesktop/Implementing-Xml-b3223253) – stuartd Oct 06 '15 at 15:10
  • @stuartd thanks let me try this out. – JeffJeffery Oct 06 '15 at 15:11
  • @Matze any examples? – JeffJeffery Oct 06 '15 at 15:13
  • @Matze I see your point, as I faced the " cannot be serialized because it does not have a parameterless constructor." issue. – JeffJeffery Oct 08 '15 at 20:19
  • @JeffJaffery Do you need this functionality as a one-way serializer; for instance in a logging-scenario, or do you also want to deserialize the data? – Matze Oct 09 '15 at 06:22
  • I just wanted to serialize my object into xml and store the file. But I just got over the problem, when I used the IXMLSerialize object and implemented the xml write and read functions. So I am good now! So yes, It is somewhat a one way serializer as I don't send the info over the wire. This previous post helped. [link] (http://stackoverflow.com/questions/267724/why-xml-serializable-class-need-a-parameterless-constructor) – JeffJeffery Oct 09 '15 at 15:07

3 Answers3

3

If you want to convert for example this kind of list:

List<int> Branches = new List<int>();
Branches.Add(1);
Branches.Add(2);
Branches.Add(3);

into this XML:

<Branches>
    <branch id="1" />
    <branch id="2" />
    <branch id="3" />
</Branches>

You can try this using LINQ:

List<int> Branches = new List<int>();
Branches.Add(1);
Branches.Add(2);
Branches.Add(3);

XElement xmlElements = new XElement("Branches", Branches.Select(i => new XElement("branch", new XAttribute("id", i))));
System.Console.Write(xmlElements);
System.Console.Read();

output:

<Branches>
  <branch id="1" />
  <branch id="2" />
  <branch id="3" />
</Branches>

you need to include using System.Xml.Linq; namespace.

EDIT : To make files you can use this method

 public string ToXML<T>(T obj)
 {
    using (StringWriter stringWriter = new StringWriter(new StringBuilder()))
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        xmlSerializer.Serialize(stringWriter, obj);
        return stringWriter.ToString();
    }
 }
VERYNET
  • 531
  • 2
  • 14
2

What you're talking about roughly translates to "serialization", and like most generic problems this one is solved. The framework certainly provides you with some tools for Xml Serialization.

Given a class:

public class TestClass
{
    public string Prop1 {get;set;}
    public string Prop2 {get;set; }
}

And an extension method:

public static class SerializationExtensions
{
    public static string ToXml<T>(this List<T> list)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<T>)); 

        StringWriter stringWriter = new StringWriter(); 
        XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter); 

        xmlWriter.Formatting = Formatting.Indented; 
        xmlSerializer.Serialize(xmlWriter, list); 

        return stringWriter.ToString();     
    }
}

A simple demo produces the xml

<?xml version="1.0" encoding="utf-16"?>
<ArrayOfTestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TestClass>
    <Prop1>val1</Prop1>
    <Prop2>val2</Prop2>
  </TestClass>
  <TestClass>
    <Prop1>val1</Prop1>
    <Prop2>val2</Prop2>
  </TestClass>
  <TestClass>
    <Prop1>val1</Prop1>
    <Prop2>val2</Prop2>
  </TestClass>
</ArrayOfTestClass>

It would be trivial to serialize to a file rather than a string, but for demonstrating the usage it's easier to output as a string.

Live demo: http://rextester.com/AKIBNI2909

Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • wow thank you! @Jamiec . I see the flaw in my question, i should just work with the strings and carry out the file IO elsewhere. – JeffJeffery Oct 06 '15 at 16:30
0

Creating an extension method isn't that much different that a regular method. You simply make the method static, if specify the first parameter (the object the method will extend) with the keyword "this". The rest is just plan reflection.

    public static string GetXML<T>(this List<T> src)
    {
        // First, we have to determine the "Type" of the generic parameter.
        Type srcType = src.GetType();
        Type[] srcTypeGenArgs = srcType.GetGenericArguments();
        if (srcTypeGenArgs.Length != 1)
            throw new Exception("Only designed to work on classes with a single generic param.");
        Type genType = srcTypeGenArgs[0];

        // Get the properties for the generic Type "T".
        System.Reflection.PropertyInfo[] typeProps = genType.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.GetProperty);

        // Now, we loop through each item in the list and extract the property values.
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("<root>");
        for (int i = 0; i < src.Count; i++)
        {
            T listItem = src[i];
            for (int t = 0; t < typeProps.Length; t++)
            {
                object propVal = typeProps[t].GetValue(listItem, null); // Always pass "null" for the index param, if we're not dealing with some indexed type (like an array).
                string propValStr = (propVal != null ? propVal.ToString() : string.Empty);
                sb.AppendLine(string.Format("<{0}>{1}</{0}>", typeProps[t].Name, propValStr));
            }
        }
        sb.AppendLine("</root>");
        return sb.ToString();
    }
Mike U
  • 709
  • 6
  • 11