Solved

foreach is not doing the second child.

Posted on 2004-09-30
19
359 Views
Last Modified: 2010-04-15
hi guys:

I am having a strange problem. I have got this node which has two children from SomeFunction. In the foreach loop it is not doing the second child, if I remove the following statement from the foreach body       
SOCHXRoot.AppendChild(n);

then it would do the second child. I do not know why it is breaking out after appending child to SOCHXRoot.

thanks in advance.


SOCHXRoot = createNode("SOCHX");

XmlNode node = SomeFunction();

// node has two children

foreach(XmlNode n in node.ChildNodes)
      SOCHXRoot.AppendChild(n);

protected XmlElement createNode(string elementName,string elementValue)
{
XmlElement node = doc.CreateElement(elementName);
node.InnerText      = elementValue;
                  
return node;
}
0
Comment
Question by:rxraza
19 Comments
 
LVL 1

Expert Comment

by:kayhustle
ID: 12192330
This is because it threw an exception.  You cannot modify a collection while you are enumerating it.  You should use a regular for loop and bind it by the number of ChildNodes.
0
 

Author Comment

by:rxraza
ID: 12192366
Am I modifying the collection? Also, I put a try catch block around it and got no clue about any exception.

0
 

Author Comment

by:rxraza
ID: 12192477
Doing the following is throwing 'object reference not set to an instance' the second time it tries to append.

int count = node.ChildNodes.Count;

for (int i=0;i<count;i++)
     SOCHXRoot.AppendChild(node.ChildNodes[i]);
      
0
 

Author Comment

by:rxraza
ID: 12192490
What I am trying to accomplish here is to append children ignoring the parent because parent is just used for decoration purposes. Any ideas???
0
 

Author Comment

by:rxraza
ID: 12192602
I took off the looping contruct and did the following.

SOCHXRoot.AppendChild(node.FirstChild);
SOCHXRoot.AppendChild(node.LastChild);

It worked but the problem is not every node that is returned by SomeFunction contains two children.

It is driving me nuts
0
 

Author Comment

by:rxraza
ID: 12195166
Though I managed to create some workaround, I still want to know that why

foreach(XmlNode n in node.ChildNodes)
     SOCHXRoot.AppendChild(n);

would not append the second time. I am curious to know, that is why I am adding more points to it.
0
 
LVL 18

Expert Comment

by:armoghan
ID: 12197710
Try to debug it by displaying the number of elements in node in foreach.

foreach(XmlNode n in node.ChildNodes)
{
//check Count here  
   SOCHXRoot.AppendChild(n);
}

if you are changing the collection in the next line it will be visible
0
 
LVL 8

Expert Comment

by:Razzie_
ID: 12199848
rxraza,

The following is happening.

Let's say your xml looks like this:

<SOCHXRoot>
    <NODE1>node1</NODE1>
    <NODE2>node2</NODE2>
</SOCHXRoot>

What is happening during the foreach?

foreach(XmlNode n in node.ChildNodes)
    SOCHXRoot.AppendChild(n);

It will detect 2 nodes in node.ChildNodes. The first one is node1 and the second one node2. The first run, XmlNode 'n' will be node1. When you call SOCHXRoot.AppendChild(n), what this will do is append node1 to the SOCHXRoot, however, AppendChild will MOVE the node, not copy. So, after the first run, your xml will look like:

<SOCHXRoot>
    <NODE2>node2</NODE2>
    <NODE1>node1</NODE1>
</SOCHXRoot>

As you can see, node1 comes after node2 since when appending it, it will append it as the last child, thus after node2. So, it will have done the first node.

Now, like armoghan says, you ARE changing your collection while enumerating, since you have adjusted the childNodes collection. Since they are not the same as before the first foreach enumeration. Thus, the enumaration WILL terminate.

Hope this helps,

Razzie
0
 

Author Comment

by:rxraza
ID: 12201146
Razzie/armoghan:

You are right, In the scenario that Razzie has, the code will modify the collection, but in my case as I put in the very first question, the node (which is returned by SomeFunction) in question is different than the SOCHXRoot and there fore in the foreach loop when I append the child (child does not belong to SOCHXRoot, it belongs to some other node), hence it is not modification of collection, so why on earth I am not able to fully traverse the collection???

XmlElement SOCHXRoot = createNode("SOCHX");

XmlNode node = SomeFunction();

