我的XML代码或.NET中是否有错误?

Bri*_*iec 1 .net c# xml xpath

我刚遇到一个问题,我的代码正在解析xml,但是一旦我在第二个节点中添加它就开始加载不正确的数据.真正的代码涵盖了许多类和项目,但是对于样本我已经汇总了导致问题的基础知识

当代码运行时,我希望输出是第二个Task节点的内容,而是输出第一个节点的内容.尽管如何检查设置对象,其内部xml是第二个Task节点的内部xml,它仍然会从第一次出现的EmailAddresses节点开始拉出.呼叫SelectSingleNode("//EmailAddresses")是问题发生的地方.

我有两种解决这个问题的方法

  1. 从EmailAddresses XPath表达式中删除前导斜杠
  2. Clone()获取"任务"或"设置"节点后调用

解决方案1适用于这种情况,但我相信这会导致我的项目中的其他代码停止工作.

对于我而言,解决方案2看起来更像是一个真正的解决方案.

我的问题是我实际上正确地做了这个并且.NET中存在一个错误(所有版本)或者我只是把XML拉错了?

c#代码

var doc = new XmlDocument();
doc.Load(@"D:\temp\Sample.xml");

var tasks = doc.SelectSingleNode("Server/Tasks");

foreach (XmlNode threadNode in tasks.ChildNodes)
{
    if (threadNode.Name.ToLower() != "thread")
    {
        continue;
    }

    foreach (XmlNode taskNode in threadNode.ChildNodes)
    {
        if (taskNode.Name.ToLower() != "task" || taskNode.Attributes["name"].Value != "task 1")
        {
            continue;
        }

        var settings = taskNode.SelectSingleNode("Settings");

        var emails = settings.SelectSingleNode("//EmailAddresses");

        Console.WriteLine(emails.InnerText);
    }
}
Run Code Online (Sandbox Code Playgroud)

XML

<?xml version="1.0"?>
<Server>
    <Tasks>
        <Thread>
            <Task name="task 2">
                <Settings>
                    <EmailAddresses>task 2 data</EmailAddresses>
                </Settings>
            </Task>
        </Thread>
        <Thread>
            <Task name="task 1">
                <Settings>
                    <EmailAddresses>task 1 data</EmailAddresses>
                </Settings>
            </Task>
        </Thread>
    </Tasks>
</Server>
Run Code Online (Sandbox Code Playgroud)

小智 5

来自http://www.w3.org/TR/xpath/#path-abbrev

//是的缩写 /descendant-or-self::node()/.例如,//para是短的 /descendant-or-self::node()/child::para ,因此将选择文档中的任何para元素(//para因为文档元素节点是根节点的子节点,因此将选择作为文档元素的para元素);

并且:

位置步骤.很短 self::node().这与结合起来特别有用//.例如,位置路径.//para 很短

self::node()/descendant-or-self::node()/child::para
Run Code Online (Sandbox Code Playgroud)

因此将选择上下文节点的所有para后代元素.

代替:

var settings = taskNode.SelectSingleNode("Settings");

var emails = settings.SelectSingleNode("//EmailAddresses");
Run Code Online (Sandbox Code Playgroud)

使用:

var emails = taskNode.SelectSingleNode("Settings/EmailAddresses");
Run Code Online (Sandbox Code Playgroud)