2013-09-19 4 views
6
<?xml version="1.0" standalone="yes"?> 
<CompanyInfo> 
    <Employee name="Jon" deptId="123"> 
     <Region name="West"> 
     <Area code="96" /> 
     </Region> 
     <Region name="East"> 
     <Area code="88" /> 
     </Region> 
    </Employee> 
</CompanyInfo> 

public class Employee 
{ 
    public string EmployeeName { get; set; } 
    public string DeptId { get; set; } 
    public List<string> RegionList {get; set;} 
} 

public class Region 
{ 
    public string RegionName { get; set; } 
    public string AreaCode { get; set; } 
} 

Я пытаюсь читать этот XML-данные, до сих пор я попытался это:Анализировать XML с помощью LINQ, чтобы получить дочерние элементы

XDocument xml = XDocument.Load(@"C:\data.xml"); 
var xElement = xml.Element("CompanyInfo"); 
if (xElement != null) 
    foreach (var child in xElement.Elements()) 
    { 
     Console.WriteLine(child.Name); 
     foreach (var item in child.Attributes()) 
     { 
      Console.WriteLine(item.Name + ": " + item.Value); 
     } 

     foreach (var childElement in child.Elements()) 
     { 
      Console.WriteLine("--->" + childElement.Name); 
      foreach (var ds in childElement.Attributes()) 
      { 
       Console.WriteLine(ds.Name + ": " + ds.Value); 
      } 
      foreach (var element in childElement.Elements()) 
      { 
       Console.WriteLine("------->" + element.Name); 
       foreach (var ds in element.Attributes()) 
       { 
        Console.WriteLine(ds.Name + ": " + ds.Value); 
       } 
      } 
     }     
    } 

Это позволяет мне получить каждый узел, его имя и значение атрибута и поэтому я могу сохранить эти данные в соответствующем поле в базе данных, но это кажется длинным, и не является гибким, например, если структура XML меняет все те, которые требуется выполнять для операторов foreach, также сложно отфильтровать данные таким образом , Мне нужно написать определенные операторы if для фильтрации данных (например, получить сотрудников только с запада и т. Д.)

Я искал более гибкий способ, с помощью LINQ, что-то вроде этого:

List<Employees> employees = 
       (from employee in xml.Descendants("CompanyInfo") 
       select new employee 
       { 
        EmployeeName = employee.Element("employee").Value, 
        EmployeeDeptId = ?? get data, 
        RegionName = ?? get data, 
        AreaCode = ?? get data,, 
       }).ToList<Employee>(); 

Но я не знаю, как я могу получить значения из дочерних узлов и применить фильтрацию (чтобы получить некоторые сотрудники). Это возможно? Любая помощь приветствуется.

Благодаря

+0

Спасибо, исправлено. – 03Usr

ответ

8
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(); 

Но он все равно будет требовать пересмотра запроса, когда изменение структуры XML файла.

Редактировать

запросов для нескольких регионов на одного работника:

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(); 

Вы можете отфильтровать список для сотрудников только из данного региона:

var westEmployees = employees.Where(x => x.RegionList.Any(r => r.RegionName == "West")).ToList(); 
6

Вы можете отслеживать структуру:

from employee in xml 
     .Element("CompanyInfo")  // must be root 
     .Elements("Employee")   // only directly children of CompanyInfo 

или менее строго

from employee in xml.Descendants("Employee") // all employees at any level 

А затем получить информацию, которую вы хотите:

 select new Employee 
     { 
      EmployeeName = employee.Attribute("name").Value, 
      EmployeeDeptId = employee.Attribute("deptId").Value, 
      RegionName = employee.Element("Region").Attribute("name").Value, 
      AreaCode = employee.Element("Region").Element("Area").Attribute("code").Value, 
     } 

и с объявление десятеричная информацию о различных регионах, предполагая List<Region> Regions свойство:

 select new Employee 
     { 
      EmployeeName = employee.Attribute("name").Value, 
      EmployeeDeptId = employee.Attribute("deptId").Value, 
      //RegionName = employee.Element("Region").Attribute("name").Value, 
      //AreaCode = employee.Element("Region").Element("Area").Attribute("code").Value, 
      Regions = (from r in employee.Elements("Region") select new Region 
         { 
         Name = r.Attribute("name").Value, 
         Code = r.Element("Area").Attribute("code").Value, 
         }).ToList(); 
     } 
+0

Спасибо, но я забыл включить, что каждый сотрудник может охватить более 1 региона (я изменил XML выше), этот запрос только извлекает первые данные региона, есть ли способ получить все регионы для сотрудника? спасибо – 03Usr

+0

Да, но сначала опубликуйте классы Employee and Region. –

+0

Но 'class Employee' не имеет свойств для (списка) регионов. –

2

Вы можете сделать выбор в одном запросе, а затем фильтрацию во втором или объединение их как к одному qu чень:

Два запросы:

 // do te transformation 
     var employees = 
      from employee in xml.Descendants("CompanyInfo").Elements("Employee") 
      select new 
      { 
       EmployeeName = employee.Attribute("name").Value, 
       EmployeeDeptId = employee.Attribute("deptId").Value, 
       Regions = from region in employee.Elements("Region") 
         select new 
          { 
           Name = region.Attribute("name").Value, 
           AreaCode = region.Element("Area").Attribute("code").Value, 
          } 
      }; 

     // now do the filtering 
     var filteredEmployees = from employee in employees 
           from region in employee.Regions 
           where region.AreaCode == "96" 
           select employee; 

Комбинированный один запрос (такой же выход):

  var employees2 = 
      from selectedEmployee2 in 
       from employee in xml.Descendants("CompanyInfo").Elements("Employee") 
       select new 
       { 
        EmployeeName = employee.Attribute("name").Value, 
        EmployeeDeptId = employee.Attribute("deptId").Value, 
        Regions = from region in employee.Elements("Region") 
          select new 
           { 
            Name = region.Attribute("name").Value, 
            AreaCode = region.Element("Area").Attribute("code").Value, 
           } 
       } 
      from region in selectedEmployee2.Regions 
      where region.AreaCode == "96" 
      select selectedEmployee2; 

Но есть одна маленькая вещь, которую вы должны рассмотреть вопрос о добавлении.Для обеспечения надежности вам необходимо проверить наличие ваших элементов и атрибутов, тогда выбор будет выглядеть так:

var employees = 
      from employee in xml.Descendants("CompanyInfo").Elements("Employee") 
      select new 
      { 
       EmployeeName = (employee.Attribute("name") != null) ? employee.Attribute("name").Value : string.Empty, 
       EmployeeDeptId = (employee.Attribute("deptId") != null) ? employee.Attribute("deptId").Value : string.Empty, 
       Regions = (employee.Elements("Region") != null)? 
         from region in employee.Elements("Region") 
         select new 
          { 
           Name = (region.Attribute("name")!= null) ? region.Attribute("name").Value : string.Empty, 
           AreaCode = (region.Element("Area") != null && region.Element("Area").Attribute("code") != null) ? region.Element("Area").Attribute("code").Value : string.Empty, 
          } 
         : null 
      }; 
Смежные вопросы