32

I am serializing List of objects List<TestObject> , and XmlSerializer generates <ArrayOfTestObject> attribute, I want rename it or remove it.
Can it be done with creating new class that encapsulated List as field?

 [XmlRoot("Container")]    
 public class TestObject
 {
     public TestObject() { }                         
     public string Str { get; set; }                         
 }

 List<TestObject> tmpList = new List<TestObject>();

 TestObject TestObj = new TestObject();
 TestObj.Str = "Test";

 TestObject TestObj2 = new TestObject();
 TestObj2.Str = "xcvxc";

 tmpList.Add(TestObj);
 tmpList.Add(TestObj2);


 XmlWriterSettings settings = new XmlWriterSettings();
 settings.OmitXmlDeclaration = true;
 settings.Indent = true;
 XmlSerializer serializer = new XmlSerializer(typeof(List<TestObject>));

 using (XmlWriter writer = XmlWriter.Create(@"C:\test.xml", settings))
 {              
     XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
     namespaces.Add(string.Empty, string.Empty);
     serializer.Serialize(writer, tmpList, namespaces);                            
}


<ArrayOfTestObject>
  <TestObject>
    <Str>Test</Str>
  </TestObject>
  <TestObject>
    <Str>xcvxc</Str>
  </TestObject>
</ArrayOfTestObject>
ilann
  • 453
  • 3
  • 10
  • 15

4 Answers4

33

The most reliable way is to declare an outermost DTO class:

[XmlRoot("myOuterElement")]
public class MyOuterMessage {
    [XmlElement("item")]
    public List<TestObject> Items {get;set;}
}

and serialize that (i.e. put your list into another object).


You can avoid a wrapper class, but I wouldn't:

class Program
{
    static void Main()
    {
        XmlSerializer ser = new XmlSerializer(typeof(List<Foo>),
             new XmlRootAttribute("Flibble"));
        List<Foo> foos = new List<Foo> {
            new Foo {Bar = "abc"},
            new Foo {Bar = "def"}
        };
        ser.Serialize(Console.Out, foos);
    }
}

public class Foo
{
    public string Bar { get; set; }
}

The problem with this is that when you use custom attributes you need to be very careful to store and re-use the serializer, otherwise you get lots of dynamic assemblies loaded into memory. This is avoided if you just use the XmlSerializer(Type) constructor, as it caches this internally automatically.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Marc hit the nail on the head. I did a similar trick over at http://stackoverflow.com/questions/3000934/return-xml-data-from-a-web-service/3001176#3001176 – Jesse C. Slicer Jun 27 '10 at 23:20
  • So there is no way to avoid using another class? – ilann Jun 28 '10 at 06:59
  • There is a better and easier way, just se this question: http://stackoverflow.com/questions/1237683/xml-serialization-of-listt-xml-root – Fedearne Jun 09 '11 at 11:11
  • 2
    @Fedearne which better/easier way is that? do you mean the accepted answer which is *identical* to the second suggestion above? And note very carefully the reasoning I gave as to why this is dangerous. – Marc Gravell Jun 09 '11 at 11:23
  • @Marc Gravell do I need to create a separate MyOuterMessage for each type I'm serializing? – roman m Jul 29 '11 at 21:39
  • @MarcGravell I ask a similar question, would you please check it, here: http://stackoverflow.com/questions/13247449/customize-xml-serialize-with-new-tags-and-attributes-and-root – Saeid Nov 06 '12 at 11:08
  • @Saeid sorry, but that's a very different question; I don't mess around with soap envelopes much – Marc Gravell Nov 06 '12 at 12:49
11

Change the following line from:

XmlSerializer serializer = new XmlSerializer(typeof(List<TestObject>));

To:

XmlRootAttribute root = new XmlRootAttribute("TestObjects");     

XmlSerializer serializer = new XmlSerializer(typeof(List<TestObject>), root);

It should work.

RGA
  • 2,577
  • 20
  • 38
Sue Hu
  • 111
  • 1
  • 2
  • Down voted. This method will insert a root element but it still won't remove the "ArrayOfTestObject" element. – gooram Dec 01 '21 at 05:00
5

You can add an additional parameter to the XmlSerializer constructor to essentially name the root element.

XmlSerializer xsSubmit = new XmlSerializer(typeof(List<DropDownOption>), new XmlRootAttribute("DropDownOptions"));

This would result in the following structure:

<DropDownOptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <DropDownOption>
      <ID>1</ID>
      <Description>foo</Description>
    </DropDownOption>
    <DropDownOption>
      <ID>2</ID>
      <Description>bar</Description>
    </DropDownOption>
</DropDownOptions>
JsonStatham
  • 9,770
  • 27
  • 100
  • 181
1

Create another class like :

       [XmlRoot("TestObjects")]
       public class TestObjects: List<TestObject>
       {

       }

Then apply below code while sealizing :

            XmlSerializer serializer = new XmlSerializer(typeof(TestObjects));
            MemoryStream memStream = new MemoryStream();
            serializer.Serialize(memStream, tmpList);
Dev Try
  • 211
  • 2
  • 14
  • This didn't have any effect in my case. I _guess_ the built-in serializer just looks if the object to serialize is a child of `List` in order to apply its special naming scheme. – Crusha K. Rool Sep 17 '17 at 20:38