Struggling to serialize an xml file using VB.net

424 Views Asked by At

I want to store the below data structure in the XML. I am a beginner in VB .net and XML any help would be appreciated

This is an extension of this Question enter link description here

Public Class PulserMeasDataPA
<XmlElement()>
Public TestData As List(Of TestData)
End Class

Public Class TestData
Public PortNumber As Integer
<XmlArray("Measurement")>
<XmlArrayItem("MeasureValues")>
Public MeasureValues As List(Of MeasureValues)
End Class

Public Class MeasureValues
Public Amplitude As String
Public Fall As String
Public Width As String
Public setWidth As Decimal
Public PRF As Decimal
Public Volt As Decimal
End Class

I want to provide Hard-Coded Data to Serializer so that it can write data to an XML file in my desired location. I want something like this. But this is not working

        Dim newPulseData As New PulserMeasDataPA()
    Dim listofVpaData As List(Of TestData)
    listofVpaData = New List(Of TestData) From
        {
            New TestData(1, New MeasureValues(1, "2", "3", 40, 1000, 100)),
            New TestData(2, New MeasureValues(1, "2", "3", 40, 1000, 100))
    }
    newPulseData.TestData= listofVpaData

XML Serializer Look like this

    Const OUTPUT_FILENAME As String = "c:\temp\test1.xml"
    Dim writer As XmlWriter = XmlWriter.Create(OUTPUT_FILENAME)
    Dim serializer As XmlSerializer = New XmlSerializer(GetType(PulserMeasDataPA))
    serializer.Serialize(writer, newPulseData)

I want to Generate XML Like this from Above Data Structure

<PulserMeasDataPA>
  <TestData>
   <PortNumber>1</PortNumber>
     <Measurement>
     <MeasureValues>
        <Amplitude></Amplitude>
        <Fall></Fall>
        <Width></Width>
        <setWidth>40<setWidth/>
        <PRF>1000<PRF/>
        <Volt>100<Volt/>
    </MeasureValues>
    <MeasureValues>
        <Amplitude></Amplitude>
        <Fall></Fall>
        <Width></Width>
        <setWidth>100<setWidth/>
        <PRF>1000<PRF/>
        <Volt>100<Volt/>
    </MeasureValues>
    <MeasureValues>
        <Amplitude></Amplitude>
        <Fall></Fall>
        <Width></Width>
        <setWidth>40<setWidth/>
        <PRF>5000<PRF/>
        <Volt>50<Volt/>
    </MeasureValues>
    <MeasureValues>
        <Amplitude></Amplitude>
        <Fall></Fall>
        <Width></Width>
        <setWidth>100<setWidth/>
        <PRF>5000<PRF/>
        <Volt>50<Volt/>
    </MeasureValues>
 </Measurement>   
</TestData>     
<TestData>
 <PortNumber>2</PortNumber>
  <Measurement>
    <MeasureValues>
        <Amplitude></Amplitude>
        <Fall></Fall>
        <Width></Width>
        <setWidth>40<setWidth/>
        <PRF>1000<PRF/>
        <Volt>100<Volt/>
    </MeasureValues>
    <MeasureValues>
        <Amplitude></Amplitude>
        <Fall></Fall>
        <Width></Width>
        <setWidth>100<setWidth/>
        <PRF>1000<PRF/>
        <Volt>100<Volt/>
    </MeasureValues>
    <MeasureValues>
        <Amplitude></Amplitude>
        <Fall></Fall>
        <Width></Width>
        <setWidth>40<setWidth/>
        <PRF>5000<PRF/>
        <Volt>50<Volt/>
    </MeasureValues>
    <MeasureValues>
        <Amplitude></Amplitude>
        <Fall></Fall>
        <Width></Width>
        <setWidth>100<setWidth/>
        <PRF>5000<PRF/>
        <Volt>50<Volt/>
    </MeasureValues>
   </Measurement>   
  </TestData>     

The Above XML is what I want to save from that data structure. I want to give values to the lists which are in these classes and I want to store that hard-coded values to the new file that it will generate. in this case, some nested lists and classes are used and I am confused about how to give values to these classes which I tried above but failed.

1

There are 1 best solutions below

1
user246821 On

The reason the code you posted doesn't work, is because you haven't created a constructor for each class that accepts parameters.

Class: TestData

Here's a simple definition for the class:

Public Class TestData

End Class

