foreach is not doing the second child.

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;
}
rxrazaAsked:
Who is Participating?
 
Razzie_Connect With a Mentor Commented:
'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
 
kayhustleCommented:
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
 
rxrazaAuthor Commented:
Am I modifying the collection? Also, I put a try catch block around it and got no clue about any exception.

0
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

 
rxrazaAuthor Commented:
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
 
rxrazaAuthor Commented:
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
 
rxrazaAuthor Commented:
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
 
rxrazaAuthor Commented:
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
 
armoghanCommented:
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
 
Razzie_Commented:
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
 
rxrazaAuthor Commented:
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
 
Razzie_Commented:
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
 
rxrazaAuthor Commented:
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
 
rxrazaAuthor Commented:
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
 
Razzie_Commented:
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
 
rxrazaAuthor Commented:
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
 
Razzie_Commented:
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
 
rxrazaAuthor Commented:
cool. Well thanks Razzie, I had good time resolving this issue wit you.
0
 
Razzie_Commented:
same here, glad I could help :)
0
 
Razzie_Commented:
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.