如果我有XML文档
<root a="value">
<item name="first">
x
<foo name = "firstgrandchild">There is nothing here</foo>
y
<foo name = "secondgrandchild">There is something here</foo>
</item>
<item name="second">
xy
<foo/>
ab
</item>
</root>
我想首先找到第一个出现的节点“item”,然后更新属性,然后我想更新第一次出现的节点“foo”,然后更新属性等,
我的代码如下
myDoc.Load("Items2.xml");
myNode = myDoc.DocumentElement;
mySearchNode = myNode.SelectSingleNode("/root/item");
mySearchNode.Attributes["name"].Value = "Joel";
Console.WriteLine(mySearchNode.OuterXml);
mySearchChildNode = mySearchNode.SelectSingleNode("/item/foo");
Console.WriteLine(mySearchChildNode.OuterXml);
虽然第一次搜索和更新属性工作正常,但第二次失败,因为mySearchNode.SelectSingleNode返回null。
问题 - 此代码是否存在根本问题? 为什么SelectSingleNode在第二个实例中没有按预期工作,就它而言,我在类型为Element的XmlNode上执行它。
请帮助。
非常感谢,
答案 0 :(得分:5)
您的第二个XPath查询应该没有前导斜杠。 /表示“文档的根”。如果省略斜杠,则查询将相对于mySearchNode变量。您也不应该再次包含“item”,您的查询是相对于您选择的“item”节点。在代码中:
myDoc.Load("Items2.xml");
myNode = myDoc.DocumentElement;
mySearchNode = myNode.SelectSingleNode("/root/item");
mySearchNode.Attributes["name"].Value = "Joel";
Console.WriteLine(mySearchNode.OuterXml);
mySearchChildNode = mySearchNode.SelectSingleNode("foo");
Console.WriteLine(mySearchChildNode.OuterXml);
答案 1 :(得分:2)
mySearchNode是item
节点,因此如果foo
是item
的孩子,则您的第二个xpath应该只是"foo"
答案 2 :(得分:0)
您可以执行SelectNodes,然后遍历所有项目节点。对于每个项目,您应该在foo节点上进一步执行SelectNodes。您应该检查节点计数以及项目和foo节点的属性名称是否存在。 您可以使用以下代码:
/// <summary>
/// Changes the xml in sourceFileName and writes the changed xml to destFileName
/// </summary>
public static void ProcessNames(string sourceFileName, string destFileName)
{
XmlDocument xmlDoc = new XmlDocument();
XmlTextWriter xtw = null;
xmlDoc.Load(sourceFileName);
try
{
// Parse through all the item nodes and process them
XmlNodeList itemList = xmlDoc.SelectNodes("//root/item");
if (itemList.Count > 0)
{
foreach (XmlNode item in itemList)
{
// Change the name attribute, if it exists
if (item.Attributes["name"] != null)
{
string newItemName = item.Attributes["name"].Value + "Joel";
item.Attributes["name"].Value = newItemName;
}
// Parse through all the foo nodes and process them
XmlNodeList fooList = item.SelectNodes("foo");
if (fooList.Count > 0)
{
foreach (XmlNode foo in fooList)
{
// Change the name attribute, if it exists
if (foo.Attributes["name"] != null)
{
string newFooName = foo.Attributes["name"].Value + "Joel";
foo.Attributes["name"].Value = newFooName;
}
}
}
}
xtw = new XmlTextWriter(destFileName, Encoding.UTF8);
xmlDoc.WriteContentTo(xtw);
}
}
finally
{
xtw.Close();
}
}
答案 3 :(得分:0)
根据我的理解,主要问题是,在节点上调用的 SelectNode(s)(此处:mySearchNode.SelectSingleNode)没有按预期工作!!!
它不会从给定的节点开始搜索,而是始终从根文档开始搜索。 (另请参阅源代码,其中对于节点,相关的 XmlDocument 节点用于启动 XPathNavigator)
我根本没想到这种行为!
最好使用应该按预期工作的 XDocument。