locked
Visual Studio 2013 (Visual Basic) Save/Writing XML to File from Form RRS feed

  • Question

  • I would "from what I can personally tell" is to do a simple thing .... I digress.

    I would like to simply take a feed from a local XML file, load it, find the item that matches a Unique ID modify it and then save the file back to the file location.

    Does anyone know how to do this using the XDocument.Load function in combination with the XMLWriter.Save function? 

    I will say this is the one thing that seems to be something anyone would do and Microsoft has made it nearly impossible to find information on how to do it.  Oh, I am doing this in a Visual Basic XAML Windows Store application in Visual Basic .... So, please do not respond with 2012, C, or Windows Desktop responses.

    My XML is based on something like this:

    File stored within the project at: "VehicleData/VehicleData.xml"

    <?xml version="1.0" encoding="utf-8" ?>
    <?test value?>
      <!--Vechicle Data for the Application - Entered by User-->
    <Vehicles>
      <Vehicle>
        <VehicleVIN>SAMPLEVIN1</VehicleVIN>
        <VehicleNCAPModelID>8160</VehicleNCAPModelID>
        <ModelYear>2014</ModelYear>
        <Make>Toyota</Make>
        <Model>Prius</Model>
      </Vehicle>
      <Vehicle>
        <VehicleVIN>SAMPLEVIN2</VehicleVIN>
        <VehicleNCAPModelID>3966</VehicleNCAPModelID>
        <ModelYear>1999</ModelYear>
        <Make>Honda</Make>
        <Model>Civic</Model>
      </Vehicle>
       <Vehicle>
        <VehicleVIN>SAMPLEVIN3</VehicleVIN>
         <VehicleNCAPModelID>1578</VehicleNCAPModelID>
         <ModelYear>2005</ModelYear>
        <Make>Ford</Make>
        <Model>Ranger</Model>
      </Vehicle>
       <Vehicle>
        <VehicleVIN>SAMPLEVIN4</VehicleVIN>
         <VehicleNCAPModelID>2174</VehicleNCAPModelID>
         <ModelYear>2007</ModelYear>
        <Make>Toyota</Make>
        <Model>Corolla</Model>
      </Vehicle>
      <Vehicle>
        <VehicleVIN>SAMPLEVIN5</VehicleVIN>
        <VehicleNCAPModelID>7731</VehicleNCAPModelID>
        <ModelYear>2013</ModelYear>
        <Make>Acura</Make>
        <Model>RDX</Model>
      </Vehicle>
    </Vehicles>


    M. Frenchik Developer At Large




    Friday, June 20, 2014 8:55 PM

