问题
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:
You have two problems here:
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 theXmlNodeList
manually, or snapshot to a static List<T> and iterate through that.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
.
来源:https://stackoverflow.com/questions/36740480/appending-a-new-node-to-a-nodelist-using-foreach-loop-and-xmlnodelist-c-sharp