Recursive method resulting in infinite loop - c#

I am doing a migration tool for sharepoint sites. I migrate sites using XML files. In my method for generating my XML file, however, I get an infinite loop and I can't figure out the cause. I get no errors what so ever but the XML file gets understandably large.
How I create the root node of my XML file:
private void createRootXmlNodeFromRootSite()
{
if (rootsite != null)
{
//Add root-site to TreeView
XmlElement rootnode = document.CreateElement(strRoot);
rootnode.SetAttribute(strTitle, rootsite.Title);
rootnode.SetAttribute(strName, rootsite.SiteAdministrators[0].Name);
rootnode.SetAttribute(strEmail, rootsite.SiteAdministrators[0].Email);
document.AppendChild(rootnode);
XmlElement nodelists = document.CreateElement(strLists);
if (rootsite.Lists.Count > 0)
{
rootnode.AppendChild(nodelists);
//Get all lists within root-site and put them under it's node.
foreach (SPList list in rootsite.Lists)
{
XmlElement nodelist = document.CreateElement(strList);
nodelist.SetAttribute(strTitle, list.Title);
if (!list.Hidden)
{
nodelists.AppendChild(nodelist);
XmlElement nodects = document.CreateElement(strContentTypes);
if (list.ContentTypes.Count > 0)
{
nodelist.AppendChild(nodects);
//Get all content types within lists of root site and put them under it's node.
foreach (SPContentType ct in list.ContentTypes)
{
XmlElement nodect = document.CreateElement(strContentType);
nodect.SetAttribute(strTitle, ct.Name);
if (!ct.Hidden)
{
nodects.AppendChild(nodect);
XmlElement nodefields = document.CreateElement(strFields);
if (ct.Fields.Count > 0)
{
nodect.AppendChild(nodefields);
foreach (SPField field in ct.Fields)
{
XmlElement nodefield = document.CreateElement(strField);
nodefield.SetAttribute(strTitle, field.Title);
if (!field.Hidden)
{
nodefields.AppendChild(nodefield);
}
}
}
}
}
}
}
//Call recursive methods to get child-site-elements.
convertSiteCollectionToXml(rootnode, rootsite);
}
}
}
}
This method then calls a recursive method which creates child nodes from the subsites:
private void convertSiteCollectionToXml(XmlNode nodeElement, SPWeb site)
{
XmlElement nodesites = document.CreateElement("Sites");
if (site.Webs.Count > 0)
{
nodeElement.AppendChild(nodesites);
foreach (SPWeb childsite in site.Webs)
{
XmlElement child = document.CreateElement("Site");
child.SetAttribute("Title", childsite.Title);
nodesites.AppendChild(child);
XmlElement nodelists = document.CreateElement("Lists");
if (childsite.Lists.Count > 0)
{
child.AppendChild(nodelists);
foreach (SPList list in childsite.Lists)
{
XmlElement nodelist = document.CreateElement("List");
nodelist.SetAttribute("Title", list.Title);
if (!list.Hidden)
{
nodelists.AppendChild(nodelist);
XmlElement nodects = document.CreateElement("ContentTypes");
if (list.ContentTypes.Count > 0)
{
nodelist.AppendChild(nodects);
foreach (SPContentType ct in list.ContentTypes)
{
XmlElement nodect = document.CreateElement("ContentType");
nodect.SetAttribute("Title", ct.Name);
if (!ct.Hidden)
{
nodects.AppendChild(nodect);
XmlElement nodefields = document.CreateElement("Fields");
if (ct.Fields.Count > 0)
{
nodect.AppendChild(nodefields);
foreach (SPField field in ct.Fields)
{
XmlElement nodefield = document.CreateElement("Field");
nodefield.SetAttribute("Title", field.Title);
if (!field.Hidden)
{
nodefields.AppendChild(nodefield);
}
}
}
}
}
}
}
convertSiteCollectionToXml(child, childsite);
}
}
}
}
}
The infinite loop happens in the second method. Anyone see the cause?

Related

Not reading two values from XML nodes

