【问题标题】:I need to InsertBefore or InsertAfter in the parent not the child我需要在父级而不是子级中 InsertBefore 或 InsertAfter
【发布时间】:2013-11-14 20:22:32
【问题描述】:

这是我的 Xml

<root>
<categories>
    <recipe id="RecipeID2">
        <name>something 1</name>
    </recipe>
    <recipe id="RecipeID2">
        <name>something 2</name>
    </recipe>
    <recipe id="RecipeID3">
        <name>something 3</name>
    </recipe>
</categories>
</root>

我正在解析客户想要在其之后或之前插入新食谱的所有食谱

XmlDocument xmlDocument = new XmlDocument();

xmlDocument.Load("thexmlfiles.xml");

XmlNodeList nodes = xmlDocument.SelectNodes("/root/categories//Recipe");

foreach (XmlNode node in nodes)
{
    if (node.Attributes["id"].InnerText == comboBoxInsertRecipe.Text)
    {
        node.InsertAfter(xfrag, node.ChildNodes[0]);
    }
}

预期输出:

<root>
<categories>
    <recipe id="RecipeID2">
        <name>something 1</name>
    </recipe>
    <recipe id="RecipeID2">
        <name>something 2</name>
    </recipe>
    <recipe id="NewRecipe4">
        <name>new Recipe 4</name>
    </recipe>
    <recipe id="RecipeID3">
        <name>something 3</name>
    </recipe>
</categories>
</root>

但是当我插入我的新食谱时,它确实是这样的

<root>
<categories>
    <recipe id="RecipeID2">
        <name>something 1</name>
    </recipe>
    <recipe id="RecipeID2">
        <name>something 2</name>
    </recipe>
    <recipe id="RecipeID3">
        <name>something 3</name>
        <recipe id="NewRecipe4">
            <name>new Recipe 4</name>
        </recipe>
    </recipe>
</categories>
</root>

新配方在另一个配方中,但不在类别中

【问题讨论】:

  • 您正在将所有 &lt;Recipe&gt; 节点选择到 nodes 列表中 - 当然,如果您向这样的节点添加一些内容,它将在该 &lt;recipe&gt; 节点内。您需要对配方节点的 parent 进行插入 - 类似于:node.parent.Insert(....);

标签: c# xml nodes xmldocument xmlnodelist


【解决方案1】:

首先,我推荐使用LINQ-to-Xml。此答案中的 L2Xml 示例。

XDocument xmlDocument = XDocument.Load("thexmlfiles.xml");
var root = xmlDocument.Root;
var recipes = root.Element("categories").Elements("recipe");

其次,获取要在之前/之后插入的节点的句柄/引用。

var currentRecipe = recipes.Where(r => r.Attribute("id") == "RecipeID3")
   .FirstOrDefault();

...然后酌情添加(使用XElement.AddAfterSelfXElement.AddBeforeSelf):

void AddNewRecipe(XElement NewRecipe, bool IsAfter, XElement CurrentRecipe) {
   if(IsAfter) {
      CurrentRecipe.AddAfterSelf(NewRecipe);
   } else {
      CurrentRecipe.AddBeforeSelf(NewRecipe);
   }
}

【讨论】:

    【解决方案2】:

    您在错误的文档级别添加新节点。该元素必须(如所指出的)添加到 category 节点而不是 sibling 节点。您有两个选项可以找到正确的节点,然后将节点添加到正确的位置:

    • 在执行此操作时,遍历所有节点以寻找匹配项
    • 直接使用 XPath 查找节点/path/element[@attribute='attributeName']

    将节点添加到正确位置的示例如下所示:

    XmlDocument xmlDocument = new XmlDocument();
    xmlDocument.Load(@"d:\temp\thexmlfile.xml");
    XmlNodeList nodes = xmlDocument.SelectNodes("/root/categories/recipe");
    // root node
    XmlNodeList category = xmlDocument.SelectNodes("/root/categories");
    // test node for the example
    var newRecipe = xmlDocument.CreateNode(XmlNodeType.Element, "recipe", "");
    var newInnerNode = xmlDocument.CreateNode(XmlNodeType.Element, "name", "");
    newInnerNode.InnerText = "test";
    var attribute = xmlDocument.CreateAttribute("id");
    attribute.Value = "RecipeID4";
    newRecipe.Attributes.Append(attribute);
    newRecipe.AppendChild(newInnerNode);
    // variant 1; find node while iteration over all nodes
    foreach (XmlNode node in nodes)
    {
        if (node.Attributes["id"].InnerText == "RecipeID3")
        {
            // insert into the root node after the found node
            category[0].InsertAfter(newRecipe, node);
        }
    }
    // variant 2; use XPath to select the element with the attribute directly
    //category[0].InsertAfter(newRecipe, xmlDocument.SelectSingleNode("/root/categories/recipe[@id='RecipeID3']"));
    // 
    xmlDocument.Save(@"d:\temp\thexmlfileresult.xml");
    

    输出是:

    <root>
        <categories>
            <recipe id="RecipeID1">
                <name>something 1</name>
            </recipe>
            <recipe id="RecipeID2">
                <name>something 2</name>
            </recipe>
            <recipe id="RecipeID3">
                <name>something 3</name>
            </recipe>
            <recipe id="RecipeID4">
                <name>test</name>
            </recipe>
        </categories>
    </root>
    

    正如还建议的那样,您可以使用 LINQ2XML 进行此操作。代码可能如下所示:

    // load document ...
    var xml = XDocument.Load(@"d:\temp\thexmlfile.xml");
    // find node and add new one after it
    xml.Root                        // from root
        .Elements("categories")     // find categories
        .Elements("recipe")         // all recipe nodes
        .FirstOrDefault(r => r.Attribute("id").Value == "RecipeID3")    // find node by attribute
        .AddAfterSelf(new XElement("recipe",                            // create new recipe node
                        new XAttribute("id", "RecipeID4"),              // with attribute
                        new XElement("name", "test")));                 // and content - name node
    // and save document ...
    xml.Save(@"d:\temp\thexmlfileresult.xml");
    

    输出是一样的。 LINQ2XML 在许多方面都比 XmlDocument 更易于使用和舒适。例如,子节点的选择可能会容易得多,并且您不需要 XPath 字符串:

    xml.Descendants("recipe");
    

    LINQ2XML 值得一试。

    【讨论】:

      猜你喜欢
      • 2015-08-14
      • 2013-11-24
      • 2012-08-09
      • 1970-01-01
      • 1970-01-01
      • 2015-08-20
      • 2023-03-16
      • 2018-07-17
      • 1970-01-01
      相关资源
      最近更新 更多