0

I am trying to load XML data that consists of a collection of Employee objects. The following function works fine for properties that are simple data types like String and Int. I am wondering how can I import data types of complex type. For example,

This function works fine:

private void LoadData()
{
   XDocument employeesDoc = XDocument.Load("Employees.xml");
   List<Employee> data = (from employee in employeesDoc.Descendants("Employee")
      select new Employee
      {
         FirstName= employee.Attribute("FirstName").Value,
         LastName = employee.Attribute("LastName ").Value,
         PhoneNumber = employee.Attribute("PhoneNumber").Value
      }).ToList();
  Employees.ItemsSource = data;
}

Here is the Employee class:

public class Employee
{
  public int Id { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string PhoneNumber { get; set; }
  public Department Department { get; set; }
}

Here is the Department class:

public class Department
{
  public int Id { get; set; }
  public string Name { get; set; }
  public string Description { get; set; }
  public Employee Manager { get; set; }
}

So, if my XML file looks like so:

<Employees>
    <Employee FirstName="John" LastName="Summers" PhoneNumber="703-548-7841" Department="Finance"></Employee>
    <Employee FirstName="Susan" LastName="Hughey" PhoneNumber="549-461-7962" Department="HR"></Employee>

So, if the Department is a complex object and it is a string in XML file, how can I change my LoadData() function to import it into my Employee object collection?

svick
  • 236,525
  • 50
  • 385
  • 514
user118190
  • 2,139
  • 7
  • 29
  • 45
  • 1
    That all depends on how `Department` is serialized and what your XML looks like - there is no catch all answer here. If `Department` is still just a string then the parsing has nothing to do with Linq to XML. – BrokenGlass Nov 07 '11 at 03:40
  • @BrokenGlass - Thanks for the response. As you can see from the XML file, Department is entered as a string. These XML files will be create by non-technical people so everything will be in string format. So given this, how can I tackle the problem? Why would this have nothing to do with LINQ to XML when my first solution is LINQ to XML, is it not? – user118190 Nov 07 '11 at 03:46
  • Because it depends solely on how that string is parsed and mapped to the properties of your `Department` object - and string parsing has nothing to do with Linq to XML – BrokenGlass Nov 07 '11 at 03:47
  • So, given the above XML, how could I map it into my Employee class? Is this possible? – user118190 Nov 07 '11 at 03:52

3 Answers3

0

You have a couple of options, but everything depends how you get your XML (how it was saved). The easiest way (to my mind) to read is:

XmlSerializer serializer = new XmlSerializer(typeof(YourType));
using (TextReader tr = new StreamReader("newSecret.xml"))
{
 YourType rrr = (YourType)serializer.Deserialize(tr);
}

More Examples here: http://msdn.microsoft.com/en-us/library/he66c7f1.aspx

From the other hand if you (for some reasone) should use LINQ - take a look here: LINQ to XML: creating complex anonymous type and here http://blogs.msdn.com/b/xmlteam/archive/2007/03/24/streaming-with-linq-to-xml-part-2.aspx Hope it helps!

Community
  • 1
  • 1
Pavel Kovalev
  • 7,521
  • 5
  • 45
  • 67
  • How will that help in this specific case? How will you convert string into a `Department` object using XML deserialization? – svick Nov 07 '11 at 07:57
  • Patience - the main quality of the Jedi. See my another answer, hope it helps because I dont know you real xml. Anyways. – Pavel Kovalev Nov 07 '11 at 09:18
0

If you can get the list of all departments before you load the employees, you could put the departments into a Dictionary, where the key is the name of the department. You could then load the correct department for each employee:

var departmentsDict = departments.ToDictionary(d => d.Name);

XDocument employeesDoc = XDocument.Load("Employees.xml");
List<Employee> data = (from employee in employeesDoc.Descendants("Employee")
   select new Employee
   {
      FirstName= employee.Attribute("FirstName").Value,
      LastName = employee.Attribute("LastName ").Value,
      PhoneNumber = employee.Attribute("PhoneNumber").Value,
      Department = departmentsDict[employee.Attribute("Department").Value]
   }).ToList();
Employees.ItemsSource = data;

The code might need modification, depending on what you want to do if the department doesn't exist or if someone doesn't have any department specified. This code would throw an exception in both cases.

svick
  • 236,525
  • 50
  • 385
  • 514
0
    using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace ConsoleApplication2
{

    public class Employee
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string PhoneNumber { get; set; }
        public Department Department { get; set; }
    }
    public class Department
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public Employee Manager { get; set; }
    }


    internal class Program
    {
        private static void Main(string[] args)
        {
            String filepath = @"C:\\rrrr.xml";

            #region Create Test Data
            List<Employee> list = new List<Employee>();
            for (int i = 0; i < 5; i++)
            {
                list.Add(new Employee
                             {
                                 Department = new Department
                                                  {
                                                      Description = "bla bla description " + i,
                                                      Id = i,
                                                      Manager = null,
                                                      Name = "bla bla name " + i
                                                  },
                                 FirstName = "First name " + i,
                                 Id = i + i,
                                 LastName = "Last name " + i,
                                 PhoneNumber = Guid.NewGuid().ToString()
                             });
            } 
            #endregion

            #region Save XML
            XmlSerializer serializer = new XmlSerializer(typeof(List<Employee>));
            using (Stream fs = new FileStream(filepath, FileMode.Create))
            {
                using (XmlWriter writer = new XmlTextWriter(fs, Encoding.Unicode))
                {
                    serializer.Serialize(writer, list);
                }
            } 
            #endregion


            //Read from XML

            XmlDocument doc = new XmlDocument();
            doc.Load(filepath);

            List<Employee> newList = new List<Employee>();
            foreach (XmlNode node in doc.GetElementsByTagName("Employee"))
            {
                Employee ee = GetEmploee(node);
                newList.Add(ee);
            }

            //ta da
        }

        public static Employee GetEmploee(XmlNode node)
        {
            return node == null
                       ? new Employee()
                       : new Employee
                             {
                                 Department = GetDepartment(node["Department"]),
                                 FirstName = (node["FirstName"]).InnerText,
                                 LastName = (node["LastName"]).InnerText,
                                 Id = Convert.ToInt32((node["Id"]).InnerText),
                                 PhoneNumber = (node["PhoneNumber"]).InnerText
                             };
        }

        public static Department GetDepartment(XmlNode node)
        {
            return node == null
                       ? new Department()
                       : new Department
                             {
                                 Description = node["Description"].InnerText,
                                 Id = Convert.ToInt32(node["Id"].InnerText),
                                 Manager = GetEmploee(node["Manager"]),
                                 Name = node["Name"].InnerText
                             };
        }
    }
}
Pavel Kovalev
  • 7,521
  • 5
  • 45
  • 67
  • This will serialize and then deserialize the structure into/from XML, but different one than what is in the question. – svick Nov 07 '11 at 11:41
  • I'm serialized objects using XmlSerializer, but I read them like XMLDocument. Sorry, for my English, maybe I'm missing something but you question was about complex types, so I give you an answer. Or you just want use linq to XML instead of my approach? – Pavel Kovalev Nov 07 '11 at 13:23
  • Look at the XML in the question. It has `Department="Finance"` for each employee, not the whole `Department`. And I'm not the one that asked this question. – svick Nov 07 '11 at 16:48
  • Ok, but he asks: "..if the Department is a complex object and it is a string in XML file..." Complex type can't be just a string and complex at the same time. If you'll serialize complex type it will be a more then one string. And further he says "... how can I change my LoadData() function to import it into my Employee object collection" The author should use some kind of mapping to convert XmlDoc to his own types... I'll be glad to help if I get more information or if the author modifies my code under a specific example. – Pavel Kovalev Nov 08 '11 at 01:04