I have this XML
<?xml version="1.0" encoding="UTF-8"?>
<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="2.00">-<NFe>-<infNFe versao="2.00" Id="NFe35130649196462000115550010000036141000025758">
<ide>
<natOp>DEVOL. ARMAZENAGEM</natOp>
</ide>
<total>
<ICMSTot>
<vNF>43778.00</vNF>
</ICMSTot>
</total>
I read with this C# code :
private void leerarquivoN(string caminx)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(caminx);
XmlNodeList ml = xmlDoc.GetElementsByTagName("*");
XmlNode primer = xmlDoc.DocumentElement;
tipo_arq = primer.Name;
if (xmlDoc.DocumentElement.Name == "nfeProc")
{ foreach (XmlNode xn in ml)
{
if (xn.Name == "infNFe")
{
chave_nota = xn.Attributes["Id"].Value;
versao = xn.Attributes["versao"].Value;
lblChaveNota.Text = chave_nota; lblversao.Text = versao;
}
}
XmlNodeList xnList = xmlDoc.GetElementsByTagName("ide");
foreach (XmlNode xn in xnList)
{
if (xn.Name == "ide")
{
if (xn["nNF"] != null)
{ nnota = (xn["nNF"]).InnerText; label8.Text = nnota; }
if (xn["dEmi"] != null)
{ ndata = (xn["dEmi"]).InnerText; lblData.Text = ndata;}
if (xn["natOP"] != null)
{ natop = (xn["natOP"]).InnerText; lblNAtop.Text = natop ; }
}
}
XmlNodeList xnList2 = xmlDoc.GetElementsByTagName("emit");
foreach (XmlNode xn in xnList2)
{
{ if (xn["CNPJ"] != null)
{ ncnpj = (xn["CNPJ"]).InnerText; lblCNPJ.Text = ncnpj; }
}
}
XmlNodeList xnList3 = xmlDoc.GetElementsByTagName("total");
foreach (XmlNode xn in xnList3)
{
{
if (xn["vNF"] != null)
{ ntotal = (xn["vNF"]).InnerText; lblvNF.Text = ntotal ; }
}
}
}
I can not read VNF and natOP , what i m doing wrong???
Thanks
The code you are using just gets the main nodes. To get the children associated with each node (natOp and vNF), you have to rely on a different code (MSDN reference). Sample for natOp (inside the xnList for loop):
if (xn.HasChildNodes)
{
for (int i=0; i<xn.ChildNodes.Count; i++)
{
//xn.ChildNodes[i].InnerText -> what you are after
}
}

read only particular instance using xmlreader

I have a xml file that looks like
<Name>AAA</Name>
<Age>23</Age>
<I1>
<Element1>A</Element1>
<Element2>B</Element2>
<Element3>C</Element3>
<\I1>
<I2>
<Element1>AA</Element1>
<Element2>BB</Element2>
<Element3>CC</Element3>
</I2>
I am reading all the values of elements using xmlreader in C# 3.0. But now i have to change by reading only the values within particular start and end tage. For the xml file mentioned above, i need to read <Name>, <Age> by default and then i have a function that returns the value "I1" or "I2" which is basically the element names. If it returns "I1" then i should read only the elements between <I1> and </I1> and should not read <I2> and vice versa. So the code structure would be (just the logic please ignore the syntax errors) like
/******function that returns element name I1 or I2*********/
string elementName = func(a,b);
xmlreader reader = reader.create("test.xml");
while(reader.read())
{
switch(reader.nodetype)
{
case xmlnodetype.element:
string nodeName = reader.name
break;
case xmlnodetype.text
switch(nodeName)
{
/*************Read default name and age values*******/
case "Name":
string personName = reader.value
break;
case "Age":
string personAge = reader.value;
break;
/*******End of reading default values**************/
/*** read only elements between the value returned by function name above
If function returns I1 then i need to read only values between <I1> </I1> else read </I2> and </I2>**/
}
}
}
Thanks!
So assuming, since we dont have any other tags to go off, that your file would look something such as this from beginning to end
<?xml version="1.0" encoding="utf-8" ?>
<RootElement>
<UserInformation>
<Name>AAA</Name>
<Age>23</Age>
<I1>
<Element1>A</Element1>
<Element2>B</Element2>
<Element3>C</Element3>
<\I1>
<I2>
<Element1>AA</Element1>
<Element2>BB</Element2>
<Element3>CC</Element3>
</I2>
</UserInformation>
</RootElement>
and then to call it
System.IO.StreamReader sr = new System.IO.StreamReader("test.xml");
String xmlText = sr.ReadToEnd();
sr.Close();
List<UserInfo> finalList = readXMLDoc(xmlText);
if(finalList != null)
{
//do something
}
private List<UserInfo> readXMLDoc(String fileText)
{
//create a list of Strings to hold our user information
List<UserInfo> userList = new List<UserInfo>();
try
{
//create a XmlDocument Object
XmlDocument xDoc = new XmlDocument();
//load the text of the file into the XmlDocument Object
xDoc.LoadXml(fileText);
//Create a XmlNode object to hold the root node of the XmlDocument
XmlNode rootNode = null;
//get the root element in the xml document
for (int i = 0; i < xDoc.ChildNodes.Count; i++)
{
//check to see if we hit the root element
if (xDoc.ChildNodes[i].Name == "RootElement")
{
//assign the root node
rootNode = xDoc.ChildNodes[i];
break;
}
}
//Loop through each of the child nodes of the root node
for (int j = 0; j < rootNode.ChildNodes.Count; j++)
{
//check for the UserInformation tag
if (rootNode.ChildNodes[j].Name == "UserInformation")
{
//assign the item node
XmlNode userNode = rootNode.ChildNodes[j];
//create userInfo object to hold results
UserInfo userInfo = new UserInfo();
//loop through each if the user tag's elements
foreach (XmlNode subNode in userNode.ChildNodes)
{
//check for the name tag
if (subNode.Name == "Name")
{
userInfo._name = subNode.InnerText;
}
//check for the age tag
if (subNode.Name == "Age")
{
userInfo._age = subNode.InnerText;
}
String tagToLookFor = "CallTheMethodThatReturnsTheCorrectTag";
//check for the tag
if (subNode.Name == tagToLookFor)
{
foreach (XmlNode elementNode in subNode.ChildNodes)
{
//check for the element1 tag
if (elementNode.Name == "Element1")
{
userInfo._element1 = elementNode.InnerText;
}
//check for the element2 tag
if (elementNode.Name == "Element2")
{
userInfo._element2 = elementNode.InnerText;
}
//check for the element3 tag
if (elementNode.Name == "Element3")
{
userInfo._element3 = elementNode.InnerText;
}
}
}
}
//add the userInfo to the list
userList.Add(userInfo);
}
}
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
return null;
}
//return the list
return userList;
}
//struct to hold information
struct UserInfo
{
public String _name;
public String _age;
public String _element1;
public String _element2;
public String _element3;
}

