Reading + Writing XML

JBudOne

Member
Joined
Jul 28, 2006
Messages
6
Ok, so I want to write something into the xml file and then read it. Im a total n00b and so Im sure its something basic. But ive checked and messed around with it for, I guess 3 days now =( any help would be greatly appreciated.

C#:
public static string LoadXML(String TheParent, String TheChild)
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(@"SP.xml");

System.Xml.XmlNode node = doc.DocumentElement;
string data = "";
{
if (node.LocalName == "XMLDoc")
{
node.SelectSingleNode(TheParent);
System.Collections.IEnumerator rootIter = node.GetEnumerator();
while (rootIter.MoveNext())
{
System.Xml.XmlNode currentNode = (System.Xml.XmlNode)rootIter.Current;
data = currentNode[TheChild].InnerText;
break;
}

}
}
return data;
}


public void WriteXML(String TheParent, String TheChild, String TheValue)
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(@"SP.xml");

System.Xml.XmlNode node = doc.DocumentElement;
node.SelectSingleNode(TheParent);
System.Collections.IEnumerator rootIter = node.GetEnumerator();
while (rootIter.MoveNext())
{
System.Xml.XmlNode currentNode = (System.Xml.XmlNode)rootIter.Current;
currentNode[TheChild].SetAttribute(TheChild, TheValue);
break;
}

private void button1_Click(object sender, EventArgs e)
{
int TestMe = 15;
WriteXML("Main", "Subjects", TestMe.ToString());
Label1.Text = LoadXML("Main", "Subjects");
}

The XML looks kind of like:
Code:
<XMLDoc>
<Main>
<Subjects>3</Subjects>
<Groups>9</Groups>
<Qs>18></Qs>
</Main>
</XMLDoc>

So there are no errors when building this, but it shows, 3 in Label1. Any ideas or suggestions are greatly appreciated. Thx.
 
Last edited by a moderator:
You say the label contains 3 which you obviously dont think is right, but you dont say what you think it should be.

The value 3 is correct for the code you have posted, which is why there no compile or runtime errors. Ive not checked to see if the code your using to add a new node in the WriteXML adds the node correctly, but you dont call doc.Save() at any point. Since you dont save the document, when LoadXML is being called its seeing the original xml file.

Just as a pointer Im not entirely sure why you have while loops in either method since you have a break statement without a condition this loop is only ever run once.
 
Kk I updated it and came out to this:
C#:
        public static string LoadXML(String TheParent, String TheChild)
        {
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            doc.Load(@"SP.xml");

            System.Xml.XmlNode node = doc.DocumentElement;
            string data = "";
            {
                if (node.LocalName == "XMLDoc")
                {
                    node.SelectSingleNode(TheParent);
                    System.Collections.IEnumerator rootIter = node.GetEnumerator();
                    while (rootIter.MoveNext())
                    {
                        System.Xml.XmlNode currentNode = (System.Xml.XmlNode)rootIter.Current;
                        data = currentNode[TheChild].InnerText;
                        break;
                    }

                }
            }
            return data;
        }


        public void WriteXML(String TheParent, String TheChild, String TheValue)
        {
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            doc.Load(@"SP.xml");

            System.Xml.XmlNode node = doc.DocumentElement;
            node.SelectSingleNode(TheParent);node.SelectSingleNode(TheChild);
            System.Xml.XmlTextWriter Writer = new System.Xml.XmlTextWriter("SP.xml", System.Text.UTF8Encoding.UTF8);
            Writer.WriteString(TheValue);
            node.WriteTo(Writer);
            doc.Save(@"SP.xml");
        }





        private void button1_Click(object sender, EventArgs e)
        {
            WriteXML("Main", "Subjects", "W00000000000T OMG IT WORKS!!!!!!!!!!!!!!!!");
        }

And there are no build errors at first. I open it up after I build the prog, and it looks like:

Code:
W00000000000T OMG IT WORKS!!!!!!!!!!!!!!!!<XMLDoc><Main><Subjects>3</Subjects></Main></XMLDoc>

when it used to look like:
Code:
<XMLDoc>
<Main>
<Subjects>3</Subjects>
</Main>
</XMLDoc>

Then I build it again and there is an error message:

doc.Load(@"SP.xml");

Data at the root level is invalid. Line 1, position 1.

Not sure what this means.. Any ideas? I know LoadXML() works, but I cant figure out how to write my message inside the <Subjects> node. Thx.
 
Last edited by a moderator:
The SelectSingleNode functions returns the selected node - you need to do something like
Code:
node = node.SelectSingleNode(TheParent)
 
