How to save data from a form to a xml file?

i'm trying to find a way to store data entered in a form into a xml file
i have found some codes~ it worked~ but when i want to store another set of data~ it replaces the one i enter before~
it's like it's creating a new xml file each time i store data in the xml file
the code i used is this

Dim xmlTW As New XmlTextWriter("..\CYFmembers.xml", Nothing)

With xmlTW
.Formatting = Formatting.Indented
.Indentation = 2

.WriteStartDocument()
.WriteStartElement("CYFMembers")
.WriteStartElement("Members")

.WriteElementString("FirstName", txt_fname.Text)
.WriteElementString("LastName", txt_lname.Text)
.WriteElementString("D.O.B", txt_dob.Text)
.WriteElementString("Telephone", txt_tele.Text)
.WriteElementString("Mobile", txt_mob.Text)
.WriteElementString("Address1", txt_add1.Text)
.WriteElementString("Address2", txt_add2.Text)
.WriteElementString("Address3", txt_add3.Text)
.WriteElementString("PostCode", txt_post.Text)
.WriteElementString("E-mail", txt_email.Text)

.WriteEndElement()
.WriteEndElement()

.WriteEndDocument()

.Flush()
.Close()

End With

what else do i need to do if i want to carry on entering data into the same xml file or are there different codes to do this

thank you very much


Answer this question