In the above code, since no constructors were defined, the default constructor is implied. If one were to explicitly include the default constructor, we'd have:

Public Class TestData

    'default constructor
    Public Sub New()

    End Sub

End Class

If we were to add a property to the class, and wanted to set the value using using a constructor, we could do the following:

Public Class TestData
    Public Property PortNumber As Integer

    'default constructor
    Public Sub New()

    End Sub

    'constructor 
    Public Sub New(PortNumber as Integer)
        'set property value
        Me.PortNumber = PortNumber
    End Sub

End Class

Note: When one defines a constructor, the default constructor is no longer implicitly defined. Therefore, if it's not explicitly defined, as shown above, it won't be available. For XML serialization, a default constructor always needs to be defined.

Usage:

This creates numerous options to set the value of PortNumber. I'll cover the following:

  1. Using the desired Property
  2. Using an Object initializer
  3. Using a constructor
  4. Using a method (Sub)

Option 1 - Using the desired Property

'create new instance
Dim td as TestData = New TestData()

'set property value
td.PortNumber = 1

Debug.WriteLine("td.PortNumber: " & td.PortNumber.ToString())

Option 2 - Using an Object initializer

Note: When using With, we use .PortNumber instead of PortNumber.

'create new instance and set property value
Dim td As TestData = New TestData() With { .PortNumber = 1 }

Debug.WriteLine("td.PortNumber: " & td.PortNumber.ToString())

Option 3 - Using a constructor

'create new instance and set property value
Dim td as TestData = New TestData(1)

Debug.WriteLine("td.PortNumber: " & td.PortNumber.ToString())

Option 4 - Using a method (Sub)

For this option, it's necessary to add a method (Sub) to class "TestData".

Public Class TestData
    Public Property PortNumber As Integer

    'ToDo: add desired constructor(s)

    Public Sub SetPortNumber(PortNumber As Integer)
        Me.PortNumber = PortNumber
    End Sub
End Class

Then we can do the following: 'create new instance Dim td as TestData = New TestData()

'set property value
td.SetPortNumber(1)

Debug.WriteLine("td.PortNumber: " & td.PortNumber.ToString())

Now, let's look at how to use a nested class.

Create class MeasureValueInfo

Note: I've changed the name of the class from MeasureValues to MeasureValueInfo to make it easier to understand.

MeasureValueInfo:

Public Class MeasureValueInfo
    Public Property Amplitude As String
    Public Property Fall As String
    Public Property Width As String
    Public Property SetWidth As Decimal
    Public Property PRF As Decimal
    Public Property Volt As Decimal

    Public Sub New()

    End Sub

    Public Sub New(Amplitude As String, Fall As String, Width As String, SetWidth As Decimal, PRF As Decimal, Volt As Decimal)
        'ToDo: add additional parameters and use them to set any additional property values
        Me.Amplitude = Amplitude
        Me.Fall = Fall
        Me.Width = Width
        Me.SetWidth = SetWidth
        Me.PRF = PRF
        Me.Volt = Volt
    End Sub
End Class

Let's add a List of MeasureValueInfo to class TestData.

TestData:

Public Class TestData
    Public Property PortNumber As Integer
    Public Property MeasureValues As List(Of MeasureValueInfo) = New List(Of MeasureValueInfo)

    'default constructor
    Public Sub New()

    End Sub
End Class

Let's add a constructor which allows us to set the value of PortNumber and add also add MeasureValueInfo to our List.

'constructor 
Public Sub New(PortNumber As Integer, measureValue As MeasureValueInfo)
    'set property value
    Me.PortNumber = PortNumber
    Me.MeasureValues.Add(measureValue) 'add
End Sub

So, now we'll have:

Public Class TestData
    Public Property PortNumber As Integer
    Public Property MeasureValues As List(Of MeasureValueInfo) = New List(Of MeasureValueInfo)

    'default constructor
    Public Sub New()

    End Sub

    'constructor 
    Public Sub New(PortNumber As Integer, measureVal As MeasureValueInfo)
        'set property value
        Me.PortNumber = PortNumber
        Me.MeasureValues.Add(measureVal)
    End Sub
End Class

Once again we have multiple ways of setting the property values. I'll demonstrate the following:

  1. Using the desired Property
  2. Using an Object initializer along with a constructor

Usage:

Option 1 - Using the desired Property

'create new instance
Dim td as TestData = New TestData()
td.PortNumber = 1