Hey, so I played around with it - still having problems. This is what I have:
C#:
public void WriteXML(String TheParent, String TheChild, String TheValue)
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(@"SP.xml");

System.Xml.XmlNode node = doc.DocumentElement;

System.Collections.IEnumerator rootIter = node.GetEnumerator();
while( rootIter .MoveNext() )
{
System.Xml.XmlElement curNode = (System.Xml.XmlElement)rootIter.Current;
if (curNode.LocalName == TheChild)
{
SetElement(curNode, TheChild, TheValue);
break;
}
}

doc.Save(@"SP.xml");
}

private void SetElement(System.Xml.XmlElement settingElement, string path, string value)
{
if( settingElement[path].InnerText == value)
{
settingElement[path].InnerText = value;
}
else
{
System.Xml.XmlDocument doc = settingElement.OwnerDocument;
System.Xml.XmlElement newElement = doc.CreateElement(path);
newElement[path].InnerText = value;
}

}

WriteXML("Main", "Subjects", "W00000000000T OMG IT WORKS!!!!!!!!!!!!!!!!");

Code:
SP.xml
<XMLDoc>
<Main>
<Subjects>3</Subjects>
<Questions>18</Questions>
<Answered>12</Answered>
<Correct>9</Correct>
</Main>
</XMLDoc>

When I try to build it I get an error on:

if( settingElement[path].InnerText == value) Object reference not set to an instance of an object. Any ideas or suggestions?
 
Last edited by a moderator:
Are you actually trying your hardest to confuse the hell out of me or is that just an accident? lol. Firstly its quite hard to work out what eactly the code does as you never provide examples of what exactly TheParent and TheChild strings would contain. The latest error in my opinion arrives from the node curNode not having a childnode with a name that matches the value stored in path.

Take a look at the following forum post I replied to the other day, it includes an example of how to add a node to an xml file as well as retrieving the information. Hopefully it will help you with your troubles.
http://www.computerhelp.forum/showthread.php?t=96945

Also it would be alot easier to read your code if you enclosed them in cs tags, Im pretty sure there are instructions how in one of the FAQs or in one of the admins signatures. Id tell you how todo it, but im not sure how to type the tags without them turning my writing into a code section.

One last thing, where did you learn todo that while loop using that Enumerator method. Im not saying theres anything wrong with it, Ive just never seen it before.
 
As Cags mentioned - you could loop through the elements far easier...
C#:
        public void WriteXML(String TheParent, String TheChild, String TheValue)
        {
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            doc.Load(@"SP.xml");

            System.Xml.XmlNode node = doc.DocumentElement;

            foreach (XmlElement curNode in node)
            {
                if (curNode.LocalName == TheChild)
                {
                    SetElement(curNode, TheChild, TheValue);
                    break;
                }
            }

            doc.Save(@"SP.xml");
        }
...should do the same thing.

However the entire method could probably be simplified to
C#:
public void WriteXML(String TheParent, String TheChild, String TheValue)
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();

doc.Load(@"SP.xml");

System.Xml.XmlNode node = doc.DocumentElement;

SetElement(node[TheChild], TheChild, TheValue);

doc.Save(@"SP.xml");
}

In the SetElement method the first part seems redundant
C#:
if (settingElement[path].InnerText == value)
    {
    settingElement[path].InnerText = value;
    }
simply checks to see if the inner text is equal to value, and if it is then makes it equal to the same value :confused:

C#:
if (settingElement[path].InnerText != value)
    {
    System.Xml.XmlDocument doc = settingElement.OwnerDocument;
    System.Xml.XmlElement newElement = doc.CreateElement(path);
    newElement[path].InnerText = value;
    }
should do the same thing.

It looks as though you have a couple of minor typos though
C#:
public void WriteXML(String TheParent, String TheChild, String TheValue)
        {
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            doc.Load(@"SP.xml");

            System.Xml.XmlNode node = doc.DocumentElement;

            SetElement(node[TheParent], TheChild, TheValue);

            doc.Save(@"SP.xml");
        }
is probably what you mean to do for the WriteXML.

The main problem I have is Im unsure if you wish to change the value of the existing Subjects element or add a new element.
For the first case you could just do
C#:
private void SetElement(System.Xml.XmlElement settingElement, string path, string value)
{
if (settingElement[path].InnerText != value)
    settingElement[path].InnerText = value;
}

