добавление рекурсивной структуры папок в сериализацию XML

#c# #xml #xml-serialization

#c# #xml #xml-сериализация

Вопрос:

У меня есть проект на c #, который сериализует список объектов в xml.

 [Serializable]
[XmlRoot]
public class collection {
    private List<item> _items = new List<item>();

    [XmlElement("item")]
    public List<item> items {
        get { return _items; }
    }
}

[Serializable]
    public class item {
}
 

затем вывод xml

 <collection>
    <item/>
    <item/>
    <item/>
</collection>
 

я хотел бы добавить опцию папок и вложенных папок, чтобы элементы можно было группировать вместе, сохраняя при этом возможность перехода в корневой узел.

 <collection>
    <item/>
    <item/>
    <folder>
        <item/>
        <item/>
    </folder>
    <item/>
    <item/>
    <folder>
        <item/>
        <item/>
        <folder>
            <item/>
            <item/>
        </folder>
    </folder>
    <item/>
</collection>
 

Может кто-нибудь посоветовать чистый способ сделать это, продолжая генерировать вывод xml с использованием сериализованных объектов?

Комментарии:

1. Вам нужно выполнить синтаксический анализ, используя folder вместо item . Вы могли бы получить родительский элемент item, но лично мне не нравится использовать родительское свойство.

Ответ №1:

Это должна быть структура классов.

 public class Folder2
{
}

public class Folder
{
    public Folder2 folder { get; set; }
}

public class Collection
{
    public List<Folder> folder { get; set; }
}

public class RootObject
{
    public Collection collection { get; set; }
}
 

Комментарии:

1. Глядя на это, я считаю, что это сделало бы папки обязательными (вместо необязательных), а также всегда фиксированными на двух уровнях.

2. Для этого вы можете использовать необязательный атрибут

Ответ №2:

После небольшого количества проб и ошибок мне удалось получить функциональность, которую я искал.

 [Serializable]
[XmlRoot]
public class collection {
    private List<treeEntry> _entries = new List<treeEntry>();

    [XmlElement("item", typeof(item))]
    [XmlElement("folder", typeof(folder))]
    public List<treeEntry> entries {
        get { return _entries; }
    }
}

public abstract class treeEntry { }

[Serializable]
public class folder : treeEntry {
    private List<treeEntry> _entries = new List<treeEntry>();

    public folder() { }

    [XmlAttribute]
    public string name { get; set; }

    [XmlElement("item", typeof(item))]
    [XmlElement("folder", typeof(folder))]
    public List<treeEntry> entries {
        get { return _entries; }
    }
}


[Serializable]
public class item : treeEntry { }


public class mytest {
    public static void main() {
        collection col = new collection();
        col.entries.Add(new item());
        col.entries.Add(new item());

        var folder1 = new folder() { name = "someFolder" };
        folder1.entries.Add(new item());
        var folder2 = new folder() { name = "anotherFolder" };
        folder1.entries.Add(folder2);
        folder1.entries.Add(new item());
        folder2.entries.Add(new item());

        col.entries.Add(folder1);
        col.entries.Add(new folder());
        col.entries.Add(new item());


        XmlSerializer sers = new XmlSerializer(typeof(collection));

        //serialise
        using (StreamWriter sw = new StreamWriter("testoutput.xml", false, Encoding.UTF8)) {
            XmlWriter xw = new XmlTextWriter(sw);
            sers.Serialize(xw, col);
        }

        //deserialise
        FileStream fs = new FileStream("testoutput.xml", FileMode.Open);
        XmlReader reader = XmlReader.Create(fs);
        collection newcol = (collection)sers.Deserialize(reader);

        //output to console
        sers.Serialize(Console.Out, newcol);
    }
}
 

что дало желаемый результат

 <collection>
    <item />
    <item />
    <folder name="someFolder">
        <item />
        <folder name="anotherFolder">
            <item />
        </folder>
        <item />
    </folder>
    <folder />
    <item />
</collection>