// node has two children AND THE NODE IS NOT THE SAME AS SOCHXROOT

foreach(XmlNode n in node.ChildNodes)
     SOCHXRoot.AppendChild(n);


protected XmlElement createNode(string elementName,string elementValue)
{
XmlElement node = doc.CreateElement(elementName);
node.InnerText     = elementValue;
               
return node;
}

0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 8

Expert Comment

by:Razzie_
ID: 12217714
rxraza,

What does SomeFunction() do? How does it create XmlNode node? From another xml? Because if it is another xml document, you can't even append it to SOCHXRoot, because you can't directly insert a node from one xml document to another.
0
 

Author Comment

by:rxraza
ID: 12217974
Razzie:

SomeFunction returns a node that is created from the same XML Document using createNode. By the way I figured out that it works fine if I do a clone and then append it.

foreach(XmlNode n in node.ChildNodes){
   XmlNode cloned = n.Clone();                 // clone the node here.
   SOCHXRoot.AppendChild(n);
}

but still I want to find the reason behind it.
 
0
 
LVL 8

Accepted Solution

by:
Razzie_ earned 250 total points
ID: 12218168
'returns a node that is created from the same XML Document using createNode'

Well, ok, that clears things up. Believe it or not, but it means you're *still* modifying the collection, since that node will still have a reference to its parent and childnodes. When you append it to the SOCHXRoot node, its parent has changed! You see how nasty that can be? :)

As for the cloning, yes that works, since that returns a shallow copy, meaning that it has no references to other object (in this case, XmlNodes).
0
 

Author Comment

by:rxraza
ID: 12218392
hmmm... that makes sense.. 'REFERENCE TO THE PARENT IS CHANGING'...

anyways, so I was able to make that work by cloning. Is cloning the right choice in this scenario or are there other better ways of getting this job done?
0
 
LVL 8

Expert Comment

by:Razzie_
ID: 12218587
Well I don't know if that was sarcastic, but I take it it was :P

Let's say there are 2 nodes in your collection. When you are enumerating, that collection may *not* change in any way.
When you enumerate the first node in the collection, it has a reference to its parent node, so the xml document knows where the node actually is. When you append that node to SOCHXRoot, you change that reference to its parent node. Because before it was, let's say, SomeNode, and now its parent is SOCHXRoot. There, a change :)

Is it the best way? It depends on what you're trying to do, I guess. If you want to create a new xml document with SOCHXRoot as it's new root, you could use the importnode function, but that works only if you have a second xml document. If SOCHXRoot was now in doc2, you could use:

doc2.ImportNode(n, false) in your foreach loop. If you set the second paramter to true, it will also add the childeren of node n, in case you might want that.
0
 

Author Comment

by:rxraza
ID: 12218886
com'n Razzie. I appreciate your help in this matter. 'REFERENECE TO THE PARENT IS CHANGING' is what I extracted from the context and that helped me a lot in developing the understanding of the scenario, Please, do not take that as a sarcasm

Regarding the best way, as you said importnode function will work if I have a second xml document but actually I do not have a second xml document. So, I can rule out this option. Now, to make this logic work I am only left with option of cloning the node first and then appending it. I believe this is the only way out in this scenario, please correct me if I am wrong.

0
 
LVL 8

Expert Comment

by:Razzie_
ID: 12218948
hehe it was no offense, just the way the capital sentence and all sounded :)

Well yes if you're not creating a seperate xml document for SOCHXRoot then I'd use the Clone() method. It's clean and it does the trick. I won't even know another way of doing it, so :)
0
 

Author Comment

by:rxraza
ID: 12219090
cool. Well thanks Razzie, I had good time resolving this issue wit you.
0
 
LVL 8

Expert Comment

by:Razzie_
ID: 12219198
same here, glad I could help :)
0
 
LVL 8

Expert Comment

by:Razzie_
ID: 12219238
Also, just came to my mind, but have you tried:

for(int i = 0; i<node.ChildNodes.Count;i++)
    SOCHXRoot.AppendChild(node.ChildNodes[i]);

Since you're not enumerating it it might work, haven't tried it though, but might be something to look at just for fun and educational purposes.
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Introduction This article series is supposed to shed some light on the use of IDisposable and objects that inherit from it. In essence, a more apt title for this article would be: using (IDisposable) {}. I’m just not sure how many people would ge…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now