Link to home
Start Free TrialLog in
Avatar of Alan Varga
Alan VargaFlag for United States of America

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:

    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

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Randy Poole
Randy Poole
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Alan Varga

ASKER

When I insert that line, an error is reported: "Overload resolution failed because no 'New' is accessible."
I get c# and VB mixed up, replace that with : L1Movie = Doc.CreateElement("movie")
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

    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

Open in new window

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!