2013-12-17 3 views
2

Я пытаюсь использовать XDocument для анализа XML-документа, однако я довольно новичок в XML и в прошлом использовал только JSON. Пока я могу анализировать каждое имя отчета, но застрял в попытке разобрать список параметров. Как разобрать список параметров, когда нет узла, дифференцирующего различные параметры?Разбор XML с парами элементов с использованием XDocument и LINQ

var reports = xml.Descendants("Report").Select(reportElement => new 
{ 
    Name = reportElement.Attribute("Name").Value, 
    Parameters = reportElement.Descendants("ParameterList").Select(parameter => new 
    { 
    }) 
}); 

XML:

<ReportList> 
    <Report Name="JobNotClose"> 
     <ParameterList> 
      <Name>@StationCode</Name><Value>LAX</Value> 
      <Name>@ShipmentType</Name><Value>SE|SI</Value> 
     </ParameterList> 
    </Report> 
    <Report Name="JobWithoutSales"> 
     <ParameterList> 
      <Name>@StationCode</Name><Value>PA</Value> 
      <Name>@JobDateFrom</Name><Value>2013-10-1</Value> 
      <Name>@JobDateTo</Name><Value>2013-10-31</Value> 
     </ParameterList> 
    </Report> 
</ReportList> 
+1

Это xml выглядит немного растрепанным для меня. Предполагается, что параметр не должен быть ? – Alex

+0

Вот что я спросил, но нет, так оно и будет отформатировано. если бы это был узел , я бы просто использовал '.Descendants()' Я не совсем уверен, что с ним делать, структурированный таким образом – ChaoticLoki

ответ

2

Вы можете использовать Enumerable.Zip сливаться последовательность имен параметров с параметром значения последовательности:

var reports = from r in xml.Root.Elements("Report") 
       let parameters = r.Element("ParameterList") 
       select new { 
        Name = (string)r.Attribute("Name"), 
        Parameters = parameters.Elements("Name") 
             .Zip(parameters.Elements("Value"), 
               (n,v) => new { 
                Name = (string)n, 
                Value = (string)v 
               }) 
       }; 

Это дает следующие отчеты коллекции:

[ 
    { 
    "Name": "JobNotClose", 
    "Parameters": [ 
     { 
     "Name": "@StationCode", 
     "Value": "LAX" 
     }, 
     { 
     "Name": "@ShipmentType", 
     "Value": "SE|SI" 
     } 
    ] 
    }, 
    { 
    "Name": "JobWithoutSales", 
    "Parameters": [ 
     { 
     "Name": "@StationCode", 
     "Value": "PA" 
     }, 
     { 
     "Name": "@JobDateFrom", 
     "Value": "2013-10-1" 
     }, 
     { 
     "Name": "@JobDateTo", 
     "Value": "2013-10-31" 
     } 
    ] 
    } 
] 
0

Возможно, это будет работать.

Вы можете использовать элементы ParameterList как IEnumerable, используя XNode.ElementsAfterSelf. Затем проведите через результирующий набор и предположите, что элементы находятся в парах.

Это, по существу, даст вам возможность проанализировать элементы в том порядке, в котором они отображаются в ParameterList, не беспокоясь о том, что .Descendants возились с порядком.

Конечно, большое допущение состоит в том, что элементы всегда попарно.

1

Попробуйте это (и попробовать я имею в виду использование):

var reports = xml.Descendants("Report").Select(reportElement => new 
{ 
    Name = reportElement.Attribute("Name").Value, 
    Parameters = reportElement.Descendants("ParameterList").Select(parameter => 
    { 
     List<string> names = parameter.Elements("Name").Select(x=>x.Value).ToList(); 
     List<string> values = parameter.Elements("Value").Select(x=>x.Value).ToList(); 

     List<object> pairs=new List<object>(); 

     for (int i = 0; i < names.Count; i++) 
     { 
      pairs.Add(new { Name = names[i], Value = values[i] }); 
     } 

     return pairs;      
    }).ToList() 
}).ToList(); 

Вы можете удалить оба ToList() вызовы. Это просто облегчило испытание. Конечно, есть вероятность, что в вашем XML теги <Name> <Value> не всегда завершены (то есть Name без Value). Вы можете проверить это, прежде чем делать цикл for.

EDIT: альтернатива:

Dictionary<string, List<Tuple<string, string>>> rep = new Dictionary<string, List<Tuple<string, string>>>(); 

foreach (XElement report in xml.Elements("Report")) 
{ 
    rep.Add(report.Attribute("Name").Value, new List<Tuple<string, string>>()); 

    List<string> names = report.Elements("ParameterList").FirstOrDefault().Elements("Name").Select(x => x.Value).ToList(); 
    List<string> values = report.Elements("ParameterList").FirstOrDefault().Elements("Value").Select(x => x.Value).ToList(); 

    for (int i = 0; i < names.Count; i++) 
    { 
     rep[report.Attribute("Name").Value].Add(new Tuple<string, string>(names[i], values[i])); 
    } 
} 
+0

Разве это не сделает Parameters List List? Возможно, я написал это неправильно с начала Параметра. Насколько я понимаю, каждый отчет будет содержать только один узел ParameterList и внутри него несколько пары – ChaoticLoki

+0

@ChaoticLoki, да, это делает список списков. Это недостаток этого метода. Есть и другие подходы. Этот был построен на вашей логике. –

Смежные вопросы