Alan Varga
asked on
Write multiple XML child nodes with VB.Net
I am a beginner with VB.Net, but have 10+ experience with VBA in Access and Excel (professional), and 15+ years with XML/XSL/CSS/JS (hobbyist). I understand how to think in XML, but I am stumped and need a little push.
I have a form which reads data from movies.xml (4 movies), allows me to change a value, then re-write all of the data (not just the changes) by replacing movies.xml. To do this, I use XmlReader to read the data into arrays (one for each element/attribute), change the data in the arrays, then use XmlTextWriter to create a new XmlDocument by reading the arrays into Values (for attributes) or InnerTexts (for elements).
In the resulting movies.xml, only the declaration and last movie appear. My question is: once I use Root.AppendChild(L1Movie), isn't that permanent? It appears to be overwritten if I build a new L1Movie element with its children. Here is my code:
I have a form which reads data from movies.xml (4 movies), allows me to change a value, then re-write all of the data (not just the changes) by replacing movies.xml. To do this, I use XmlReader to read the data into arrays (one for each element/attribute), change the data in the arrays, then use XmlTextWriter to create a new XmlDocument by reading the arrays into Values (for attributes) or InnerTexts (for elements).
In the resulting movies.xml, only the declaration and last movie appear. My question is: once I use Root.AppendChild(L1Movie),
Private Sub WriteArraysIntoFile()
'Declare all of the needed components first
Dim OutputFile As New XmlTextWriter(
mcstrDatafile,
System.Text.Encoding.UTF8)
Dim Doc As New XmlDocument
Dim myXmlDeclaration As XmlDeclaration
Dim Root As XmlElement
Dim RootShelf As XmlAttribute
Dim L1Movie As XmlElement
Dim L1MovieTitle As XmlAttribute
Dim L2Type As XmlElement
Dim L2Format As XmlElement
Dim L2Year As XmlElement
Dim L2Episodes As XmlElement
Dim L2Rating As XmlElement
Dim L2Stars As XmlElement
Dim L2Description As XmlElement
'Initialize the overall structure components
myXmlDeclaration =
Doc.CreateXmlDeclaration("1.0", "UTF-8", "yes")
Root = Doc.CreateElement("collection")
RootShelf = Doc.CreateAttribute("shelf")
L1Movie = Doc.CreateElement("movie")
L1MovieTitle = Doc.CreateAttribute("title")
L2Type = Doc.CreateElement("type")
L2Format = Doc.CreateElement("format")
L2Year = Doc.CreateElement("year")
L2Episodes = Doc.CreateElement("episodes")
L2Rating = Doc.CreateElement("rating")
L2Stars = Doc.CreateElement("stars")
L2Description = Doc.CreateElement("description")
Doc.AppendChild(myXmlDeclaration)
' Build the Root and branches, starting with the shelf name
RootShelf.Value = mstrShelf
Root.Attributes.Append(RootShelf)
' Then append the movies
For miintTitlesIndex = 1 To mcintMovieCount
L1MovieTitle.Value = mastrTitles(miintTitlesIndex)
L2Type.InnerText = mastrTypes(miintTitlesIndex)
L2Format.InnerText = mastrFormats(miintTitlesIndex)
L2Year.InnerText = mastrYears(miintTitlesIndex)
L2Episodes.InnerText = mastrEpisodeCounts(miintTitlesIndex)
L2Rating.InnerText = mastrRatings(miintTitlesIndex)
L2Stars.InnerText = mastrStars(miintTitlesIndex)
L2Description.InnerText = mastrDescriptions(miintTitlesIndex)
L1Movie.Attributes.Append(L1MovieTitle)
L1Movie.AppendChild(L2Type)
L1Movie.AppendChild(L2Format)
L1Movie.AppendChild(L2Year)
L1Movie.AppendChild(L2Episodes)
L1Movie.AppendChild(L2Rating)
L1Movie.AppendChild(L2Stars)
L1Movie.AppendChild(L2Description)
Root.AppendChild(L1Movie)
Next ' miintTitlesIndex
Doc.AppendChild(Root)
Doc.WriteTo(OutputFile)
OutputFile.Close()
End Sub
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I get c# and VB mixed up, replace that with : L1Movie = Doc.CreateElement("movie")
ASKER
Based on your intention, and assuming Dim would have the same effect as "new", and assuming the same idea would apply to each of the child elements (i.e. I would keep repeating the previous movie's data), I reshuffled my code as shown. That was exactly the push I needed; the results were finally what I expected. Thanks very much Randy!
Alan
Alan
Private Sub WriteArraysIntoFile()
Dim OutputFile As New XmlTextWriter(
mcstrDatafile,
System.Text.Encoding.UTF8)
Dim Doc As New XmlDocument
' Initialize the document with a doctype declaration
Dim myXmlDeclaration As XmlDeclaration
myXmlDeclaration =
Doc.CreateXmlDeclaration("1.0", "UTF-8", "yes")
Doc.AppendChild(myXmlDeclaration)
' Declare the root node and it's attribute, but do not append to the doc until it is completely built
Dim Root As XmlElement
Root = Doc.CreateElement("collection")
Dim RootShelf As XmlAttribute
RootShelf = Doc.CreateAttribute("shelf")
RootShelf.Value = mstrShelf
Root.Attributes.Append(RootShelf)
' Then append the movies, building the nodes one at a time
For miintTitlesIndex = 1 To mcintMovieCount
Dim L1Movie As XmlElement
L1Movie = Doc.CreateElement("movie")
Dim L1MovieTitle As XmlAttribute
L1MovieTitle = Doc.CreateAttribute("title")
L1MovieTitle.Value = mastrTitles(miintTitlesIndex)
L1Movie.Attributes.Append(L1MovieTitle)
Dim L2Type As XmlElement
L2Type = Doc.CreateElement("type")
L2Type.InnerText = mastrTypes(miintTitlesIndex)
L1Movie.AppendChild(L2Type)
Dim L2Format As XmlElement
L2Format = Doc.CreateElement("format")
L2Format.InnerText = mastrFormats(miintTitlesIndex)
L1Movie.AppendChild(L2Format)
Dim L2Year As XmlElement
L2Year = Doc.CreateElement("year")
L2Year.InnerText = mastrYears(miintTitlesIndex)
L1Movie.AppendChild(L2Year)
Dim L2Episodes As XmlElement
L2Episodes = Doc.CreateElement("episodes")
L2Episodes.InnerText = mastrEpisodeCounts(miintTitlesIndex)
L1Movie.AppendChild(L2Episodes)
Dim L2Rating As XmlElement
L2Rating = Doc.CreateElement("rating")
L2Rating.InnerText = mastrRatings(miintTitlesIndex)
L1Movie.AppendChild(L2Rating)
Dim L2Stars As XmlElement
L2Stars = Doc.CreateElement("stars")
L2Stars.InnerText = mastrStars(miintTitlesIndex)
L1Movie.AppendChild(L2Stars)
Dim L2Description As XmlElement
L2Description = Doc.CreateElement("description")
L2Description.InnerText = mastrDescriptions(miintTitlesIndex)
L1Movie.AppendChild(L2Description)
Root.AppendChild(L1Movie)
Next ' miintTitlesIndex
' Finally, append the completely built Root node to the document, write and close the document
Doc.AppendChild(Root)
Doc.WriteTo(OutputFile)
OutputFile.Close()
End Sub
ASKER
In this case the concept was more important than the code, but was exactly what I needed to get unstuck. I just renewed my annual subscription, and the experts at EE have bailed me out again!
ASKER