.net 慢速选择单节点

.net 慢速选择单节点,.net,xml,performance,.net-3.5,.net,Xml,Performance,.net 3.5,我有一个简单的结构化XML文件,如下所示: <ttest ID="ttest00001", NickName="map00001"/> <ttest ID="ttest00002", NickName="map00002"/> <ttest ID="ttest00003", NickName="map00003"/> <ttest ID="ttest00004", NickName="map00004"/> nickNameLoopNum = M

我有一个简单的结构化XML文件,如下所示:

<ttest ID="ttest00001", NickName="map00001"/>
<ttest ID="ttest00002", NickName="map00002"/>
<ttest ID="ttest00003", NickName="map00003"/>
<ttest ID="ttest00004", NickName="map00004"/>
nickNameLoopNum = MyXmlDoc.SelectSingleNode("//ttest[@ID=' + testloopNum + "']").Attributes["NickName"].Value
这条线需要30到40毫秒


我搜索了一些旧文章(追溯到2002年)说,使用某种编译的“xpath”可以帮助解决这个问题,但那是5年前的事了。我想知道有没有一种现代的方法可以使它更快?(我正在使用.NET 3.5)

在这种情况下,您可能需要考虑将XML文件中的昵称读入数组(如果您的测试ID确实是顺序整数)或字典(如果不是),则使用它来定位每个昵称,而不是尝试一堆XPath查询。通过这种方式,您可能会获得更好的查找性能

编辑:类似这样的内容(伪代码)

var昵称=新字典();
foreach(MyXmlDoc.ChildNodes中的XmlNode节点)
{
if(节点是XmlElement)
{
添加(node.Attributes[“ID”]、node.Attributes[“昵称”]);
}
}
...
昵称LoopNum=昵称[testLoopNum];

您已经在使用XPath(“//ttest…”),这是访问文档节点的最慢方式,因为“/”语法贯穿整个文档

试试像

foreach (XMLNode node in MyXmlDoc.ChildNodes) {
    ...
}
相反,不需要xpath,而且应该更快。(隐式假设它是一个没有嵌套的“扁平”xml文件。如果是这样,您很快就会递归my lad)。

在XPath表达式中使用“
/
”缩写会导致效率大大降低,因为它会导致搜索整个xml文档。反复使用“
/
”会使这种效率倍增

该问题的一个有效解决方案是通过只计算一个XPath表达式来获取所有“
昵称
”属性节点:

ttest/@昵称

其中,上下文节点是所有“
ttest
”元素的父节点

C#代码将如下所示:

    int n = 15;
    XmlDocument doc = new XmlDocument();
    doc.Load("MyFile.xml");

    XmlNodeList nodeList;
    XmlNode top = doc.DocumentElement;
    nodeList =
        top.SelectNodes("ttest/@NickName");

    // Get the N-th NickName, can be done in a loop for
    // all n in a range

    string nickName = nodeList[n].Value;
这里我们假设“ttest”元素是xml文档顶部元素的子元素

总而言之,提出了一种有效的解决方案,它只对XPath表达式求值一次,并将所有结果放在一个方便的IEnumerable对象(可以用作数组)中,以访问时间
O(c)
中的任何必需项。

回答Dimitre

实际上。。。选择整个节点比只选择属性更快

我有一个单元测试,对下面的代码进行基准测试,(令人惊讶的是)选择完整节点并处理属性比选择属性并直接获取值要快

将其放入10000个迭代循环中,交换注释以进行测试

 //XmlNodeList nodeList = document.SelectNodes("test/@NickName");
            XmlNodeList nodeList = document.SelectNodes("test");
            foreach (XmlNode node in nodeList)
            {
                //string nickName = node.Value;
                string nickName = ((XmlAttribute)node.Attributes.GetNamedItem("NickName")).Value;

            }

我知道这是违反直觉的,但是。。。。你必须测量

在提供解决方案之前-循环的目标是什么?你是想得到所有昵称的列表吗?ID为=“ttest*”的节点的所有昵称?与其浪费每个SelectSingleNode 30/40毫秒的时间,我们还可以在一次呼叫中完成所有任务,但我不知道您的目标是什么。请检查我的答案,然后自己测试代码。你会感到惊讶。@argatha:我没有说过立即选择属性更快,只是只选择必要的节点比扫描整个树更快。如果整个树只包含我们想要选择的节点,那么我们可以选择任何一种方式。然而,在实践中有许多情况下,XML文档包含许多根本不包含任何节点的大型子树。测试这些案例,做到公正。
 //XmlNodeList nodeList = document.SelectNodes("test/@NickName");
            XmlNodeList nodeList = document.SelectNodes("test");
            foreach (XmlNode node in nodeList)
            {
                //string nickName = node.Value;
                string nickName = ((XmlAttribute)node.Attributes.GetNamedItem("NickName")).Value;

            }