Dim mvInfo As MeasureValueInfo = Nothing

'create new instance
mvInfo = New MeasureValueInfo()

'set property values
mvInfo.Amplitude = "1"
mvInfo.Fall = "2"
mvInfo.Width = "3"
mvInfo.SetWidth = 40
mvInfo.PRF = 1000
mvInfo.Volt = 100

'add
td.MeasureValues.Add(mvInfo)

'create new instance
mvInfo = New MeasureValueInfo()

'set property values
mvInfo.Amplitude = "1"
mvInfo.Fall = "2"
mvInfo.Width = "3"
mvInfo.SetWidth = 100
mvInfo.PRF = 1000
mvInfo.Volt = 100

'add
td.MeasureValues.Add(mvInfo)

Debug.WriteLine(String.Format("td.PortNumber: {0}", td.PortNumber.ToString()))

For Each mVal As MeasureValueInfo In td.MeasureValues
    'ToDo: add properties to output
    Debug.WriteLine(String.Format("    mVal.Amplitude: {0} mVal.SetWidth: {1}", mVal.Amplitude.ToString(), mVal.SetWidth.ToString()))
Next

Option 2a - Using an Object initializer along with a constructor

Dim td As TestData = New TestData() With {.PortNumber = 1, .MeasureValues = New List(Of MeasureValueInfo) From
    {
        New MeasureValueInfo(Amplitude:="1", Fall:="2", Width:="3", SetWidth:=40, PRF:=1000, Volt:=100),
        New MeasureValueInfo(Amplitude:="1", Fall:="2", Width:="3", SetWidth:=100, PRF:=1000, Volt:=100)
    }}

Debug.WriteLine(String.Format("td.PortNumber: {0}", td.PortNumber.ToString()))

For Each mVal As MeasureValueInfo In td.MeasureValues
    'ToDo: add properties to output
    Debug.WriteLine(String.Format("    mVal.Amplitude: {0} mVal.SetWidth: {1}", mVal.Amplitude.ToString(), mVal.SetWidth.ToString()))
Next

Option 2b - Using an Object initializer along with a constructor

Dim td As TestData = New TestData() With {.PortNumber = 1, .MeasureValues = New List(Of MeasureValueInfo) From
    {
        New MeasureValueInfo("1", "2", "3", 40, 1000, 100),
        New MeasureValueInfo("1", "2", "3", 100, 1000, 100)
    }}

Debug.WriteLine(String.Format("td.PortNumber: {0}", td.PortNumber.ToString()))

For Each mVal As MeasureValueInfo In td.MeasureValues
    'ToDo: add properties to output
    Debug.WriteLine(String.Format("    mVal.Amplitude: {0} mVal.SetWidth: {1}", mVal.Amplitude.ToString(), mVal.SetWidth.ToString()))
Next

In order to use the classes with XML serialization,

Add the following Imports statements:

  • Imports System.Xml
  • Imports System.Xml.Serialization

Then modify the classes so they look like the following:

Note: The code for the classes was adapted from the OP which was given as an answer in this post. The code was changed from using fields to using properties, initialization was added for the Lists, and constructors were added.

Public Class PulserMeasDataPA
    <XmlElement()>
    Public Property TestData As New List(Of TestData)
End Class

Public Class TestData
    Public Property PortNumber As Integer

    <XmlArray("Measurement")>
    <XmlArrayItem("MeasureValues")>
    Public Property MeasureValues As New List(Of MeasureValueInfo)

    Public Sub New()

    End Sub

    Public Sub New(PortNumber As Integer, measureVal As MeasureValueInfo)
        'set property value
        Me.PortNumber = PortNumber
        Me.MeasureValues.Add(measureVal)
    End Sub
End Class

Public Class MeasureValueInfo
    Public Property Amplitude As String
    Public Property Fall As String
    Public Property Width As String
    Public Property SetWidth As Decimal
    Public Property PRF As Decimal
    Public Property Volt As Decimal

    Public Sub New()

    End Sub

    Public Sub New(Amplitude As String, Fall As String, Width As String, SetWidth As Decimal, PRF As Decimal, Volt As Decimal)
        'ToDo: add additional parameters and use them to set any additional property values
        Me.Amplitude = Amplitude
        Me.Fall = Fall
        Me.Width = Width
        Me.SetWidth = SetWidth
        Me.PRF = PRF
        Me.Volt = Volt
    End Sub
End Class

Resources: