Search code examples
c#xelementenum-flags

XElement using Flags Enum


In my code, I have got an Flags Enum for days of the week, as follows:

[Flags]
public enum DaysOfWeek          // enumeration for days of week
{
    Sunday = 0x0000001,
    Saturday = 0x0000010,
    Friday = 0x0000100,
    Thursday = 0x0001000,
    Wednesday = 0x0010000,
    Tuesday = 0x0100000,
    Monday = 0x1000000,
    MondayToFriday = Monday | Tuesday | Wednesday | Thursday | Friday,
    MondayToSaturday = MondayToFriday | Saturday,
    NotSaturday = MondayToFriday | Sunday,
    Weekend = Saturday | Sunday,
    MondayToSunday = MondayToFriday | Weekend,
    HolidaysOnly = ~MondayToSunday,
}

And I use this as in the following simplified example to output XML:

List<DaysOfWeek> profiles = new List<DaysOfWeek>();
profiles.Add(DaysOfWeek.MondayToFriday);
profiles.Add(DaysOfWeek.MondayToSaturday);
profiles.Add(DaysOfWeek.Monday | DaysOfWeek.Tuesday);

XElement xml = new XElement("Profiles",
                 from DaysOfWeek pf in profiles 
                 select new XElement("Profile",pf.ToString())
               );
Console.WriteLine(xml);

This gives me the output:

<Profiles>
    <Profile>MondayToFriday</Profile>
    <Profile>MondayToSaturday</Profile>
    <Profile>Tuesday, Monday</Profile>
</Profiles>

But what I want is:

<Profiles>
    <Profile>
        <MondayToFriday />
    </Profile
    <Profile>
        <MondayToSaturday />
    </Profile>
    <Profile>
        <Monday />
        <Tuesday />
    </Profile>
</Profiles>

I appreciate that the format of my XElement needs to be extended so that I get empty elements for the days of the week, but if I do this then the "Tuesday, Monday" element throws an exception because I can't use a comma (or space) as part of an element name.

But

a) If not using one of the predefined groups of days, I need to write the elements in a particular order (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday) which is given by the schema (see c below). I have made it harder for myself because I've defined them in reverse, with Monday as the high bit, but this was because the older data format that I dealt with first presents the days as flags (1/0) in a string in that order e.g. Monday and Tuesday are "1100000" (Monday on left, Sunday on right);

b) I would like to be able to output the appropriate elements without having to test for everything individually (although I guess I will have to if I have to); and

c) The output XML format I am looking for is dictated by a standard with an XSD, and I can't change it.

Any bright ideas?


Solution

  • The following might suit your needs.
    It parses the output string of the flag and determines if the content should be an XElement or a list of.

    public static object GetDaysOfWeekXelementContent(DaysOfWeek pf)
    {
        var pfStr = pf.ToString();
        if (pfStr.Contains(","))
        {
            return pfStr.Split(',').Select(x => new XElement(x.Trim()));
        }
        else
        {
            return new XElement(pfStr);
        }
    }
    
    static void Main(string[] args)
    {
        List<DaysOfWeek> profiles = new List<DaysOfWeek>();
        profiles.Add(DaysOfWeek.MondayToFriday);
        profiles.Add(DaysOfWeek.MondayToSaturday);
        profiles.Add(DaysOfWeek.Monday | DaysOfWeek.Tuesday);
    
        XElement xml = new XElement("Profiles",
                            from DaysOfWeek pf in profiles
                            select new XElement("Profile", GetDaysOfWeekXelementContent(pf))
                        );
        Console.WriteLine(xml);
    }
    

    Edit Regarding sorting of the values, you declare your values from Sunday to Monday. You can parse the values one by one, sort them descending in order to have Monday to Sunday.
    The following should do:

    public static object GetDaysOfWeekXelementContent(DaysOfWeek pf)
    {
        var pfStr = pf.ToString();
        if (pfStr.Contains(","))
        {
            return pfStr.Split(',').Reverse().Select(x => new XElement(x.Trim()));
        }
        else
        {
            return new XElement(pfStr);
        }
    }