2016-08-30 6 views
1

Вот моя примерная XML-схема, созданная SQL Server. Я хочу, чтобы он назначал List<class> в C# с помощью LINQ. Я попробовал, но я получаю шесть строк, но после разбора этого XML. Я должен получить только один ряд в списке.Как обрабатывать XML-файл в список C# <T> на условной основе?

Есть несколько условий для анализа этого XML.

  • TYPE == 1, то SMS,
  • TYPE == 3 затем DATA
  • TYPE == 2, то ПРОТОКОЛ

XML:

<summary> 
    <period>Jul-2016</period> 
    <providerid>7</providerid> 
    <type>1</type> 
    <volume>2981655</volume>   
</summary> 
<summary> 
    <period>Jul-2016</period> 
    <providerid>7</providerid> 
    <type>2</type> 
    <volume>6449570</volume> 
</summary> 
<summary> 
    <period>Jul-2016</period> 
    <providerid>7</providerid> 
    <type>3</type> 
    <volume>7702484</volume> 
</summary>   

Вот мой C# класса. Я хочу проанализировать эту XML-схему в List<UsageSummary>. После разбора это будет только два ряда в List<UsageSummary>. Я использовал XDocument.Parse для синтаксического анализа XML. После этого я использую метод Linq .Descendants, но я получаю шесть строк, но вывод должен содержать только одну строку.

public class UsageSummary 
{  
     public int carrierID { get; set; } 
     public Int64 minutes { get; set; } 
     public Int64 sms { get; set; } 
     public Int64 data { get; set; } 
     public string period { get; set; } 
} 

Я использовал этот код:

List<UsageSummary> obj = new List<UsageSummary>(); 

obj = (from res in xmlDoc.Descendants("summary") 
     select new UsageSummary 
        { 
         carrierID = (Convert.ToInt16(res.Element("providerid").Value)),     
         period = res.Element("period").Value.ToString(), 
         sms = (Convert.ToInt64(res.Element("SMS").Value)), 
         data = (Convert.ToInt64(res.Element("DATA").Value)), 
         minutes = (Convert.ToInt64(res.Element("MINUTES").Value)) 
        }).ToList();  

Пожалуйста, помогите мне с этой проблемой.

+0

выход содержит одну строку, какой из них, что такое состояние, и вы можете поделиться код, который вы пытались – Mostafiz

+0

я отправил ответ, который я использовал в своем коде, но получаю три строки, но должна содержать одну строку. –

+0

с учетом данных, которые вы опубликовали, тогда у вас должно быть три строки (без применения фильтрации и/или группировки). Есть ли еще какие-либо общие элементы xml, которые не отображаются в разделе входных данных вашего сообщения? –

ответ

1

Вам необходимо сгруппировать элементы. Вы можете разделить проблему на 3 части, чтобы вы не пытались все это сразу.

Во-первых, сопоставить XML на структуру, которая отражает структуру XML:

var items = 
    from summary in doc.Descendants("summary") 
    select new 
    { 
     Period = (string) summary.Element("period"), 
     CarrierId = (int) summary.Element("providerid"), 
     Type = (int) summary.Element("type"), 
     Volume = (long) summary.Element("volume") 
    }; 

Тогда группа их по CarrierId и Period. Для Volume, вы хотите поиск всех томов по Type:

var volumesByPeriodAndCarrier = 
    from item in items 
    group item by new {item.CarrierId, item.Period} 
    into grouping 
    select new 
    { 
     grouping.Key.CarrierId, 
     grouping.Key.Period, 
     VolumeByType = grouping.ToLookup(x => x.Type, x => x.Volume) 
    }; 

Затем вы можете легко создавать свои резюме. CarrierId и Period карту непосредственно в класс, и 3-х томах, где вы использовать отображение из типов для полей и суммировать итоги:

var summaries = volumesByPeriodAndCarrier 
    .Select(x => new UsageSummary 
    { 
     carrierID = x.CarrierId, 
     minutes = x.VolumeByType[2].Sum(), 
     sms = x.VolumeByType[1].Sum(), 
     data = x.VolumeByType[3].Sum(), 
     period = x.Period 
    }).ToList(); 

См this fiddle для рабочей демонстрации.

+0

Это правильное решение. Но здесь пункт. Я повторяю данные за один месяц. Как и вышеприведенные данные XML повторяются в течение одного месяца. Я имею в виду, что у меня будет 3 записи за каждый день в месяц. это означает, что для этого же провайдера будет 90 записей с другим набором томов. Поэтому в этом сценарии мы не можем использовать класс Dictionary здесь, потому что он не может содержать дубликат ключа (типа). –

+0

Вы можете использовать поиск (например, 'grouping.ToLookup (x => x.Type, x => x.Volume'), а затем делать то, что вы хотите в проекции с несколькими томами. Вы могли бы их суммировать, например:' x.VolumeByType [2] .Sum() '. –

+0

Да, то же самое я пытаюсь. –

1

Это решение реализовано с использованием технологии «поворота» linq.

Pivoting состоит из сбора различных типов данных, каждый из которых соответствует заданной записи данных (или узлам xml в нашем примере) в полях одной записи (или объекта ..).

В нашем случае каждый шарнирный объект содержит «набор» различных типов данных (на которых вы можете управлять несколькими операторами агрегации) определенной группировки исходного набора данных.

В частности, это позволяет суммировать volume значения по type, providerid и period, и это становится нулевой (0) для отсутствующих type значений XML-элементов.

List<UsageSummary> obj = new List<UsageSummary>(); 

obj = (from xmlsummary in doc.Descendants("summary") 
     group xmlsummary by new { id = xmlsummary.Element("providerid").Value, period = xmlsummary.Element("period").Value } into summaryGrouped 
     select new UsageSummary{ 
       carrierID = Convert.ToInt16(summaryGrouped.Key.id), 
       period = summaryGrouped.Key.period, 
       sms = (summaryGrouped.Where(sg => sg.Element("type").Value.Equals("1")).Select(v => Convert.ToInt64(v.Element("volume").Value)).Sum()), 
       minutes = (summaryGrouped.Where(sg => sg.Element("type").Value.Equals("2")).Select(v => Convert.ToInt64(v.Element("volume").Value)).Sum()), 
       data = (summaryGrouped.Where(sg => sg.Element("type").Value.Equals("3")).Select(v => Convert.ToInt64(v.Element("volume").Value)).Sum()) 
       } 
    ).ToList(); 
+0

У меня есть данные за один месяц. Как и вышеприведенные данные XML повторяются в течение одного месяца. Я имею в виду, что у меня будет 3 записи за каждый день в месяц, это означает, что это будет 90 записей для того же поставщика с другим набором томов, поэтому в этом сценарии мы не можем использовать словарь, потому что он не может содержать дубликат ключа (типа). g, но после поиска мне нужно суммировать, потому что есть дубликат ключа в поиске, так как это сделать? –

+0

На самом деле я попросил вас только это требование .. см. Мой комментарий на вашем OP! Почему вы подтвердили ответ Mager, поскольку он делает тот же самый запрос моего запроса (что это компактная и правильная версия его версии)? –

+0

u оба имеют правильный ответ, но здесь ваш ответ немного компактный, но хороший. теперь что делать дальше? –