直接在根元素下方读取XML节点数量的最有效方法



我需要计算直接位于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身体为Stream

您可以使用linq到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

确实可以忽略不计,除非您做了很多迭代

您不太可能比:

更有效
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,则会逐渐递增其tally;也就是说,直接在根节点下方。

当然,它会比构建XDocumentXmlDocument的任何内容都更快,因为它不会花费时间和内存这样做,尽管如果您要使用XDocumentXmlDocument作为其他东西,那么这些方法会更快地(对他们来说,计数位很快,并且已经花费了花费的时间)。

如果您要阅读几个这样的文档,并且它们具有很多XML名称(元素和属性名称,名称名称和名称空间前缀),那么您将做得很好,以保持您传递的NameTable对象的缓存进入settings.NameTable属性。Nametables不是线程安全的,因此您不能仅使用相同的方法,但是当"学习"新名称并重复使用它们时,它们最昂贵,从而可以提高性能。但这是True 如果每个文档中都有很多名称;如果文档非常不同,则它们不会从"先验知识"中受益,而您只是在浪费周期,而不是垃圾收集每个新的XmlReader给出的默认一个。(实际上,您的查找非常慢)。

如果您真的想要绝对最有效的能力,那么您可以通过阅读流并跟踪<...></...><.../>来击败上述,但是您还必须处理一堆一堆特殊情况,因此您对上述收益不足以使努力值得。

用您的示例进行10000迭代的粗略数字:

XmlDocument:                     2387373
XDocument:                       1942206
XmlReader:                       1872387
XmlReader with reused NameTable: 1864708

根据您的示例,使用136KIB文件的100次迭代的粗略数字:

XmlDocument:                     1887930
XDocument:                       1297059
XmlReader:                       996636
XmlReader with reused NameTable: 961763

易于轻松:

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());

两者都将OUPUT 4

相关内容

  • 没有找到相关文章

最新更新