Answers

  • What regarding this do you think changed between 2012 and 2013? Can you show your code that worked in 2012 and explain where it fails? It should be essentially the same in 2013.

    The code you linked targets the desktop and never would have worked in a Windows Store app.

    Here's the same code converted to save in the app's local folder using Windows Runtime storage API instead of desktop file access.

        Public Async Sub WriteXML()
            Dim overview As New Book
            Dim folder As StorageFolder = Windows.Storage.ApplicationData.Current.LocalFolder
            Dim file As StorageFile = Await folder.CreateFileAsync("SerializationOverview.xml", CreationCollisionOption.ReplaceExisting)
            Dim stream As Stream = Await file.OpenStreamForWriteAsync()
            overview.Title = "Serialization Overview"
            Dim serializer As New System.Xml.Serialization.XmlSerializer(GetType(Book))
            Dim writer As New System.IO.StreamWriter(stream)
            serializer.Serialize(writer, overview)
            stream.Dispose()
        End Sub
    • Marked as answer by GoliathRulz Saturday, June 21, 2014 12:36 PM
    Friday, June 20, 2014 9:48 PM
    Moderator
  • Thanks Rob again for getting me down the right path!

    OK got it!  Just need to get the target location of the file fixed.

    I have this as my Import on the module ... probably overkill, but it works.

    Imports Windows.Web.Http
    Imports System.Xml.XmlWriter
    Imports System.Xml.XmlReader
    Imports System.Xml
    Imports System.IO.TextWriter
    Imports System.IO
    Imports Windows.Storage
    Imports System
    Imports System.Xml.Serialization
    Imports Microsoft.VisualBasic
    

    Here is my XML

    <?xml version="1.0" encoding="utf-8"?>
    <Vehicles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <myVehicle VehicleUID="TESTVEH1">
        <VehicleVIN>SAMPLEVIN5</VehicleVIN>
        <VehicleMake>Toyota</VehicleMake>
        <VehicleModel>Prius</VehicleModel>
        <VehicleNCAPID>8710</VehicleNCAPID>
      </myVehicle>
    </Vehicles>
    Code Solution .... with Class Setup
        Public Async Sub WriteXML(vehVIN As String)
    
            'Dim queryitem As Object
            Dim sFilename As String = "VehicleData/VehicleData.xml"
            ' Load XML Based data from Feed and Local File
            Dim MyVehiclesXml As XDocument = XDocument.Load(sFilename)
            Dim myvehiclesquery = From myVehicleInfo In MyVehiclesXml...<Vehicle> _
                               Select VehicleVIN = myVehicleInfo.<VehicleVIN>.Value, VehicleYear = myVehicleInfo.<ModelYear>.Value, _
                                VehicleNCAPModelID = myVehicleInfo.<VehicleNCAPModelID>.Value, _
                                VehicleMake = myVehicleInfo.<Make>.Value(), VehicleModel = myVehicleInfo.<Model>.Value() _
                                Where VehicleNCAPModelID.Contains("SAMPLEVIN3")
    
    
            Dim folder As StorageFolder = Windows.Storage.ApplicationData.Current.LocalFolder
            Dim file As StorageFile = Await folder.CreateFileAsync("VehicleData.xml", CreationCollisionOption.ReplaceExisting)
            Dim stream As Stream = Await file.OpenStreamForWriteAsync()
            Dim serializer As New System.Xml.Serialization.XmlSerializer(GetType(Vehicles))
            Dim writer As New System.IO.StreamWriter(stream)
    
            ' Establish XML Structure for New File
            Dim vehiclefile As New Vehicles()
    
            ' Establish Values for Vehicle
            Dim vehicledetails As New MyVehicleData()
            vehicledetails.VehicleUID = "TESTVEH1"
            vehicledetails.VehicleVIN = vehVIN
            vehicledetails.VehicleMake = "Toyota"
            vehicledetails.VehicleModel = "Prius"
            vehicledetails.VehicleNCAPID = 8710
    
            ' Populate Vehicle Inforamation
            vehiclefile.myVehicle = vehicledetails
    
            serializer.Serialize(writer, vehiclefile)
            stream.Dispose()
        End Sub
    
    Public Class Vehicles
        Public myVehicle As MyVehicleData
    End Class
    
    Public Class MyVehicleData
        <XmlAttribute()> _
        Public VehicleUID As String
        Public VehicleVIN As String
        Public VehicleYear As String
        Public VehicleMake As String
        Public VehicleModel As String
        Public VehicleNCAPID As String
    End Class


    M. Frenchik Developer At Large


    • Marked as answer by GoliathRulz Saturday, June 21, 2014 12:57 AM
    • Edited by GoliathRulz Saturday, June 21, 2014 1:05 AM
    Saturday, June 21, 2014 12:57 AM