C# How do I determine childnode level in xml

I need to remove elements in some xml files. How do I correctly ensure that I transverse through all childnodes to remove all element with a matching name. I have code such as:
string strFilename = #"D:\sample.xml";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(strFilename);
XmlNode parentNode;
parentNode = xmlDoc.DocumentElement;
foreach (XmlNode node1 in parentNode.ChildNodes)
{
foreach (XmlNode node2 in node1.ChildNodes)
{
if (node2.Name == "ElementNodeToDelete")
{
node2.ParentNode.RemoveChild(node2);
}
foreach (XmlNode node3 in node2.ChildNodes)
{
if (node3.Name == "ElementNodeToDelete")
{
node3.ParentNode.RemoveChild(node3);
}
foreach (XmlNode node4 in node3.ChildNodes)
{
if (node4.Name == "ElementNodeToDelete")
{
node4.ParentNode.RemoveChild(node4);
}
}
}
}
}
Is this a valid solution? How do I determine how many foreach loops to perform to ensure that all children are checked?
Thanks for your time in advance.
Recursion is your friend.
void DeleteNodes(XmlNode root, string deleteName)
{
foreach(XmlNode node in root.ChildNodes)
{
if (node.Name == deleteName)
{
root.RemoveChild(node);
}
else
{
DeleteNodes(node,deleteName);
}
}
}

No Collapse/Expand icon in TreeView when using ASP.NET and C#

