50

I want XML in the following format:

<configuration><!-- Only one configuration node -->
  <logging>...</logging><!-- Only one logging node -->
  <credentials>...</credentials><!-- One or more credentials nodes -->
  <credentials>...</credentials>
</configuration>

I'm trying to create a class Configuration that has the [Serializable] attribute. To serialize the credentials nodes, I have the following:

[XmlArray("configuration")]
[XmlArrayItem("credentials", typeof(CredentialsSection))]
public List<CredentialsSection> Credentials { get; set; }

However, when I serialize this to XML, the XML is in the following format:

<configuration>
  <logging>...</logging>
  <configuration><!-- Don't want credentials nodes nested in a second
                      configuration node -->
    <credentials>...</credentials>
    <credentials>...</credentials>
  </configuration>
</configuration>

If I remove the [XmlArray("configuration")] line, I get the following:

<configuration>
  <logging>...</logging>
  <Credentials><!-- Don't want credentials nodes nested in Credentials node -->
    <credentials>...</credentials>
    <credentials>...</credentials>
  </Credentials>
</configuration>

How can I serialize this the way I want, with multiple <credentials> nodes within the single root node <configuration>? I wanted to do this without having to implement IXmlSerializable and do custom serialization. This is how my class is described:

[Serializable]
[XmlRoot("configuration")]
public class Configuration : IEquatable<Configuration>
Sarah Vessels
  • 30,930
  • 33
  • 155
  • 222

1 Answers1

81

The following should serialize properly the way you want. The clue being [XmlElement("credentials")] on the list. I did this by taking your xml, generating a schema (xsd) from it in Visual Studio. Then running xsd.exe on the schema to generate a class. (And some small edits)

public class CredentialsSection
{
    public string Username { get; set; }
    public string Password { get; set; }
}

[XmlRoot(Namespace = "", IsNullable = false)]
public class configuration
{
    /// <remarks/>
    public string logging { get; set; }

    /// <remarks/>
    [XmlElement("credentials")]
    public List<CredentialsSection> credentials { get; set; }

    public string Serialize()
    {
        var credentialsSection = new CredentialsSection {Username = "a", Password = "b"};
        this.credentials = new List<CredentialsSection> {credentialsSection, credentialsSection};
        this.logging = "log this";
        XmlSerializer s = new XmlSerializer(this.GetType());
        StringBuilder sb = new StringBuilder();
        TextWriter w = new StringWriter(sb);
        s.Serialize(w, this);
        w.Flush();
        return sb.ToString();
    }
}

give the following output

<?xml version="1.0" encoding="utf-16"?>
<configuration xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <logging>log this</logging>
  <credentials>
    <Username>a</Username>
    <Password>b</Password>
  </credentials>
  <credentials>
    <Username>a</Username>
    <Password>b</Password>
  </credentials>
</configuration>
Mikael Svenson
  • 39,181
  • 7
  • 73
  • 79
  • 2
    Yep, that worked! I was so set on "it's a `List`, gotta use the `XmlArrayItem` attribute somewhere" that I didn't even think of making it a regular `XmlElement`. – Sarah Vessels Jul 21 '10 at 20:22
  • 2
    good answer, i had the same problem - i wanted to remove: DATAITEMS> resolved it with: [XmlElement("DATAITEM")] public List DATAITEM { get; set; } – nologo Jun 23 '11 at 11:04
  • Thanks Mikael. This helped me out with my problem today. +1 – John Oct 31 '11 at 19:10
  • 1
    It works only when using XmlSerializer. It doesn't work when used inside a WCF DataContract, in a WCF DataMember, like `[XmlElement("credentials")] [DataMember] public List credentials { get; set; }`. It seems like WCF ignores the Xml* attributes for serialization. Any suggestion? – natenho Sep 18 '14 at 22:04
  • @natenho Correct. Look at http://stackoverflow.com/questions/591907/how-can-you-control-net-datacontract-serialization-so-it-uses-xml-attributes-in for more insight into this. – Mikael Svenson Sep 19 '14 at 13:37
  • 1
    thanks a lot ! That was killing me all the XmlArray , XmlArrayItem, ... The answer was so simple easy. – Titwan Nov 27 '14 at 17:28