All replies

  • And before we go down the link path .... This does not work in 2013 .... as they changed how to do it and decided not to tell anyone ....

    http://msdn.microsoft.com/en-us/library/ms172873.aspx


    M. Frenchik Developer At Large

    Friday, June 20, 2014 9:16 PM
  • What regarding this do you think changed between 2012 and 2013? Can you show your code that worked in 2012 and explain where it fails? It should be essentially the same in 2013.

    The code you linked targets the desktop and never would have worked in a Windows Store app.

    Here's the same code converted to save in the app's local folder using Windows Runtime storage API instead of desktop file access.

        Public Async Sub WriteXML()
            Dim overview As New Book
            Dim folder As StorageFolder = Windows.Storage.ApplicationData.Current.LocalFolder
            Dim file As StorageFile = Await folder.CreateFileAsync("SerializationOverview.xml", CreationCollisionOption.ReplaceExisting)
            Dim stream As Stream = Await file.OpenStreamForWriteAsync()
            overview.Title = "Serialization Overview"
            Dim serializer As New System.Xml.Serialization.XmlSerializer(GetType(Book))
            Dim writer As New System.IO.StreamWriter(stream)
            serializer.Serialize(writer, overview)
            stream.Dispose()
        End Sub
    • Marked as answer by GoliathRulz Saturday, June 21, 2014 12:36 PM
    Friday, June 20, 2014 9:48 PM
    Moderator
  • Thanks for getting back quick Rob. BTW the last round you help me got me down a good track.  Now if I can get something to write to a file that would be the trick.

    This is the path I was going down and ran into a wall (3 hours long).  Yea I'm one to punish myself before posting ....

    The MyVehicleXML.Save("VehicleData.xml") is where it falls apart.  I think the write-back to the XML is a bit screwy also, but I would just take getting something to write to a file for the solution in this situation.  I can keep plugging on the XML piece. 

    I guess if I were to just start simple and have a routine that had say:

    1.) A person clicks a button on a form; and

    2.) Then "This is a new file" saves in a test.txt file in a directory in a Windows Store app

    How would something like that simply be done?  

    Here is my code:

        Public Sub VehicleInfoSave( _
           ByVal vehVIN As String)
            Dim queryitem As Object
            Dim sFilename As String = "VehicleData/VehicleData.xml"
            ' Load XML Based data from Feed and Local File
            Dim MyVehiclesXml As XDocument = XDocument.Load(sFilename)
            Dim myvehiclesquery = From myVehicleInfo In MyVehiclesXml...<Vehicle> _
                               Select VehicleVIN = myVehicleInfo.<VehicleVIN>.Value, VehicleYear = myVehicleInfo.<ModelYear>.Value, _
                                VehicleNCAPModelID = myVehicleInfo.<VehicleNCAPModelID>.Value, _
                                VehicleMake = myVehicleInfo.<Make>.Value(), VehicleModel = myVehicleInfo.<Model>.Value() _
                                Where VehicleNCAPModelID.Contains(vehVIN)
    
            Dim varNewNCAPID As String = cmbNCAPID.SelectedValue
    
            For Each queryitem In myvehiclesquery
                If queryitem.VehicleVIN = vehVIN Then
                    queryitem.VehicleNCAPModelID.Value = varNewNCAPID
                End If
            Next
    
            MyVehiclesXml.Save("VehicleData.xml")
    
        End Sub

    M. Frenchik Developer At Large


    Friday, June 20, 2014 10:14 PM
  • Error is "Overload resolution failed because no accessible 'Save' can be called with these arguments: Public Sub Save (writer As System.XML.XMLWriter) ..... etc.

    On the one you posted there is all sorts of crazy .....

    Book not defined

    StorageFolder not defined

    StorageFile not defined .... etc.


    M. Frenchik Developer At Large


    Friday, June 20, 2014 10:16 PM
  • Book is any class named book. You can use the one from the original link.

    For the others you need to Import Windows.Storage . Visual Studio tells you this. See Visual Studio's Red Squigglies (it works essentially the same in C# and VB).

    Your app doesn't have write access to its install directory, so you can't save back to VehicleData\VehicleData.xml in the project. You will need to save it out to application data.

    --Rob

    Friday, June 20, 2014 10:37 PM
    Moderator
  • Ah, OK .... Let me give it a go.    Update coming ......

    M. Frenchik Developer At Large

    Friday, June 20, 2014 10:40 PM
  • OK, holy cheese wiz Batman .... the thing wrote to the file system with the routine above and created a XML that I can logically understand ....   Thanks Rob.

    I'm going to assume that this means is I should target a specific directory out of the install package for the local source XML.

    How do you get the directory to move from

    Dim folder As StorageFolder = Windows.Storage.ApplicationData.Current.LocalFolder

    To something like:

    My Documents / My <appname> / 

    Here is the successful write of the XML off the routine above.

    <?xml version="1.0" encoding="utf-8"?>
    <Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Title>Serialization Overview</Title>
    </Book>


    M. Frenchik Developer At Large


    Friday, June 20, 2014 11:19 PM
  • One more question on this one ...

    If the base class is something simple like the Book Class (which makes the first Element) ...

     Public Class Book
            Public Title As String 
        End Class 

    How would you expand this to have a structure with the aspect of the following when it writes up?

    <Vehicles>
      <Vehicle>
        <VehicleVIN>SAMPLEVIN1</VehicleVIN>
        <VehicleNCAPModelID>8160</VehicleNCAPModelID>
        <ModelYear>2014</ModelYear>
        <Make>Toyota</Make>
        <Model>Prius</Model>
      </Vehicle>


    M. Frenchik Developer At Large

    Friday, June 20, 2014 11:54 PM
  • Actually I think I have found the complex serialization example .... It's in C but I'm working through it ...

    http://msdn.microsoft.com/en-us/library/aa719523.aspx


    M. Frenchik Developer At Large

    Friday, June 20, 2014 11:59 PM
  • OK, got this far and now I'm stuck ......

    The piece where it breaks is where I am trying to get the string from the incoming form to populate the test field of VehicleVIN

    Line specifically is:

    vehiclefile.myVehicle.VehicleVIN = vehVIN

    It checks out in the coding screen but gives an undefined error in the runtime.

    ' Part of Class MainForm
    
    
        Public Async Sub WriteXML(vehVIN As String)
            Dim vehiclefile As New VehiclesWrite
            Dim sFilename As String = "VehicleData/VehicleData.xml"
            ' Load XML Based data from Feed and Local File
            Dim MyVehiclesXml As XDocument = XDocument.Load(sFilename)
            Dim myvehiclesquery = From myVehicleInfo In MyVehiclesXml...<Vehicle> _
                               Select VehicleVIN = myVehicleInfo.<VehicleVIN>.Value, VehicleYear = myVehicleInfo.<ModelYear>.Value, _
                                VehicleNCAPModelID = myVehicleInfo.<VehicleNCAPModelID>.Value, _
                                VehicleMake = myVehicleInfo.<Make>.Value(), VehicleModel = myVehicleInfo.<Model>.Value() _
                                Where VehicleNCAPModelID.Contains("SAMPLEVIN3")
    
            Dim folder As StorageFolder = Windows.Storage.ApplicationData.Current.LocalFolder
            Dim file As StorageFile = Await folder.CreateFileAsync("VehicleData.xml", CreationCollisionOption.ReplaceExisting)
            Dim stream As Stream = Await file.OpenStreamForWriteAsync()
            vehiclefile.myVehicle.VehicleVIN = vehVIN
            Dim serializer As New System.Xml.Serialization.XmlSerializer(GetType(VehiclesWrite))
            Dim writer As New System.IO.StreamWriter(stream)
            serializer.Serialize(writer, vehiclefile)
            stream.Dispose()
        End Sub
    
        Private Sub Save_Clicked(sender As Object, e As RoutedEventArgs)
            WriteXML(vehVIN.Text)
        End Sub
    
    End Class
    
    Public Class VehiclesWrite
        Public myVehicle As Vehicle
    End Class
    
    Public Class Vehicle
        Public VehicleVIN As String
    End Class
    


    M. Frenchik Developer At Large

    Saturday, June 21, 2014 12:12 AM
  • Thanks Rob again for getting me down the right path!

    OK got it!  Just need to get the target location of the file fixed.

    I have this as my Import on the module ... probably overkill, but it works.

    Imports Windows.Web.Http
    Imports System.Xml.XmlWriter
    Imports System.Xml.XmlReader
    Imports System.Xml
    Imports System.IO.TextWriter
    Imports System.IO
    Imports Windows.Storage
    Imports System
    Imports System.Xml.Serialization
    Imports Microsoft.VisualBasic
    

    Here is my XML

    <?xml version="1.0" encoding="utf-8"?>
    <Vehicles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <myVehicle VehicleUID="TESTVEH1">
        <VehicleVIN>SAMPLEVIN5</VehicleVIN>
        <VehicleMake>Toyota</VehicleMake>
        <VehicleModel>Prius</VehicleModel>
        <VehicleNCAPID>8710</VehicleNCAPID>
      </myVehicle>
    </Vehicles>
    Code Solution .... with Class Setup
        Public Async Sub WriteXML(vehVIN As String)
    
            'Dim queryitem As Object
            Dim sFilename As String = "VehicleData/VehicleData.xml"
            ' Load XML Based data from Feed and Local File
            Dim MyVehiclesXml As XDocument = XDocument.Load(sFilename)
            Dim myvehiclesquery = From myVehicleInfo In MyVehiclesXml...<Vehicle> _
                               Select VehicleVIN = myVehicleInfo.<VehicleVIN>.Value, VehicleYear = myVehicleInfo.<ModelYear>.Value, _
                                VehicleNCAPModelID = myVehicleInfo.<VehicleNCAPModelID>.Value, _
                                VehicleMake = myVehicleInfo.<Make>.Value(), VehicleModel = myVehicleInfo.<Model>.Value() _
                                Where VehicleNCAPModelID.Contains("SAMPLEVIN3")
    
    
            Dim folder As StorageFolder = Windows.Storage.ApplicationData.Current.LocalFolder
            Dim file As StorageFile = Await folder.CreateFileAsync("VehicleData.xml", CreationCollisionOption.ReplaceExisting)
            Dim stream As Stream = Await file.OpenStreamForWriteAsync()
            Dim serializer As New System.Xml.Serialization.XmlSerializer(GetType(Vehicles))
            Dim writer As New System.IO.StreamWriter(stream)
    
            ' Establish XML Structure for New File
            Dim vehiclefile As New Vehicles()
    
            ' Establish Values for Vehicle
            Dim vehicledetails As New MyVehicleData()
            vehicledetails.VehicleUID = "TESTVEH1"
            vehicledetails.VehicleVIN = vehVIN
            vehicledetails.VehicleMake = "Toyota"
            vehicledetails.VehicleModel = "Prius"
            vehicledetails.VehicleNCAPID = 8710
    
            ' Populate Vehicle Inforamation
            vehiclefile.myVehicle = vehicledetails
    
            serializer.Serialize(writer, vehiclefile)
            stream.Dispose()
        End Sub
    
    Public Class Vehicles
        Public myVehicle As MyVehicleData
    End Class
    
    Public Class MyVehicleData
        <XmlAttribute()> _
        Public VehicleUID As String
        Public VehicleVIN As String
        Public VehicleYear As String
        Public VehicleMake As String
        Public VehicleModel As String
        Public VehicleNCAPID As String
    End Class


    M. Frenchik Developer At Large


    • Marked as answer by GoliathRulz Saturday, June 21, 2014 12:57 AM
    • Edited by GoliathRulz Saturday, June 21, 2014 1:05 AM
    Saturday, June 21, 2014 12:57 AM