How to save data from a form to a xml file?

  • NickBuck

    There are really many ways to accomplish this, but Serialization of some sort is probably best.  By creating an object that supports serialization and filling it with your values, you can leverage the power of the framework and not worry about so many XML specific details.

    Here is an example that does just that.  It uses the new generic ListOf to create a list of strings that are contained within a list of list of string.  :)  Sounds confusing but look at the following example.

    To build this example, create a blank form, add three single line text boxes (TextBox1, TextBox2, and TextBox3), and then add a button (Button1) for those three text boxes.  This will represent your input controls and save data button.  Next, add a multiline text box (TextBox4) and one more button (Button2).  This will be the load button and output control - to show the results of saving the data.

    Now add the following code for the click events of the two buttons.



    Private
    Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    'Create the ListOf(ListOf(String))

    'This is a simple container for a collection of strings that supports serialization

    Dim ExistingData As New List(Of List(Of String))

    'Create the XML serialization object

    Dim Serializer As New System.Xml.Serialization.XmlSerializer(GetType(List(Of List(Of String))))

    'If we already have a data file, load its contents so that previously saved data is not overwritten

    If System.IO.File.Exists("C:\MySavedData.xml") Then

    'Create a FileStream to read the XML text file into

    Dim OpenStream As System.IO.FileStream = System.IO.File.Open("C:\MySavedData.xml", IO.FileMode.Open)

    'Deserialize the XML into our container object

    ExistingData = Serializer.Deserialize(OpenStream)

    'Close the stream

    OpenStream.Close()

    End If

    'Now create a new ListOf(String) object to hold the new input data

    Dim NewData As New List(Of String)

    'Add the data to the new list

    NewData.Add(TextBox1.Text)

    NewData.Add(TextBox2.Text)

    NewData.Add(TextBox3.Text)

    'Add the new list to the existing string list container

    ExistingData.Add(NewData)

    'Save the updated container back to the XML file on disk

    'Create a file stream as we did above - note the create option rather than open

    Dim SaveStream As System.IO.FileStream = System.IO.File.Open("C:\MySavedData.xml", IO.FileMode.Create)

    'Serialize the container object to XML

    Serializer.Serialize(SaveStream, ExistingData)

    'Close the stream

    SaveStream.Close()

    'Clear the text boxes to show that the save is complete and to allow a new entry

    TextBox1.Clear()

    TextBox2.Clear()

    TextBox3.Clear()

    End Sub


    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

    'This simple example just reads the saved file and displays it in the multiline textbox

    'Create the container object and serialization object as we did above

    Dim ExistingData As New List(Of List(Of String))

    Dim Serializer As New System.Xml.Serialization.XmlSerializer(GetType(List(Of List(Of String))))

    'Check for the file and if it exists open and deserialize it, as above

    If System.IO.File.Exists("C:\MySavedData.xml") Then

    Dim OpenStream As System.IO.FileStream = System.IO.File.Open("C:\MySavedData.xml", IO.FileMode.Open)

    ExistingData = Serializer.Deserialize(OpenStream)

    OpenStream.Close()

    End If

    'Clear the output textbox

    TextBox4.Clear()

    'Loop through the collection of string collections and output their contents

    For Each Entry As List(Of String) In ExistingData

    TextBox4.AppendText("Entry Data:")

    TextBox4.AppendText(ControlChars.NewLine)

    For Each Item As String In Entry

    TextBox4.AppendText(Item)

    TextBox4.AppendText(ControlChars.NewLine)

    Next

    TextBox4.AppendText(ControlChars.NewLine)

    Next

    End Sub


    As you can see, this is a fairly simple and straight-forward way of saving data to xml.  Now, you may wish to expand upon this idea in order to get more functionality - namely by creating a custom object to load your data into that supports more fields such as timestamp, user data, etc.  If you plan to have this XML file modified very often, it may begin to grow too large and so further modification may be necessary for performance reasons.

    But this basic example should get you started!

    Good luck!

    Oh - I should also add, if you are using framework 1.x and cannot use the new generic ListOf() object, just use a System.Collections.ArrayList instead.



  • ALFKI

    Yes, that works. That is, until his application ab-ends or experiences power failure -- anything that prevents the application from executing the form's close event properly.  Secondly, what happens if he closes the application, then opens it back up later   He would suffer the same problem as before -- that is having more than one root element.
  • Moistly

    wow thanx a lot rkimble
    thanx everyone ^^ thank you!!!
    it works now ^^ thanx

  • Ahmed Shahin

    This is what I meant when I said there would have to be extra logic in the Form Load event to read existing data and write this to the XMLTextWriter i.e. rebuild the state appropriately to ensure there is just one root.

    Thanks



  • rabbitoh

    http://msdn.microsoft.com/library/default.asp url=/library/en-us/cpref/html/frlrfsystemxmlxmltextwriterclassctortopic.asp

    Creates an instance of the XmlTextWriter class using the specified =
    TextWriter.
    public XmlTextWriter(TextWriter);

    Creates an instance of the XmlTextWriter class using the specified =
    stream.
    public XmlTextWriter(Stream, Encoding);

    Creates an instance of the XmlTextWriter class using the specified file.
    public XmlTextWriter(string, Encoding);

    The third constructor is the one you're probably using.

    You can use the second constructor, which requires a object of type =
    Stream, or FileStream in this case:


    Dim f As System.IO.FileStream = New System.IO.FileStream("C:\path\to\file", System.IO.FileMode.Append)
    Dim xmlTW As System.Xml.XmlTextWriter = New System.Xml.XmlTextWriter(f, System.Text.Encoding.UTF8)

    This may help you, I'm not an expert on XML but this at least it will allow appending to the File. Which is I think what you were trying to get at.


  • WHMoweryJr

    Here is a simple example of the custom class idea. Please note that you would have to build a complete custom collection to avoid the word "Array" in the XML.

    Public Class MyPerson

    Public FirstName As String

    Public LastName As String

    Public Age As Integer

    End Class

    Public Class MyPeople

    Inherits List(Of MyPerson)

    End Class

    This is the modified save routing for the custom classes MyPerson and MyPeople:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    'Create the ListOf(ListOf(String))

    'This is a simple container for a collection of strings that supports serialization

    Dim ExistingData As New MyPeople

    'Create the XML serialization object

    Dim Serializer As New System.Xml.Serialization.XmlSerializer(GetType(MyPeople))

    'If we already have a data file, load its contents so that previously saved data is not overwritten

    If System.IO.File.Exists("C:\MySavedData.xml") Then

    'Create a FileStream to read the XML text file into

    Dim OpenStream As System.IO.FileStream = System.IO.File.Open("C:\MySavedData.xml", IO.FileMode.Open)

    'Deserialize the XML into our container object

    ExistingData = Serializer.Deserialize(OpenStream)

    'Close the stream

    OpenStream.Close()

    End If

    'Now create a new ListOf(String) object to hold the new input data

    Dim NewData As New MyPerson

    'Add the data to the new list

    NewData.FirstName = TextBox1.Text

    NewData.LastName = TextBox2.Text

    NewData.Age = TextBox3.Text

    'Add the new list to the existing string list container

    ExistingData.Add(NewData)

    'Save the updated container back to the XML file on disk

    'Create a file stream as we did above - note the create option rather than open

    Dim SaveStream As System.IO.FileStream = System.IO.File.Open("C:\MySavedData.xml", IO.FileMode.Create)

    'Serialize the container object to XML

    Serializer.Serialize(SaveStream, ExistingData)

    'Close the stream

    SaveStream.Close()

    'Clear the text boxes to show that the save is complete and to allow a new entry

    TextBox1.Clear()

    TextBox2.Clear()

    TextBox3.Clear()

    End Sub

    And finally, the XML output:

    < xml version="1.0" >

    - <ArrayOfMyPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    - <MyPerson>
    <FirstName>Reed</FirstName>
    <LastName>Kimble</LastName>
    <Age>28</Age>
    </MyPerson>
    - <MyPerson>
    <FirstName>Casey</FirstName>
    <LastName>Kimble</LastName>
    <Age>9</Age>
    </MyPerson>
    </ArrayOfMyPerson>

    Good luck!



  • ant42

    You could do a simple refactoring of your code as indicated in the comments below. This has a disadvantage that you would be keeping the XmlTestWriter instance open as long as the form is open (So if your application encounters any errors before it is closed, all data entered could be lost).

    To preserve existing information in the file you would need a little extra logic in the Form.Load event handler to basically read the Xml for all existing members into an XmlTextReader and write this into your XmlTextWriter. You can read more about
    these APIS here:

    1. http://msdn.microsoft.com/library/default.asp url=/library/en-us/cpguide/html/cpconReadingXMLWithXmlReader.asp
    2. http://msdn.microsoft.com/library/default.asp url=/library/en-us/cpguide/html/cpconWritingXMLWithXmlWriter.asp
    3. http://msdn.microsoft.com/library/default.asp url=/library/en-us/cpguide/html/cpconemployingxmlinnetframework.asp
    4. http://msdn.microsoft.com/msdnmag/issues/01/01/xml/

    'Make xmlTW a private variable on the Form
    Dim xmlTW As New XmlTextWriter("..\CYFmembers.xml", Nothing)

    With xmlTW
    '-----------------------------------------------------------------
    'Move this code to the Form.Load event handler

    .Formatting = Formatting.Indented
    .Indentation = 2

    .WriteStartDocument()
    .WriteStartElement("CYFMembers")
    '-----------------------------------------------------------------
    'Keep this code in the button click event
    .WriteStartElement("Members")

    .WriteElementString("FirstName", txt_fname.Text)
    .WriteElementString("LastName", txt_lname.Text)
    .WriteElementString("D.O.B", txt_dob.Text)
    .WriteElementString("Telephone", txt_tele.Text)
    .WriteElementString("Mobile", txt_mob.Text)
    .WriteElementString("Address1", txt_add1.Text)
    .WriteElementString("Address2", txt_add2.Text)
    .WriteElementString("Address3", txt_add3.Text)
    .WriteElementString("PostCode", txt_post.Text)
    .WriteElementString("E-mail", txt_email.Text)

    .WriteEndElement()
    '-----------------------------------------------------------------
    'Move this code to the From.Close event handler

    .WriteEndElement()

    .WriteEndDocument()

    .Flush()
    .Close()
    '-----------------------------------------------------------------
    End With


    Hope this helps!

    Thanks



  • Andrew Grammenos

    Using something like what ShyamN said...

    'Make xmlTW a private variable on the Form
    Dim xmlTW As New XmlTextWriter("..\CYFmembers.xml", Nothing)

    With xmlTW
    '-----------------------------------------------------------------
    'Move this code to the Form.Load event handler
    .Formatting = Formatting.Indented
    .Indentation = 2

    .WriteStartDocument()
    .WriteStartElement("CYFMembers")
    '-----------------------------------------------------------------
    'Keep this code in the button click event
    .WriteStartElement("Members")

    .WriteElementString("FirstName", txt_fname.Text)
    .WriteElementString("LastName", txt_lname.Text)
    .WriteElementString("D.O.B", txt_dob.Text)
    .WriteElementString("Telephone", txt_tele.Text)
    .WriteElementString("Mobile", txt_mob.Text)
    .WriteElementString("Address1", txt_add1.Text)
    .WriteElementString("Address2", txt_add2.Text)
    .WriteElementString("Address3", txt_add3.Text)
    .WriteElementString("PostCode", txt_post.Text)
    .WriteElementString("E-mail", txt_email.Text)

    .WriteEndElement()
    '-----------------------------------------------------------------
    'Move this code to the From.Close event handler
    .WriteEndElement()

    .WriteEndDocument()

    .Flush()
    .Close()
    '-----------------------------------------------------------------
    End With

    What would be an easy way like that to load back the data stored in the .xml file

    On VB6, all you have to do is put something in your code like "Text1.Text = GetXMLNodeText("FirstName")" and it would retrieve that from the XML that looked something like "<FirstName>Bill</FirstName>" Thus the Textbox1 equaling "Bill"... So how would you load data from an XML file on VB2005 easily like vb6 Thanks.

    P.S. VB2005 says that "GetXMLNodeText" is not declared.


  • JHavenite

    wow these codes works thanx

    in the xml file, the codes are like this

    < xml version="1.0" >
    - <ArrayOfArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    - <ArrayOfString>
    <string>1</string>
    <string>1</string>
    <string>1</string>
    </ArrayOfString>
    - <ArrayOfString>
    <string>22</string>
    <string>2</string>
    <string>2</string>
    </ArrayOfString>
    </ArrayOfArrayOfString>

    is there anyway i can change the title
    <ArrayOfArrayOfString>
    <ArrayOfString> and <string>

    do i need to change something here

    Dim ExistingData As New List(Of List(Of String))

    Dim Serializer As New System.Xml.Serialization.XmlSerializer(GetType(List(Of List(Of String))))






  • Sharewareisland.com

    Well, what your seeing is the result of the CLR as it interprets the generic ListOf object.

    If you create your own custom class(es) to be the container(s) then the name of your class is what will appear in the XML.



  • Wallace_

    Hi rkimble,

    Can you show an example how to extract a specified data (say, the 'FirstName' from the 1st group infomation of your 2nd example) and show in a TextBox. Thank you!


  • __ButterFly__

    Using a stream will allow him to append to the file, but after the second record is written to the file, the file will no longer be parsable because it will contain more than one root element. Another way to append a record to the XML file , and allow the file to validate properly, is to simply use the XmlDocument object. Use the Load event to load the xml file and save to save the xml file again. Use the document object instance's CreateElement object to create new elements and use the XmlDocument.DocumentElement.AppendChild() method to insert a new record in the correct spot.

    There are other methods available that provide this same functionality, such as using a dataset, but I'm not sure what your requirements are.


  • mattdawg

    I definitely agree that serialization as another option. It does require a bit more background work to get the fine-grain control on what exactly is going into the xml file (i.e. element / attribute names, etc), but it does work fairly well. As rkimble said, performance can be a problem with larger files, but this is typically the case when working with large xml files. You could always cut down on the overhead by splitting the xml files up in various ways. (i.e. create a new one daily, split them up by first letter of last name, etc).
  • eriawan

    Not intending to hijack this post, but, how would you go about reading the XML file created using this:

    .WriteStartElement("Members")

    .WriteElementString("FirstName", txt_fname.Text)
    .WriteElementString("LastName", txt_lname.Text)
    .WriteElementString("D.O.B", txt_dob.Text)
    .WriteElementString("Telephone", txt_tele.Text)
    .WriteElementString("Mobile", txt_mob.Text)
    .WriteElementString("Address1", txt_add1.Text)
    .WriteElementString("Address2", txt_add2.Text)
    .WriteElementString("Address3", txt_add3.Text)
    .WriteElementString("PostCode", txt_post.Text)
    .WriteElementString("E-mail", txt_email.Text)


    I have tried this:

    Dim xmlRdr As New Xml.XmlTextReader("C:\TestData.xml") '("C:\TestData.xml", Nothing)

    With xmlRdr

    .ReadStartElement("Test")

    .ReadStartElement("List")

    txt_fname.Text = .ReadElementString("FirstName")

    txt_lname.Text = .ReadElementString("LastName")

    txt_dob.Text = .ReadElementString("D.O.B")

    txt_tele.Text = .ReadElementString("Telephone")

    txt_mob.Text = .ReadElementString("Mobile")

    txt_add1.Text = .ReadElementString("Address1")

    txt_add2.Text = .ReadElementString("Address2")

    txt_add3.Text = .ReadElementString("Address3")

    txt_post.Text = .ReadElementString("PostCode")

    txt_email.Text = .ReadElementString("E-mail")

    .Close()

    End With

    And it blows up with this error:

    System.Xml.XmlException was unhandled
    Message="Element 'FirstName' was not found. Line 2, position 2."
    Source="System.Xml"
    StackTrace:
    at System.Xml.XmlReader.ReadElementString(String name)
    at XMLreaderWriter.Form1.btnXMLread_Click(Object sender, EventArgs e) in C:\Documents and Settings\james\My Documents\Visual Studio 2005\Projects\XMLreaderWriter\XMLreaderWriter\Form1.vb:line 55
    at System.Windows.Forms.Control.OnClick(EventArgs e)
    at System.Windows.Forms.Button.OnClick(EventArgs e)
    at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
    at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
    at System.Windows.Forms.Control.WndProc(Message& m)
    at System.Windows.Forms.ButtonBase.WndProc(Message& m)
    at System.Windows.Forms.Button.WndProc(Message& m)
    at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
    at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
    at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
    at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
    at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
    at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
    at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
    at System.Windows.Forms.Application.Run(ApplicationContext context)
    at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
    at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
    at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
    at XMLreaderWriter.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
    at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
    at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
    at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    at System.Threading.ThreadHelper.ThreadStart()

    Any hints on this I have not had any experience with XML and VB and have a project that at some point will need it. And so, when I saw this post it looked like something that would work for what I needed to do , using the original poster's code.

    james

    aka:Trucker


  • How to save data from a form to a xml file?