简体   繁体   中英

How to Serialize List<T> property in c# without showing its type in XML serialization

I have a class for which I need to serialize it in XML. Below is the example:

public class StringArray
{        
    public List<string> Days { get; set; }

    public StringArray()
    {
        List<string> s = new List<string>();
        s.Add("Monday");
        s.Add("Tuesday");
        s.Add("Wed");           
        Days = s;
    }
}

When I Serialize it in XML format then result is:

 <StringArray xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Days>
     <string>Monday</string>
     <string>Tuesday</string>
     <string>Wed</string>
   </Days>
 </StringArray>

However, I need result like below:

 <StringArray xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Days>             
         <Monday />
         <Tuesday />
         <Wed />                 
  </Days>
</StringArray>

Actually I do not want to show the type of list item.

Note that the set of possible strings is fixed. I also tried using an enum for this, however the XML shows the enum type name instead of 'string' which doesn't solve the problem.

Try following :

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

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            string xml = File.ReadAllText(FILENAME);

            XDocument doc = XDocument.Parse(xml);

            List<XElement> strings = doc.Descendants("string").ToList();

            foreach (XElement xelement in strings)
            {
                xelement.ReplaceWith(new XElement((string)xelement));
            }
        }
    }
}

Since you have only a fixed set of possible string values, your schema corresponds to an unbounded sequence of choice elements, where the possible element names correspond to the possible string values.

This can be modeled by replacing the string with some appropriate enum , then making use of the Choice Element Binding Support support built in to XmlSerializer , which requires application of XmlChoiceIdentifierAttribute along with the use of an appropriate serialization surrogate DTO .

First, define an enum that corresponds to the possible string values:

public enum Day
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

Next, define the following DTO which will be serialized in place of your List<Day> :

public class DayListDTO
{
    [XmlIgnore]
    public Day [] Days { get; set; }

    [XmlChoiceIdentifier(nameof(DayListDTO.Days))]
    [XmlElement(nameof(Day.Monday), typeof(object))]
    [XmlElement(nameof(Day.Tuesday), typeof(object))]
    [XmlElement(nameof(Day.Wednesday), typeof(object))]
    [XmlElement(nameof(Day.Thursday), typeof(object))]
    [XmlElement(nameof(Day.Friday), typeof(object))]
    [XmlElement(nameof(Day.Saturday), typeof(object))]
    [XmlElement(nameof(Day.Sunday), typeof(object))]
    public object[] DaysObjects
    {
        get
        {
            return Days == null ? null : Enumerable.Repeat(new object(), Days.Length).ToArray();
        }
        set
        {
            // Do nothing
        }
    }

    public static implicit operator DayListDTO(List<Day> list)
    {
        return list == null ? null : new DayListDTO { Days = list.ToArray() };
    }

    public static implicit operator List<Day>(DayListDTO dayList)
    {
        return dayList?.Days?.ToList() ?? new List<Day>();
    }
}

Finally, make use of the DTO by adding surrogate properties to containing classes as follows:

public class StringArray
{
    [XmlIgnore]
    public List<Day> Days { get; set; }

    [XmlElement("Days")]
    public DayListDTO XmlDaysSurrogate { get { return Days; } set { Days = value; } }
}

Which, when serialized, generates the following XML:

<StringArray xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Days>
    <Monday />
    <Tuesday />
    <Wednesday />
  </Days>
</StringArray>

Notes:

  • To use XmlChoiceIdentifier correctly with an array, your containing DTO type must have two array members:

    1. One array that records the contents of the choice elements, here DayListDTO.DaysObjects ;
    2. One array that records the names of the choice elements, here DayListDTO.Days , in 1-1 correspondence with the first array.


    Since the elements corresponding to your list of enums contain no contents at all, a dummy array of object items is returned for the first array.

  • Using XmlChoiceIdentifier guarantees that the schema which xsd.exe auto-generates for your types will correctly indicate an unbounded sequence of correctly-named choice elements. Other solutions such as implementing custom serialization via IXmlSerializable on some subclass of List<Day> do not have this advantage.

Working sample fiddle here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM