Search code examples
c#xmllinqxelement

LINQ to XML. How to query List<T> with Linq recursively


I'm generating XML file from structs. Some struct members are in List<T> type. I'm using linq queries but I'm stuck at some level.

My structs are like this:

public struct Project
{
    public string name;
    public List<Class> classes;
}

public struct Class
{
    public string name;
    public int class_id;
    public List<Var> vars;
}

public struct Var
{
    public string name;
    public string description;
    public int var_id;
    public List<Element> elements;
}

public struct Element
{
    public string name;
    public string description;
    public int element_id;
    public List<Element> elements;
    public List<Enm> enums;
}

public struct Enm
{
    public string name;
    public int value;
}

and I'm trying to create an XML file that looks like this

<PROJECT name="test project xml">
    <CLASS name="class1" class_id="1">
        <VAR name="var name 1" description="var description" var_id="1">
            <ELEMENT name="element name 1" description="element description" element_id="1"/>

            <ELEMENT name="element name 2" description="element description" element_id="2">
                <ELEMENT name="element name 3" description="element description" element_id="3"/>
            </ELEMENT>

            <ELEMENT name="element name 4" description="element description" element_id="4">
                <ELEMENT name="element name 5" description="element description" element_id="5">
                    <ELEMENT name="element name 6" description="element description" element_id="6"/>
                </ELEMENT>
            </ELEMENT>

            <ELEMENT name="element name 7" description="element description" element_id="7">
                <ENUM name="option 1" value="1"/>
                <ENUM name="option 2" value="2"/>
                <ENUM name="option 3" value="3"/>
            </ELEMENT>
        </VAR>

        <VAR name="var name 2" description="var description" var_id="2">
            <ELEMENT name="element name 8" description="element description" element_id="8">
        </VAR>
    </CLASS>
</PROJECT>

I wrote this code to generate the XML file, but it reaches only the first element level. Elements within elements are skipped. How can I get it to reach lower element levels? Also some element tags have enum tags.

XElement elm = new XElement("PROJECT", new XAttribute("name" project.name),
    project.classes.Select(x=> new XElement("CLASS", new XAttribute("name", x.name), new XAttribute("class_id", x.class_id),
        x.vars.Select(v=> new XElement("VAR", new XAttribute("name", v.name), new XAttribute("description", v.description), new XAttribute("var_id", v.var_id),
            v.elements.Select(e=> new XElement("ELEMENT", new XAttribute("name", e.name),new XAttribute("description", e.description),new XAttribute("element_id", e.element_id)
            )))))));

Is there an easy way to done this with minimum code lines? I think there must be a recursive method to fix my issue.


Solution

  • Use Xml Serialization

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;
    
    namespace ConsoleApplication132
    {
        class Program
        {
            const string FILENAME = @"c:\temp\test.xml";
            static void Main(string[] args)
            {
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
    
                XmlWriter writer = XmlWriter.Create(FILENAME, settings);
                XmlSerializer serializer = new XmlSerializer(typeof(Project));
                Project project = new Project();
                serializer.Serialize(writer, project);
            }
        }
        [XmlRoot("PROJECT")]
        public class Project
        {
            [XmlAttribute]
            public string name { get; set; }
            [XmlElement("CLASS")]
            public List<cClass> classes { get; set; }
    
            public Project()
            {
                name = "test project xml";
                classes = new List<cClass>() {
                    new cClass() {
                        name = "class1",
                        class_id = 1,
                        vars = new List<Var>() {
                            new Var() { 
                                name = "var name 1",
                                description = "var description",
                                var_id = 1,
                                elements = new List<Element>() {
                                    new Element() {
                                       name = "element name 1",
                                       description = "element description",
                                       element_id = 1
                                    },
                                    new Element() {
                                       name = "element name 2",
                                       description = "element description",
                                       element_id = 2,
                                       elements = new List<Element>() {
                                           new Element() {
                                               name = "element name 3",
                                               description = "element description",
                                               element_id = 3
                                           }
                                       }
                                    },
                                    new Element() {
                                       name = "element name 4",
                                       description = "element description",
                                       element_id = 4,
                                       elements = new List<Element>() {
                                            new Element() {
                                               name = "element name 5",
                                               description = "element description",
                                               element_id = 5,
                                               elements = new List<Element>() {
                                                   new Element() {
                                                       name = "element name 6",
                                                       description = "element description",
                                                       element_id = 6
                                                   }
                                               }
                                            }
                                       }
                                    },
                                    new Element() {
                                       name = "element name 7",
                                       description = "element description",
                                       element_id = 7,
                                       enums = new List<Enm>() {
                                           new Enm() {
                                              name = "option 1",
                                              value = 1
                                           },
                                           new Enm() {
                                              name = "option 2",
                                              value = 2
                                           },
                                           new Enm() {
                                              name = "option 3",
                                              value = 3
                                           }
                                       }
                                    }
                                }
                            },
                            new Var() { 
                                name = "var name 2",
                                description = "var description",
                                var_id = 2,
                                elements = new List<Element>() {
                                    new Element() {
                                       name = "element name 8",
                                       description = "element description",
                                       element_id = 8
                                    }
                                }
                            }
                       }
                    }
                };
    
            }
        }
    
        public class cClass
        {
            [XmlAttribute]
            public string name { get; set; }
            [XmlAttribute]
            public int class_id;
            [XmlElement("VAR")]
            public List<Var> vars;
        }
    
        public class Var
        {
            [XmlAttribute]
            public string name;
            [XmlAttribute]
            public string description;
            [XmlAttribute]
            public int var_id;
            [XmlElement("ELEMENT")]
            public List<Element> elements;
        }
    
        public struct Element
        {
            [XmlAttribute]
            public string name;
            [XmlAttribute]
            public string description;
            [XmlAttribute]
            public int element_id;
            [XmlElement("ELEMENT")]
            public List<Element> elements;
            [XmlElement("EMNU")]
            public List<Enm> enums;
        }
    
        public struct Enm
        {
            [XmlAttribute]
            public string name;
            [XmlAttribute]
            public int value;
        }
    
    }