我刚遇到一个问题,我的代码正在解析xml,但是一旦我在第二个节点中添加它就开始加载不正确的数据.真正的代码涵盖了许多类和项目,但是对于样本我已经汇总了导致问题的基础知识
当代码运行时,我希望输出是第二个Task节点的内容,而是输出第一个节点的内容.尽管如何检查设置对象,其内部xml是第二个Task节点的内部xml,它仍然会从第一次出现的EmailAddresses节点开始拉出.呼叫SelectSingleNode("//EmailAddresses")是问题发生的地方.
我有两种解决这个问题的方法
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很短Run Code Online (Sandbox Code Playgroud)self::node()/descendant-or-self::node()/child::para因此将选择上下文节点的所有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)