使用foreach循环和XmlNodeList C#将新节点追加到节点列表 [英] appending a new node to a nodelist using foreach loop and XmlNodeList C#

查看:146
本文介绍了使用foreach循环和XmlNodeList C#将新节点追加到节点列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,我正在处理的是XML类型: XML文件

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

关于XML文件,我要检查一个节点,如果找不到该节点,则必须将该节点附加到文件中.我尝试了以下代码:

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);

我遇到的错误是:元素列表已更改.枚举操作无法继续.

在第一次执行foreach循环后,出现此错误,我该如何克服该错误?

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

推荐答案

您在这里遇到两个问题:

You have two problems here:

  1. 您正在迭代遍历XmlNodeList集合. Microsoft的标准做法是在迭代过程中修改集合时引发异常,例如,请参见

  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:

例外

InvalidOperationException:创建枚举器后,已修改集合.

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

为避免此异常,您可以使用for循环并手动通过XmlNodeList进行索引,或者使用

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.

您正在搜索名为<DEFINITION-REF><FUNCTION-NAME-VALUE>的XML节点,但是您也正在使用该名称创建节点.这意味着您可能会在迭代的后期找到在迭代的早期创建的节点,从而导致递归创建更多的节点.我认为您不想要这个.如果我的估算正确,则应该对满足搜索条件的所有节点进行快照,然后遍历快照,如下所示:

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);
    }
}

然后,如果我计算XML节点的数量之前和之后:

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);

我看到342个节点已添加到XmlDocument.

I see that 342 nodes were added to the XmlDocument.

这篇关于使用foreach循环和XmlNodeList C#将新节点追加到节点列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