简体   繁体   中英

Create XML Hierarchy in C# from Text Doc

I need to take in a text document from a server and create an XML hierarchy from it in order to use it in a C# program.

It will be an organizational hierarchy. Here is the same of the text file:

EmployeeID; Employee Name; SupervisorID

1; Bob; 3
2; Mark; 1
3; Jill; 0
4; Ann ; 1

Where the above relationships would be:

Bob's boss is Jill. Mark's boss is Bob, and Jill has no boss.

I want to create an XML file from that data to look something like this:

<Employee> Jill
   <Employee> Bob
      <Employee> Mark </Employee>
      <Employee> Ann </Employee>
  </Employee>
</Employee>

I don't know if this makes sense, because I have never worked with C# or XML before.
Feel free to change how the tags are named, the main things I will need to do:

  1. Be able to get the names of everyone supervised by the same person. (Ex: Mark would want Mark and Ann)

  2. Be able to get the names of all supervisors above an employee (Ex: Mark's would be Bob and Jill)

  3. Be able to get the names of all people under then (Ex: Mark would have nobody, Jill would have everybody, Bob would have Mark and Ann)

I've looked at XElement and XDoc and various tutorials and SO questions but most of the SO questions are too advanced for me at this point, and most of the tutorials aren't trying to create a hierarchy like mine.

Define a class Employee:

public class Employee{
    [XmlIgnore]
    public int ID{get;set;}

    [XmlIgnore]
    public int BossID{get;set;}

    [XmlText]
    public string Name{get;set;}

    [XmlElement("Employee")
    public Employee[] Minions{get;set;}
    public SetMinions(List<Employee> list){
       Minions = list.Where(e=>e.BossID==ID).ToArray();
    }
}

then parse your input:

List<Employee> list = File.ReadAllLines("MyInputFile.txt")
   .Select(l=>new Emplyee(){
        ID = l.Split(';')[0],
        Name= l.Split(';')[1],
        BossID = l.Split(';')[2]}).ToList();

and then set the minions for each:

list.ForEach(e=>e.SetMinions(list));

And produce the XML like this:

  XmlSerializer xser = new XmlSerializer(typeof(Employee));
  xser.Serialize(File.OpenWrite("output.txt", list.First(e=>e.BossID==0)));

If it's not obvious this code is quite dirty and unreliable, add some checks and cleanups

Employee class:

public class Employee
{
    public Employee()
    {
        Subordinates = new List<Employee>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public int SupervisorId { get; set; }
    public List<Employee> Subordinates { get; private set; }

    public XElement ToXml()
    {
        return new XElement("Employee",
                   new XElement("Id", Id),
                   new XElement("Name", Name),
                   new XElement("Subordinates", Subordinates.Select(s => s.ToXml())));
    }
}

And parsing logic:

// dictionary as a storage for data read from file
var Employees = new Dictionary<int,Employee>();

// file reading
var file = File.Open("Input.txt", FileMode.Open);
using (var reader = new StreamReader(file))
{
    reader.ReadLine();
    while (!reader.EndOfStream)
    {
        string line = reader.ReadLine();
        string[] fields = line.Split(';');

        var newEmployee = new Employee { Id = int.Parse(fields[0]), Name = fields[1].Trim(), SupervisorId = int.Parse(fields[2]) };
        Employees.Add(newEmployee.Id, newEmployee);
    }
}

// filling Subordinates within every employee
foreach (var emp in Employees.Values)
{
    if (Employees.ContainsKey(emp.SupervisorId))
        Employees[emp.SupervisorId].Subordinates.Add(emp);
}

// taking first (root) employee by selecting the one with supervisorId == 0
var first = Employees.Values.First(e => e.SupervisorId == 0);

// XML generation
var xml = first.ToXml();

Result that I received from that code with your sample input:

<Employee>
  <Id>3</Id>
  <Name>Jill</Name>
  <Subordinates>
    <Employee>
      <Id>1</Id>
      <Name>Bob</Name>
      <Subordinates>
        <Employee>
          <Id>2</Id>
          <Name>Mark</Name>
          <Subordinates />
        </Employee>
        <Employee>
          <Id>4</Id>
          <Name>Ann</Name>
          <Subordinates />
        </Employee>
      </Subordinates>
    </Employee>
  </Subordinates>
</Employee>

I think that structure is better than you suggested. However, you can easily modify XML structure by modifying ToXml method within Employee class. Following one would give output you suggested:

public XElement ToXml()
{
    return new XElement("Employee",
               new XText(Name),
               Subordinates.Select(s => s.ToXml()));
}

Result:

<Employee>Jill
    <Employee>Bob
        <Employee>Mark</Employee>
        <Employee>Ann</Employee>
    </Employee>
</Employee>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM