我必须从Internet加载许多XML文件.但是为了以更好的速度进行测试,我下载了以下格式的所有内容(超过500个文件).
我必须从Internet加载许多XML文件.但是为了以更好的速度进行测试,我下载了以下格式的所有内容(超过500个文件).
36
Adam Gilchrist
Australia
Gilchrist
A Gilchrist
Nov 14, 1971
Left-hand bat
Right-arm offbreak
Wicket-Keeper
Western Australia, New South Wales, ICC World XI, Deccan Chargers, Australia
Deccan Chargers
ODI
287
279
11
9619
172
9922
149
1000+
0
55
417
55
16
96.95
35.89
.
.
.
.
.
.
.
.
.
ODI
378
58
64
3
0
0
19.33
6.62
21.33
.
.
.
.
.
.
.
.
.
我在用
XmlNodeList list = _document.SelectNodes("/player-profile/batting-statistics/odi-stats");
然后使用foreach循环此列表
foreach (XmlNode stats in list)
{
_btMatchType = GetInnerString(stats, "matchtype"); //it returns null string if node not availible
.
.
.
.
_btAvg = Convert.ToDouble(stats["average"].InnerText);
}
即使我正在离线加载所有文件,解析也很慢
有没有更快的解析方法?或者它是SQL的问题?我正在使用带有插入命令的DataSet,TableAdapters将所有提取的数据从XML保存到数据库.
编辑:现在使用XmlReader请为上面的文档提供一些XmlReader代码.现在,我做到了这一点
void Load(string url)
{
_reader = XmlReader.Create(url);
while (_reader.Read())
{
}
}
XmlReader的可用方法令人困惑.我需要的是完全击球和保龄球数据,击球和保龄球统计数据是不同的,而odi,t2o,ipl等在保龄球和击球中是相同的.
解决方法:
抛出异常的开销可能使XML解析的开销相形见绌.您需要重写代码,以便它不会抛出异常.
一种方法是在询问元素之前检查元素是否存在.这将有效,但它是很多代码.另一种方法是使用地图:
Dictionary map = new Dictionary
{
{ "matchtype", null },
{ "matches", null },
{ "ballsbowled", null }
};
foreach (XmlElement elm in stats.SelectNodes("*"))
{
if (map.ContainsKey(elm.Name))
{
map[elm.Name] = elm.InnerText;
}
}
此代码将处理您关注其名称的所有元素,并忽略您不关注的元素.如果map中的值为null,则表示具有该名称的元素不存在(或没有文本).
实际上,如果您将数据放入DataTable中,并且DataTable中的列名与XML中的元素名相同,则甚至不需要构建映射,因为DataTable.Columns属性是你需要的所有地图.此外,由于DataColumn知道它包含哪种数据类型,因此您无需在代码中复制该知识:
foreach (XmlElement elm in stats.SelectNodes("*"))
{
if (myTable.Columns.Contains(elm.Name))
{
DataColumn c = myTable.Columns[elm.Name];
if (c.DataType == typeof(string))
{
myRow[elm.Name] = elm.InnerText;
continue;
}
if (c.DataType == typeof(double))
{
myRow[elm.Name] = Convert.ToDouble(elm.InnerText);
continue;
}
throw new InvalidOperationException("I didn't implement conversion logic for " + c.DataType.ToString() + ".");
}
}
请注意我没有声明任何变量来存储这些信息,所以我没有机会搞砸并声明一个与它存储的列不同的数据类型的变量,或者在我的表中创建一个列并忘记实现填充它的逻辑.
编辑
好的,这里的东西有点棘手.这是Python中非常常见的技术;在C#中我认为大多数人仍然认为它有些奇怪.
如果你看看我给出的第二个例子,你可以看到它正在使用DataColumn中的元信息来确定用于将元素的值从文本转换为其基类型的逻辑.您可以通过构建自己的地图来完成同样的事情,例如:
Dictionary typeMap = new Dictionary
{
{ "matchtype", typeof(string) },
{ "matches", typeof(int) },
{ "ballsbowled", typeof(int) }
}
然后做我在第二个例子中展示的相同的东西:
if (typeMap[elm.Name] == typeof(int))
{
result[elm.Name] = Convert.ToInt32(elm.Text);
continue;
}
您的结果不再是字典,因为现在它们可以包含非字符串的内容;它们必须是Dictionary.
但这种逻辑看起来有点笨拙;你正在多次测试每个项目,有继续声明要突破它 – 它并不可怕,但它可能更简洁.怎么样?通过使用另一个映射,将类型映射到转换函数:
Dictionary> cOnversionMap=
new Dictionary>
{
{ typeof(string), (x => x) },
{ typeof(int), (x => Convert.ToInt32(x)) },
{ typeof(double), (x => Convert.ToDouble(x)) },
{ typeof(DateTime), (x => Convert.ToDateTime(x) }
};
如果你不习惯lambda表达式,这有点难以阅读.类型Func指定一个以字符串作为参数并返回对象的函数.这就是该映射中的值是什么:它们是lambda表达式,也就是说函数.它们采用字符串参数(x),然后返回一个对象. (我们怎么知道x是一个字符串?Func告诉我们.)
这意味着转换元素可以占用一行代码:
result[elm.Name] = conversionMap[typeMap[elm.Name]](elm.Text);
从内部表达式转到外部表达式:这会在typeMap中查找元素的类型,然后在conversionMap中查找转换函数,并调用该函数,并将其作为参数传递给elm.Text.
在您的情况下,这可能不是理想的方法.我真的不知道.我在这里展示它是因为有一个更大的问题在起作用.正如Steve McConnell在Code Complete中指出的那样,调试数据比调试代码更容易.此技术允许您将程序逻辑转换为数据.在某些情况下,使用此技术可以大大简化程序的结构.值得了解.