Search code examples
xmlvb.netnodesreadxml

Read xml nodes to dataset, edit values of descendants and save (Visal Studio) - reopen


This is my sample.xml file. I'm looking for instruction how to read this and put content from all nodes (subnodes) to DataSet and show it in DataGrid. I can only read single Node (without subnodes).

My code is below:

Private Sub ReadXmlButton_Click() Handles ReadXmlButton.Click

    Dim filePath As String = "C:\Path\"
    DataSet.ReadXml("C:\Path\sample.xml")

    DataGridView1.DataSource = DataSet
    DataGridView1.DataMember = "CART_ID"
End Sub

But it reads only head Node without SubNodes (1000, 10.05, YES, 8, 2). I want to display all informations (example: 1000, 10.05, A1A, Triangle, 10, 1, YES, 8, 2) from first (and all)CART_ID in DataGridView.

My result: enter image description here

Expected result: enter image description here

sample.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <XML_FILE>
        <typ>xml</typ>
        <ID>
            <NR>007</NR>
        </ID>
        <PERSONAL>
            <Surname>John</Surname>
            <Name>Smith</Name>
        </PERSONAL>
        <COUNTRY>
            <CName>UK</CName>
        </COUNTRY>
          <CITY>
            <TOWN>
                <TOWN_ID>
                    <PART_ID>
                        <CART_ID>
                            <SIMPLE_ID>1000</SIMPLE_ID>
                            <SIMPLE_AREA_ID>10.05</SIMPLE_AREA_ID>
                            <PLACE_ID>
                                <SPECIFIC_ID>
                                    <id>A1A</id>
                                    <name>Triangle</name>
                                    <area>10</area>
                                    <note>1</note>
                                </SPECIFIC_ID>
                            </PLACE_ID>
                            <Control>YES</Control>
                            <Control_area>8</Control_area>
                            <Control_rest>2</Control_rest>
                        </CART_ID>
                              <CART_ID>
                            <SIMPLE_ID>2000</SIMPLE_ID>
                            <SIMPLE_AREA_ID>20.05</SIMPLE_AREA_ID>
                            <PLACE_ID>
                                <SPECIFIC_ID>
                                    <id>B1B</id>
                                    <name>Triangle</name>
                                    <area>20</area>
                                    <note>2</note>
                                </SPECIFIC_ID>
                            </PLACE_ID>
                            <Control>YES</Control>
                            <Control_area>18</Control_area>
                            <Control_rest>2</Control_rest>
                        </CART_ID>
                    </PART_ID>
                 </TOWN_ID>
            </TOWN>
        </CITY>
</XML_FILE>

UPDATED: The last thing is how to save modified descendant (for example - manually changed SIMPPLE_ID from 1000 to 5000, etc.) to original sample.xml file ? Is it possible to do it with this solution or should I look for other way ?


Solution

  • @Artec I haven't used WinForms for the longest time and I'm not sure if there's an easier way to determine which specific row and column was changed. For now, I'm just going for the simplest and basic solution to set you to the right direction.

    First off, we can't just directly replace the dataset back to the xml because of your xml structure. There's no way of telling that the code needs to go few levels deep into the CART_ID element. So, we'll just be reversing the approach of loading the xml.

    Using the same CartItem class from my previous answer, we cast the DataGridView dataset to the list of CartItem. Update the xDoc elements with the values of the list and save the xDocument back to the xml.

    Public Class Form1
    
        Private _CartItems As List(Of CartItem)
        'TODO: Replace ... with the file location.
        Private _FilePath As String = "...\source.xml"
    
        '... Button1_Click and BuildCart in here.
    
        Private Sub UpdateXmlButton_Click(sender As Object, e As EventArgs) Handles UpdateXmlButton.Click
            _CartItems = DirectCast(DataGridView1.DataSource, List(Of CartItem))
            UpdateXml()
            MessageBox.Show("Update Done.")
        End Sub
    
        Private Sub UpdateXml()
            Dim xDoc As XDocument = XDocument.Load(_FilePath)
            Dim cartIDs As IEnumerable(Of XElement) = xDoc.Root.Descendants("CART_ID")
    
            For index As Integer = 0 To cartIDs.Count - 1
                Dim cartElement As XElement = cartIDs.ElementAt(index)
                Dim item As CartItem = _CartItems(index)
    
                With cartElement
                    .Descendants("SIMPLE_ID").Value = item.Simple_Area_ID
                    .Descendants("SIMPLE_AREA_ID").Value = item.Simple_ID
                    .Descendants("id").Value = item.Place_ID
                    .Descendants("name").Value = item.Place_Name
                    '...
                End With
            Next
    
            xDoc.Save(_FilePath)
        End Sub
    End Class
    

    You're practically changing the elements of the loaded XDocument in memory and throwing it back into the xml file. There's definitely a lot of improvement that can be done, like:

    • looping through the properties instead of coding each property in a line. This can be achieved with the combination of reflection and dictionary.
    • updating only the elements that were changed instead of changing the entire thing
    • etc.

    But code above should get you started.