C#SelectSingleNode - 可以递归使用吗?

时间:2009-06-14 15:54:50

标签: c# xml selectsinglenode

如果我有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上执行它。

请帮助。

非常感谢,

4 个答案:

答案 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节点,因此如果fooitem的孩子,则您的第二个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。