appending a new node to a nodelist using foreach l

2019-07-04 15:59发布

Currently I am dealing with this is the type of XML: XML FILE

With reference to the XML file, I want to check for a node, if the node is not found, I have to append the node to the file. I have tried the following code:

 private void button12_Click(object sender, EventArgs e)
    {
     //   XmlNodeList func_name_value = doc.GetElementsByTagName("FUNCTION-NAME-VALUE");
        XmlNodeList list_def_ref = doc.GetElementsByTagName("DEFINITION-REF");
        foreach (XmlNode nodeDef in list_def_ref)
        {
            if (nodeDef.InnerText == "/AUTOSAR/Com/ComConfig/ComSignal")
                {
                    if (nodeDef.ParentNode.HasChildNodes)
                    {
                        XmlNodeList list = nodeDef.ParentNode.ChildNodes;
                        foreach (XmlNode node in list)
                        {
                            if (node.Name == "PARAMETER-VALUES")
                            {
                                XmlNodeList param_list = node.ChildNodes;
                                foreach (XmlNode paramNode in param_list)
                                {
                                    if (paramNode.Name == "FUNCTION-NAME-VALUE")
                                    {
                                        XmlNodeList func_child_list = paramNode.ChildNodes;
                                        foreach (XmlNode funChild in func_child_list)
                                        {
                                            if (funChild.Name == "DEFINITION-REF")
                                            {
                                                string tout = "/AUTOSAR/Com/ComConfig/ComSignal/ComTimeoutNotification";
                                                string comnotify = "/AUTOSAR/Com/ComConfig/ComSignal/ComNotification";
                                                string invalid = "/AUTOSAR/Com/ComConfig/ComSignal/ComInvalidNotification";
                                                if (funChild.InnerText != tout)
                                                {
                                                    if (funChild.InnerText != comnotify)
                                                    {
                                                        //ADD ComInvalidNotification tags
                                                        XmlNode newNode = doc.CreateElement("FUNCTION-NAME-VALUE");
                                                        paramNode.AppendChild(newNode);
                                                        XmlNode defRefNode = doc.CreateElement("DEFINITION-REF");
                                                        XmlAttribute attr = doc.CreateAttribute("DEST");
                                                        attr.Value = "FUNCTION-NAME-DEF";
                                                        defRefNode.Attributes.SetNamedItem(attr);
                                                        newNode.AppendChild(defRefNode);
                                                        XmlNode val = doc.CreateElement("VALUE");
                                                        val.InnerText = "ComInvalidNotification";//ComInvalidNotification + shortName ;
                                                        newNode.AppendChild(val);
                                                    }
                                                    else
                                                    {
                                                        //ADD ComNotification tags
                                                        XmlNode newNode = doc.CreateElement("FUNCTION-NAME-VALUE");
                                                        paramNode.AppendChild(newNode);
                                                        XmlNode defRefNode = doc.CreateElement("DEFINITION-REF");
                                                        XmlAttribute attr = doc.CreateAttribute("DEST");
                                                        attr.Value = "FUNCTION-NAME-DEF";
                                                        defRefNode.Attributes.SetNamedItem(attr);
                                                        newNode.AppendChild(defRefNode);
                                                        XmlNode val = doc.CreateElement("VALUE");
                                                        val.InnerText = "ComNotification Node";//ComNotification + shortName;
                                                        newNode.AppendChild(val);
                                                    }
                                                }
                                                else
                                                {
                                                    //ADD ComTimeOutNotification tags
                                                    XmlNode newNode = doc.CreateElement("FUNCTION-NAME-VALUE");
                                                    paramNode.AppendChild(newNode);
                                                    XmlNode defRefNode = doc.CreateElement("DEFINITION-REF");
                                                    XmlAttribute attr = doc.CreateAttribute("DEST");
                                                    attr.Value = "FUNCTION-NAME-DEF";
                                                    defRefNode.Attributes.SetNamedItem(attr);
                                                    newNode.AppendChild(defRefNode);
                                                    XmlNode val = doc.CreateElement("VALUE");
                                                    val.InnerText = "ComTimeoutNotification node";//ComInvalidNotification + shortName;
                                                    newNode.AppendChild(val);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

        doc.Save(openFileDialog1.FileName);

The Error I am getting is: the element list has changed. the enumeration operation failed to continue.

After the 1st execution of the foreach loop, I am getting this error, how should I overcome this error?

1条回答
我想做一个坏孩纸
2楼-- · 2019-07-04 16:35

You have two problems here:

  1. You are modifying your XmlNodeList collections while iterating through them. It is standard practice by Microsoft to throw an exception when a collection is modified during iteration, see for instance the documentation for IEnumerator.MoveNext:

    Exceptions

    InvalidOperationException: The collection was modified after the enumerator was created.

    To avoid this exception, you can use a for loop and index through the XmlNodeList manually, or snapshot to a static List<T> and iterate through that.

  2. You are searching for XML nodes named <DEFINITION-REF> and <FUNCTION-NAME-VALUE>, but you are also creating nodes with this name. This means that nodes you create early in the iteration might be found later in the iteration, causing recursive creation of even more nodes. I reckon you do not want this. If my reckoning is correct, you should snapshot all nodes meeting your search criteria, then iterate through the snapshots, like so:

    private static void AddMissingNodes(XmlDocument doc)
    {
        var query = from nodeDef in doc.GetElementsByTagName("DEFINITION-REF").Cast<XmlNode>()
                    where nodeDef.InnerText == "/AUTOSAR/Com/ComConfig/ComSignal"
                    from nodeDefSibling in nodeDef.ParentNode.ChildNodes.Cast<XmlNode>()
                    where nodeDefSibling.Name == "PARAMETER-VALUES"
                    from paramNode in nodeDefSibling.ChildNodes.Cast<XmlNode>()
                    where paramNode.Name == "FUNCTION-NAME-VALUE"
                    select new
                    {
                        paramNode = paramNode,
                        func_child_list = (from funChild in paramNode.ChildNodes.Cast<XmlNode>()
                                          where funChild.Name == "DEFINITION-REF"
                                           select funChild).ToList() // Snapshot func_child_list by calling ToList()
                    };
    
        foreach (var paramNodeAndFuncChildren in query.ToList()) // Snapshot everything by calling ToList()
            foreach (var funChild in paramNodeAndFuncChildren.func_child_list)
                AddMissingNodes(doc, paramNodeAndFuncChildren.paramNode, funChild);
    
    }
    
    private static void AddMissingNodes(XmlDocument doc, XmlNode paramNode, XmlNode funChild)
    {
        string tout = "/AUTOSAR/Com/ComConfig/ComSignal/ComTimeoutNotification";
        string comnotify = "/AUTOSAR/Com/ComConfig/ComSignal/ComNotification";
        string invalid = "/AUTOSAR/Com/ComConfig/ComSignal/ComInvalidNotification";
        if (funChild.InnerText != tout)
        {
            if (funChild.InnerText != comnotify)
            {
                //ADD ComInvalidNotification tags
                XmlNode newNode = doc.CreateElement("FUNCTION-NAME-VALUE");
                paramNode.AppendChild(newNode);
                XmlNode defRefNode = doc.CreateElement("DEFINITION-REF");
                XmlAttribute attr = doc.CreateAttribute("DEST");
                attr.Value = "FUNCTION-NAME-DEF";
                defRefNode.Attributes.SetNamedItem(attr);
                newNode.AppendChild(defRefNode);
                XmlNode val = doc.CreateElement("VALUE");
                val.InnerText = "ComInvalidNotification";//ComInvalidNotification + shortName ;
                newNode.AppendChild(val);
            }
            else
            {
                //ADD ComNotification tags
                XmlNode newNode = doc.CreateElement("FUNCTION-NAME-VALUE");
                paramNode.AppendChild(newNode);
                XmlNode defRefNode = doc.CreateElement("DEFINITION-REF");
                XmlAttribute attr = doc.CreateAttribute("DEST");
                attr.Value = "FUNCTION-NAME-DEF";
                defRefNode.Attributes.SetNamedItem(attr);
                newNode.AppendChild(defRefNode);
                XmlNode val = doc.CreateElement("VALUE");
                val.InnerText = "ComNotification Node";//ComNotification + shortName;
                newNode.AppendChild(val);
            }
        }
        else
        {
            //ADD ComTimeOutNotification tags
            XmlNode newNode = doc.CreateElement("FUNCTION-NAME-VALUE");
            paramNode.AppendChild(newNode);
            XmlNode defRefNode = doc.CreateElement("DEFINITION-REF");
            XmlAttribute attr = doc.CreateAttribute("DEST");
            attr.Value = "FUNCTION-NAME-DEF";
            defRefNode.Attributes.SetNamedItem(attr);
            newNode.AppendChild(defRefNode);
            XmlNode val = doc.CreateElement("VALUE");
            val.InnerText = "ComTimeoutNotification node";//ComInvalidNotification + shortName;
            newNode.AppendChild(val);
        }
    }
    

    Then, if I count the number of XML nodes before and after:

        var fileName = @"D:\Temp\Question36740480\autosar_ecucvalues_Fx4_L.xml";
        var newFileName = @"D:\Temp\Question36740480\autosar_ecucvalues_Fx4_L_NEW.xml";
    
        var doc = new XmlDocument();
        doc.Load(fileName);
    
        int countBefore = doc.SelectNodes("descendant::*").Count;
    
        AddMissingNodes(doc);
    
        int countAfter = doc.SelectNodes("descendant::*").Count;
    
        Debug.WriteLine(string.Format("Added {0} nodes", countAfter - countBefore));
    
        doc.Save(newFileName);
    
        Debug.WriteLine("Wrote: " + newFileName);
    

    I see that 342 nodes were added to the XmlDocument.

查看更多
登录 后发表回答