If you need to append a new element try something along the lines of
C#:
private void SetElement(System.Xml.XmlElement settingElement, string path, string value)
{
if (settingElement[path].InnerText != value)
    {
    System.Xml.XmlDocument doc = settingElement.OwnerDocument;
    System.Xml.XmlElement newElement = doc.CreateElement(path);
    newElement.InnerText = value;
    settingElement.ParentNode.AppendChild(newElement);
    }
}
 
WOOOOOOOOOOOOOOOOOOOOOOO!!!!!!!!! IT WORKS!!!!!



Omg: PlausiblyDamp, I am forever in your debt. I was having problems with that for so long. Thank you sooooo much. And btw I was using the loop because in another forum I asked about this and he showed me that code, with a loop. I really didnt understand it either. Anyways thanks sooooooo much again =))))))))) You made my day.
 
Ok X_x Im having problems again. I cant save the document...

I want to do both adding an element and changing one:

I have -


<Ore>
<Copper>
<NumOre>0</NumOre>
</Copper>
<Tin>
<NumOre>0</NumOre>
</Tin>
<Iron>
<NumOre>0</NumOre>
</Iron>
</Ore>


I want -

<Ore>
<Copper>
<NumOre>0</NumOre>
</Copper>
<Tin>
<NumOre>1</NumOre>
<Col1>35,67,82</Col1>
</Tin>
<Iron>
<NumOre>0</NumOre>
</Iron>
</Ore>



The code I have:

C#:
        static string GetOreNum(String TheChild)
        {
            System.IO.StreamReader sr = new System.IO.StreamReader(@"Colors.xml");
            System.Xml.XmlTextReader xr = new System.Xml.XmlTextReader(sr);
            System.Xml.XmlDocument SP = new System.Xml.XmlDocument();
            SP.Load(xr);
            System.Xml.XmlNodeList SPParent = SP.SelectNodes("Ore/" + TheChild);
            System.Xml.XmlNode SPChild = SPParent.Item(0).SelectSingleNode("NumOre");
            
            return SPChild.InnerText;
        }


        public void WriteXML(String TheParent, String TheChild, String NChild, String TheValue)
        {
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            doc.Load(@"Colors.xml");
            System.Xml.XmlNode node = doc.DocumentElement;
            AddElement(node[TheChild], NChild, TheValue);
            String OreNum = GetOreNum(TheChild);
            int NewOreNum = Int32.Parse(OreNum) + 1;
            SetElement(node[TheChild], "NumOre", NewOreNum.ToString());
            doc.Save(@"Colors.xml");
        }


        private void AddElement(System.Xml.XmlElement settingElement, string path, string value)
        {
                System.Xml.XmlDocument doc = settingElement.OwnerDocument;
                System.Xml.XmlElement newElement = doc.CreateElement(path);
                newElement.InnerText = value;
                settingElement.AppendChild(newElement);
        }


        private void SetElement(System.Xml.XmlElement settingElement, string path, string value)
        {
            if (settingElement[path].InnerText != value)
                settingElement[path].InnerText = value;
        }


            String Parent = "Ore";
            String Child = "Tin";
            String OreNum = GetOreNum(Child);
            int NewOreNum = Int32.Parse(OreNum) + 1;
            Col.Text = "35,67,82";
            WriteXML(Parent, Child, "Col" + NewOreNum.ToString(), Col.Text);





I am getting the error on:

C#:
doc.Save(@"Colors.xml");

IOException was unhandled

The process cannot access the file "path" because it is being used by another process.




I dont have the file open and no other program is using it. Any ideas? =( I know the write works because I can save it to a different filename and it saves fine and has all the stuff I want, but it wont save to the same filename that it was loaded from.
 
JBudOne said:
I dont have the file open and no other program is using it.

Yes you do, take a look:

C#:
        static string GetOreNum(String TheChild)
        {
            System.IO.StreamReader sr = new System.IO.StreamReader(@"Colors.xml"); //<--- File is opened here

            System.Xml.XmlTextReader xr = new System.Xml.XmlTextReader(sr);
            System.Xml.XmlDocument SP = new System.Xml.XmlDocument();
            SP.Load(xr);
            System.Xml.XmlNodeList SPParent = SP.SelectNodes("Ore/" + TheChild);
            System.Xml.XmlNode SPChild = SPParent.Item(0).SelectSingleNode("NumOre");
            
            return SPChild.InnerText;
        }

You need to call sr.Close(); after loading the XML.

Good luck :cool:
 
I find it interesting that the file is being opened with a StreamReader class, passed to a XmlTextReader class, then read in with the XmlDocument class. One of the overloads for the XmlDocument class accepts a path as a parameter, using this should sidestep the problem altogether as well as neaten up the code.
 
Back
Top