locked
Parse XML with LINQ C# RRS feed

  • Question

  • Hello,

    With C # .NET, I use LINQ to parse XML, but I'm not completely familiar with LINQ for XML.<o:p></o:p>

    I have the following XML code:

    <?xml version="1.0" encoding="utf-8" ?>
    
    <Root>
      <PackageVersion version="1.0"/>
      <Window title="test">
    	<ComboBox label="labelTest1">
    		<item>article1</item>
    		<item>article2</item>
    		<item>article3</item>
    	</ComboBox>
    	<ComboBox label="labelTest2">
    		<item>base1</item>
    		<item>base2</item>
    	</ComboBox>
      </Window>  
    </Root>
    

    I would like to retrieve in this XML file, several information such as version, title and items.

    To get the version, here is my code:

    IEnumerable<string> version = from item in xelement.Elements("PackageVersion")
    select (string)item.Attribute("version");
    Console.WriteLine("Version: {0}", version.First());
    

    To get the title, here is my code:<o:p></o:p>

    IEnumerable<string> title = from item in xelement.Elements("Window")
    select (string)item.Attribute("title");
    Console.WriteLine("Title: {0}", titleFirst());
    

    If you have a better way to write the previous two codes, could you show it? Thank you.

    I block on the recovery of each comboBox with its label and its items.<o:p></o:p>

    I would like to put in two List <string> each item in string.<o:p></o:p>

    <o:p> </o:p>

    For example, the listComboBox1 list would contain article1, article2 and article3.<o:p></o:p>

    The listComboBox2 list would contain base1 and base2.<o:p></o:p>

    I tried with the following code:<o:p></o:p>

    IEnumerable<XElement> combos = xelement.Elements("Window").Elements("ComboBox").Elements("item");
    foreach (var combo in combos)
    {     
       Console.WriteLine(combo.Value);
    }
    

    but I collect all the items at once and I do not separate them.

    I cannot separate the items from each comboBox into two lists.

    I would also like to retrieve the label of each combobox separately.<o:p></o:p>

    <o:p> </o:p>

    Thank you for your help.<o:p></o:p>



    <o:p></o:p>


    <o:p></o:p>

    Thursday, August 6, 2020 6:03 PM

All replies

  • Hello,

    If this is your xml you might consider using json as it can be much easier to work with and lighter weight.

    {
        "PackageVersion": {
            "version": "1.0"
        },
        "Window": {
            "title": "test",
            "ComboBox": [
                {
                    "label": "labelTest1",
                    "item": [
                        "article1",
                        "article2",
                        "article3"
                    ]
                },
                {
                    "label": "labelTest2",
                    "item": [
                        "base1",
                        "base2"
                    ]
                }
            ]
        }
    }

    Install Json.net from Nuget, add these classes

        public class PackageVersion
        {
            public string version { get; set; }
        }
        public class ComboBox
        {
            public string label { get; set; }
            public List<string> item { get; set; }
        }
        public class Window
        {
            public string title { get; set; }
            public List<ComboBox> ComboBox { get; set; }
        }
    
        public class Root
        {
            public PackageVersion PackageVersion { get; set; }
            public Window Window { get; set; }
        }

    Deserialize (there is also a serialize method too)

    var data = JsonConvert.DeserializeObject<Root>(File.ReadAllText("data.json"));
    
    Console.WriteLine($"Package version: {data.PackageVersion.version}");
    
    foreach (ComboBox comboBox in data.Window.ComboBox)
    {
        Console.WriteLine($"label: {comboBox.label}");
        foreach (string item in comboBox.item)
        {
            Console.WriteLine($"  {item}");
        }
    }

    Results

    Package version: 1.0
    label: labelTest1
      article1
      article2
      article3
    label: labelTest2
      base1
      base2

    Otherwise see https://stackoverflow.com/questions/670563/linq-to-read-xml


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange


    Thursday, August 6, 2020 8:58 PM
  • To separate the items, try splitting the code into two loops:

    IEnumerable<XElement> combos = xelement.Elements( "Window" ).Elements( "ComboBox" );
    foreach( var combo in combos )
    {
    	Console.WriteLine( "Label: " + combo.Attribute( "label" ).Value );
    	var items = combo.Elements( "item" );
    	foreach( var item in items )
    	{
    		Console.WriteLine( item.Value );
    	}
    }
    

    To get the version and title, check this alternative:

    string version = xelement.Element( "PackageVersion" ).Attribute( "version" ).Value;
    string title = xelement.Element( "Window" ).Attribute( "title" ).Value;

     


    • Edited by Viorel_MVP Friday, August 7, 2020 5:43 AM
    Friday, August 7, 2020 5:42 AM
  • Hi speed780,
    Has your problem been solved? If it is resolved, we suggest that you mark it as the answer. So it can help other people who have the same problem find a solution quickly.
    Best Regards,
    Daniel Zhang


    "Windows Forms General" forum will be migrating to a new home on Microsoft Q&A (Preview)!
    We invite you to post new questions in the "Windows Forms General" forum’s new home on Microsoft Q&A (Preview)!
    For more information, please refer to the sticky post.

    Wednesday, August 12, 2020 9:35 AM
  • var employees = (from e in xml.Root.Elements("Employee")
                     let r = e.Element("Region")
                     where (string)r.Attribute("name") == "West"
                     select new Employee
                     {
                         EmployeeName = (string)e.Attribute("employee"),
                         EmployeeDeptId = (string)e.Attribute("deptId"),
                         RegionName = (string)r.Attribute("name"),
                         AreaCode = (string)r.Element("Area").Attribute("code"),
                     }).ToList();
    But it will still require query revision when XML file structure changes.

    Edit

    Query for multiple regions per employee:

    var employees = (from e in xml.Root.Elements("Employee")
                     select new Employee
                     {
                         EmployeeName = (string)e.Attribute("employee"),
                         DeptId = (string)e.Attribute("deptId"),
                         RegionList = e.Elements("Region")
                                       .Select(r => new Region {
                                           RegionName = (string)r.Attribute("name"),
                                           AreaCode = (string)r.Element("Area").Attribute("code")
                                       }).ToList()
                     }).ToList();
    You can then filter the list for employees from given region only:

    var westEmployees = employees.Where(x => x.RegionList.Any(r => r.RegionName == "West")).ToList();
    Wednesday, August 12, 2020 10:40 AM
  • Hi speed780,
    If the solution we provide solves your problem, please mark it as an answer.
    So it can help other people who have the same problem find a solution quickly.
    Thank you for your understanding.
    Best Regards,
    Daniel Zhang


    "Windows Forms General" forum will be migrating to a new home on Microsoft Q&A (Preview)!
    We invite you to post new questions in the "Windows Forms General" forum’s new home on Microsoft Q&A (Preview)!
    For more information, please refer to the sticky post.

    Friday, August 28, 2020 2:03 AM