读取 XML 并在 C# 中创建元素的频率计数
Reading XML and creating a frequency count of elements in C#
我有一个这种格式的 XML 文件(但只是大得多):
<customer>
<name>John</name>
<age>24</age>
<gender>M</gender>
</customer>
<customer>
<name>Keith</name>
<age></age> <!--blank value-->
<gender>M</gender>
</customer>
<customer>
<name>Jenny</name>
<age>21</age>
<gender>F</gender>
</customer>
<customer>
<name>John</name>
<age>24</age> <!--blank value-->
<gender>M</gender> <!--blank value-->
</customer>
我想生成一个格式如下的 DataTable :
Element Name Value Frequency
name filled 4
name blank 0
age filled 2
age blank 2
gender filled 3
gender blank 1
目前我分两部分完成这个任务,首先创建一个如上所述的数据表结构并将所有频率设置为 0 作为默认值。然后使用 XmlReader 读取 XML,并在每次 XmlReader 找到子元素时增加频率计数。
我的问题是,我用于添加实际计数的第二个函数对于非常大的 Xml 文件来说花费的时间太长,其中许多客户具有许多属性。如何提高这个函数的效率?
我的代码:
static void AddCount(DataTable dt)
{
int count;
using (XmlReader reader = XmlReader.Create(@"C:\Usr\sample.xml"))
{
while (reader.Read())
{
if (reader.IsStartElement())
{
string eleName = reader.Name;
DataRow[] foundElements = dt.Select("ElementName = '" + eleName + "'");
if (!reader.IsEmptyElement)
{
count = int.Parse(foundElements.ElementAt(0)["Frequency"].ToString());
foundElements.ElementAt(0).SetField("Frequency", count + 1);
}
else
{
count = int.Parse(foundElements.ElementAt(0)["Frequency"].ToString());
foundElements.ElementAt(0).SetField("Frequency", count + 1);
}
}
}
}
}
我也准备将 XmlReader class 更改为任何其他更有效的 class 以完成此任务。欢迎任何建议。
试试这个逻辑,目前我这里只取了一个属性即Name
XDocument xl = XDocument.Load(@"C:\Usr\sample.xml");
var customers = xl.Descendants("Customer");
var customerCount = customers.Count();
var filledCustomers = customers.Where(x => x.Element("Name").Value != string.Empty).Count();
var nonfilledCustomers = customerCount - filledCustomers;
您可以使用以下代码:
using (XDocument xdoc = XDocument.Load(@"C:\Users\aks\Desktop\sample.xml"))
{
var customers = xdoc.Descendants("customer");
var totalNodes = customers.Count();
var filledNames = customers.Descendants("name").Where(x => x.Value != string.Empty).Count();
var filledAges = customers.Descendants("age").Where(x => x.Value != string.Empty).Count();
var filledGenders = customers.Descendants("gender").Where(x => x.Value != string.Empty).Count();
var unfilledNames = totalNodes - filledNames;
var unfilledAges = totalNodes - filledAges;
var unfilledGenders = totalNodes - filledGenders;
}
事实证明,使用 Select 操作在 DataTable 中查询非常昂贵,这使得我的函数非常慢。
取而代之,使用 Dictionary<string, ValueFrequencyModel>
并对其进行查询以用计数填充字典,完成后,将 Dictionary<string, ValueFrequencyModel>
转换为数据表。
这为我节省了大量时间并解决了问题。
我有一个这种格式的 XML 文件(但只是大得多):
<customer>
<name>John</name>
<age>24</age>
<gender>M</gender>
</customer>
<customer>
<name>Keith</name>
<age></age> <!--blank value-->
<gender>M</gender>
</customer>
<customer>
<name>Jenny</name>
<age>21</age>
<gender>F</gender>
</customer>
<customer>
<name>John</name>
<age>24</age> <!--blank value-->
<gender>M</gender> <!--blank value-->
</customer>
我想生成一个格式如下的 DataTable :
Element Name Value Frequency
name filled 4
name blank 0
age filled 2
age blank 2
gender filled 3
gender blank 1
目前我分两部分完成这个任务,首先创建一个如上所述的数据表结构并将所有频率设置为 0 作为默认值。然后使用 XmlReader 读取 XML,并在每次 XmlReader 找到子元素时增加频率计数。
我的问题是,我用于添加实际计数的第二个函数对于非常大的 Xml 文件来说花费的时间太长,其中许多客户具有许多属性。如何提高这个函数的效率?
我的代码:
static void AddCount(DataTable dt)
{
int count;
using (XmlReader reader = XmlReader.Create(@"C:\Usr\sample.xml"))
{
while (reader.Read())
{
if (reader.IsStartElement())
{
string eleName = reader.Name;
DataRow[] foundElements = dt.Select("ElementName = '" + eleName + "'");
if (!reader.IsEmptyElement)
{
count = int.Parse(foundElements.ElementAt(0)["Frequency"].ToString());
foundElements.ElementAt(0).SetField("Frequency", count + 1);
}
else
{
count = int.Parse(foundElements.ElementAt(0)["Frequency"].ToString());
foundElements.ElementAt(0).SetField("Frequency", count + 1);
}
}
}
}
}
我也准备将 XmlReader class 更改为任何其他更有效的 class 以完成此任务。欢迎任何建议。
试试这个逻辑,目前我这里只取了一个属性即Name
XDocument xl = XDocument.Load(@"C:\Usr\sample.xml");
var customers = xl.Descendants("Customer");
var customerCount = customers.Count();
var filledCustomers = customers.Where(x => x.Element("Name").Value != string.Empty).Count();
var nonfilledCustomers = customerCount - filledCustomers;
您可以使用以下代码:
using (XDocument xdoc = XDocument.Load(@"C:\Users\aks\Desktop\sample.xml"))
{
var customers = xdoc.Descendants("customer");
var totalNodes = customers.Count();
var filledNames = customers.Descendants("name").Where(x => x.Value != string.Empty).Count();
var filledAges = customers.Descendants("age").Where(x => x.Value != string.Empty).Count();
var filledGenders = customers.Descendants("gender").Where(x => x.Value != string.Empty).Count();
var unfilledNames = totalNodes - filledNames;
var unfilledAges = totalNodes - filledAges;
var unfilledGenders = totalNodes - filledGenders;
}
事实证明,使用 Select 操作在 DataTable 中查询非常昂贵,这使得我的函数非常慢。
取而代之,使用 Dictionary<string, ValueFrequencyModel>
并对其进行查询以用计数填充字典,完成后,将 Dictionary<string, ValueFrequencyModel>
转换为数据表。
这为我节省了大量时间并解决了问题。