我需要计算XML流中根元素下直接位置的节点数。我不关心任何子节点。
例如,对于以下XML,它应该返回4:
<?xml version="1.0" encoding="utf-8"?>
<root>
<node1>
<subnode1_1>
<subnode_1_1_1>
<subnode_1_1_1_1>…</subnode_1_1_1_1>
</subnode_1_1_1>
<subnode_1_1_2>…</subnode_1_1_2>
</subnode1_1>
</node1>
<node2 />
<node3>
<subnode3_1>…</subnode3_1>
<subnode3_2>…</subnode3_2>
<subnode3_3>…</subnode3_3>
</node3>
<node4>…</node4>
</root>
在C#中执行此操作的最有效(我关心执行时间)的方法是什么?假设我有和XML body Stream
。
答案 0 :(得分:4)
您可以使用Linq To XML将其删除:
var count = XDocument.Load(stream).Root.Elements.Count();
//count = 4
就效率而言,在给出的两个答案之间,我的结果是:
var sw = Stopwatch.StartNew();
XmlDocument xml = new XmlDocument();
xml.Load(stream);
int i = xml.LastChild.ChildNodes.Count;
sw.Stop();
//971 ticks
和
var sw = Stopwatch.StartNew();
var count = XDocument.Load(stream).Root.Elements().Count();
sw.Stop();
//860 ticks
确实可以忽略不计的差异,除非你做了很多次迭代
答案 1 :(得分:3)
你不可能比以下更有效率:
public static int GetImmediateChildrenCount(Stream stm)
{
using(stm)
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.CheckCharacters = false; //optomisation - best avoided.
settings.DtdProcessing = DtdProcessing.Ignore;
int count = 0;
using(XmlReader rdr = XmlReader.Create(stm, settings))
while(rdr.Read())
if(rdr.NodeType == XmlNodeType.Element && rdr.Depth == 1)
++count;
return count;
}
}
没有实际编写专门的解析器来做到这一点。
上面扫描了XmlReader
忽略了除了起始,结束和空元素标签的深度以外的所有内容,并且如果深度为1
,则递增其计数;也就是说,直接在根节点下面。
它肯定比构建XDocument
或XmlDocument
的任何东西都快,因为它不会花费时间和内存这样做,但是如果你要使用XDocument
或者XmlDocument
用于其他东西,那么这些方法会更快(计数位对他们来说很快,构建对象所花费的时间已经花掉了。)
如果您要阅读几个这样的文档,并且它们有许多共同的xml名称(元素和属性名称,命名空间名称和名称空间前缀),那么您最好保留NameTable
的缓存传递到settings.NameTable
属性的对象。 NameTables不是线程安全的,所以你不能只使用同一个,但是在“学习”新名称时它们是最昂贵的,并且重用它们可以提高后续的性能。但如果每个文件中有很多相同的名称,则仅是真的;如果文档非常不同,它们不会从“先验知识”中受益,而您只是浪费周期移动它们而不是垃圾收集每个新XmlReader
给出的默认值。 (事实上,你的查找速度稍微慢一些。)
如果您确实希望绝对最有效率,那么您可以通过阅读流并跟踪<...>
,</...>
和{{1但是你还必须处理一堆特殊情况,所以你对上述内容的收益不足以让你付出相应的努力。
使用您的示例进行10000次迭代的粗略数字:
<.../>
基于您的示例,使用136KiB文件进行100次迭代的粗略数字:
XmlDocument: 2387373
XDocument: 1942206
XmlReader: 1872387
XmlReader with reused NameTable: 1864708
答案 2 :(得分:2)
这很简单:
XmlDocument xml = new XmlDocument();
xml.Load(/*path to your file*/);
int i = xml.LastChild.ChildNodes.Count; //as the xml header is first child
Console.WriteLine(i.ToString());
或者@Jonesy说:
int i = XDocument.Load(/*your stream*/).Root.Elements.Count();
Console.WriteLine(i.ToString());
两者都将输出4
。