[英]How to process XML file into C# List<T> on conditional basis?
这是我的SQL Server生成的示例XML模式。 我希望它使用LINQ在C#中分配给List<class>
。 我试了一下,但是在解析此XML之后得到了六行。 我应该在列表中仅得到一行。
有一些条件可以解析此XML。
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();
请帮助我解决这个问题。
您需要对元素进行分组。 您可以将问题分为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();
请参阅此小提琴以获得有效的演示。
此解决方案是使用linq“透视”技术实现的。
数据透视包括在一个记录(或对象..)的字段中收集不同类型的数据,每个数据对应于一个给定的数据记录(在我们的示例中为xml节点)。
在我们的例子中,每个枢纽对象都包含原始数据集特定分组的不同类型数据的“集合”(可以在其上操作多个聚合运算符)。
特别是,它允许按type
, providerid
和period
来对volume
值求和,对于缺少的xml type
元素值,它会得到零( 0
)。
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();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.