I have a trouble with Expand / Collapse icon in TreeView
What I get : http://i.imgur.com/dl5Lg.jpg
What I did :
C# code :
public static void TreeLoad(TreeView tree, string #source)
{
XmlDocument document = new XmlDocument();
//TreeView tree = new TreeView();
try
{
if (File.Exists(source))
{
document.Load(source);
tree.Nodes.Clear();
XmlNodeList category = document.SelectNodes("/parent/Categories");
//XmlNodeList links = document.SelectNodes("/parent/Categories/link");
foreach (XmlNode node in category)
{
TreeNode t1 = new TreeNode(node.Attributes["Name"].Value);
tree.Nodes.Add(t1);
//t1.ShowCheckBox = true;
if (node.HasChildNodes)
{
//foreach (XmlNode nod in links)
foreach (XmlNode nod in node.ChildNodes)
{
TreeNode t2 = new TreeNode(nod.Attributes["name"].Value);
tree.Nodes.Add(t2);
}
}
}
//tree.Nodes[0].CollapseAll();
//document.Save(source);
}
else
{
messages = NOTFOUND;
}
}
catch (Exception ect)
{
//exist.InnerText = ect.Message;
messages = ect.Message;
}
finally
{
// document.Save(source);
}
//return tree;
}
URLStorageCtrl.TreeLoad(tree, "example.xml");
ASP.NET code
<asp:TreeView ID="tree" runat="server"></asp:TreeView>
I'm using 4-tier architecture so please do not redirect me to design page, I use only coding.
yeah, of course. you added all nodes to tree as its root.
this code:
tree.Nodes.Add(t2);
change to :
t1.ChildNodes.Add(t2);

Xml node reading for each loop

I am trying to loop through an Xml file and display the value for account in a message.
XmlNodeList nodeList = testDoc.SelectNodes("/details/row/var");
foreach (XmlNode no in nodeList)
{
XmlNode node = testDoc.SelectSingleNode("/details/row/var[#name='account']");
test.actual = node.Attributes["value"].Value;
MessageBox.Show(test.account);
}
The message box is currently displaying the first record repeatidly, how can I get to the next record?
Thanks for your input in advance.
You are repeatedly assigning node with the same element from testDoc. It is not clear what test.account is (perhaps a mistype for test.actual)?
no is the variable which will iterate the contents of nodeList - I imagine you intended to use that.
EDIT following edit of OP
Now you've shown us what nodeList is, I suspect you want to do something like this instead :
XmlNodeList nodeList = testDoc.SelectNodes("/details/row/var[#name='account']");
foreach (XmlNode no in nodeList)
{
test.actual = no.Attributes["value"].Value;
...
XmlDocument doc = new XmlDocument();
doc.Load("d:\\test.xml");
XmlNodeList node = doc.GetElementsByTagName("w:r");
foreach (XmlNode xn in node)
{
try
{
if (xn["w:t"].InnerText != null)
{
if (xn["w:t"].InnerText == "#")
{
string placeHolder = xn["w:t"].InnerText;
foreach (XmlNode a in node)
{
if (a["w:t"].InnerText != "#")
{
string placeHolder1 = a["w:t"].InnerText;
}
}
}
}
}
catch (Exception e)
{
Console.Write(e);
}
}
Here is the sample for parent node value to get information of the child nodes.here i am using the ReportItems ParentNode and Print only image child nodes.
xmldoc.Load(rdlFile);
StringBuilder sb=new StringBuilder();
XmlNode node = xmldoc.GetElementsByTagName("ReportItems")[0];
XmlNodeList list = node.ChildNodes;
atributes=new string[node.ChildNodes.Count];
int l = 0;
for (int j = 0; j < node.ChildNodes.Count; j++)
{
if (list[j].Name == "Image")
{
XmlAttributeCollection att = list[j].Attributes;
atributes[l] = att[0].Value.ToUpper();
}
l++;
}
for (int i = 0; i < node.ChildNodes.Count; i++)
{
if (searchText.Text.ToUpper() == atributes[i])
{
XmlNodeList lastlist = node.ChildNodes;
XmlNodeList endlist = lastlist[i].ChildNodes;
for (int k = 0; k < endlist.Count; k++)
{
sb.Append(endlist[k].Name+" - "+ endlist[k].InnerText);
sb.Append("\n"+"\n");
}
}
}
let me know if you have doubt..
Try this,
XmlDocument xdoc = new XDocument();
xdoc.Load("*/File/*");
string xmlcontents = xdoc.InnerXml;
var xpath = "(/details/row/var[#name='account'])";
XmlNodeList lists = xdoc.DocumentElement.SelectNodes(xpath);
foreach (XmlNode _node in lists)
{
string _nodeValue = _node.InnerText;
MessageBox.Show(_nodeValue);
}
Try the following:
//Create an xml reader;
XmlDocument _xmlDocument = new XmlDocument();
_xmlDocument.Load(/*File Name here*/);
//Select the element with in the xml you wish to extract;
XmlNodeList _nodeList = _xmlDocument.SelectNodes("/details/row/var[#name='account']");
//Display the values in the node list to the screen;
foreach (XmlNode _node in _nodeList)
{
String _nodeValue = _node.InnerText.ToString();
MessageBox.Show(_nodeValue.ToString());
}
I'm not 100% sure, but you may need to use recursion. If not, it should just look like this:
XmlDocument doc = //etc..
foreach(XmlNode node in doc.ChildNodes)
{
if(node.Name == "account")
{
MessageBox.Show(node.Value);
}
}
You shouldn't spend time with reading the xml node by node. Try Deserialization:

Categories

Resources