Kannan Suresh
Kannan Suresh

Reputation: 4580

How to read xml file using VB.NET by using XElement parsing?

I am pretty new to parsing xml. I tried the solutions provided for similar questions but the xml I have is formatted in a different way. I have an xml file as below which comes from an external tool. I get this as a webresponse from the tool.

<Entities TotalResults="2">
  <Entity Type="release">
    <Fields>
      <Field Name="name">
        <Value>Release1</Value>
      </Field>
      <Field Name="end-date">
        <Value>2015-05-15</Value>
      </Field>
      <Field Name="req-count">
        <Value>29</Value>
      </Field>
      <Field Name="usedPlans">
        <Value>Plan1</Value>
        <Value>Plan2</Value>
      </Field>      
    </Fields>
    <RelatedEntities />
  </Entity>
  <Entity Type="release">
    <Fields>
      <Field Name="name">
        <Value>Release2</Value>
      </Field>
      <Field Name="end-date">
        <Value>2015-05-15</Value>
      </Field>
      <Field Name="req-count">
        <Value>10</Value>
      </Field>
      <Field Name="usedPlans">
        <Value>Plan5</Value>
        <Value>Plan6</Value>
      </Field>      
    </Fields>
    <RelatedEntities />
  </Entity>
</Entities>

I need to get the the following details Release Name, End Date, Req Count, UsedPlans etc

Sample output for the first release would be

Release Name: Release1
End Date: 2015-05-15
Req Count: 29
Used Plans: Plan1, Plan2

VB.NET code:

Public Function getReleaseInfo(cookie As String, domain As String, project As String) As RestResponse
    Dim resp As New relResponse()

    Try
        Dim relStartDate As String = ConfigurationManager.AppSettings("RelStartDate").Trim()
        Dim url = (Convert.ToString((Convert.ToString((Convert.ToString(RestUrl + "/rest/domains/") & domain) + "/projects/") & project) + "/releases?query={start-date[>='") & relStartDate) + "'] }"
        Dim request As WebRequest = WebRequest.Create(url)
        request.Headers.Set(HttpRequestHeader.Cookie, cookie)
        Dim result As WebResponse = request.GetResponse()

        Dim responseStream = result.GetResponseStream()
        If responseStream IsNot Nothing Then
            Dim reader = New StreamReader(responseStream)
            Dim output As String = reader.ReadToEnd()
            Dim xml = XElement.Parse(output)

            'below part gives me req-count but is there a better way. 
            'If I do as below, I have to do this for all items that I need

            Dim reqCount = From r In releaseXML...<Field> Where [email protected] = "req-count" Select counReq = r.Value

            For Each req In reqCount
                Console.WriteLine(req)
            Next


        End If
    Catch ex As Exception
        resp.Good= False
        resp.Error= ex
    End Try

    Return resp
End Function


Dim reqCount = From r In releaseXML...<Field> Where [email protected] = "req-count" Select counReq = r.Value

For Each req In reqCount
    Console.WriteLine(req)
Next

Gives out put in the console as

29
10

Is there any better way to do this?

I have the following code to do the linq query using C# and it's working fine. Unfortunately I am not able to convert it to vb.net I tried many converters and they are failing to give me the correct vb.net version of the query. I am not good in linq to correct it. Can someone convert the code for me.

Working C# code:

string output = reader.ReadToEnd();
var xml = XElement.Parse(output);
var entities = xml.Descendants("Entity");
var releases = (
                from entity in entities
                select entity.Descendants("Field")
                    into fields
                    select fields as IList<XElement> ?? fields.ToList()
                        into xElements
                        let name = xElements.Single(x => x.Attribute("Name").Value == "name").Value
                        let endDate = xElements.Single(x => x.Attribute("Name").Value == "end-date").Value
                        let reqCount = xElements.Single(x => x.Attribute("Name").Value == "req-count").Value                                    
                        let PlansUsed = xElements.Single(x => x.Attribute("Name").Value == "usedPlans").Value                                                                    
                        select new Release { Name = name, EndDate = endDate, ReqCount = reqCount, PlansUsed = usedPlans }).ToList();

Edit: Added working C# code for the linq query. Can someone convert it to vb.net. Note: online converters and other tools are not giving working converted code.

Upvotes: 0

Views: 3990

Answers (2)

Kannan Suresh
Kannan Suresh

Reputation: 4580

Thanks you all for the help. I managed to get a solution for my problem. Here is the code that worked

Public Function getReleaseInfo(cookie As String, domain As String, project As String) As RestResponse
    Dim resp As New relResponse()

    Try
        Dim url = "http://resturl"
        Dim request As WebRequest = WebRequest.Create(url)
        request.Headers.Set(HttpRequestHeader.Cookie, cookie)
        Dim result As WebResponse = request.GetResponse()

        Dim responseStream = result.GetResponseStream()
        If responseStream IsNot Nothing Then
            Dim reader = New StreamReader(responseStream)
            Dim output As String = reader.ReadToEnd()
            Dim xml = XElement.Parse(output)

             Dim releaseInformation = (From e As XElement In xml.Elements
                                          Let relName = e...<Field>.Single(Function(x) x.Attribute("Name").Value = "name").Value
                                          Let relEndDate = e...<Field>.Single(Function(x) x.Attribute("Name").Value = "end-date").Value
                                          Let relReqCount = e...<Field>.Single(Function(x) x.Attribute("Name").Value = "req-count").Value
                                          Let relUsedPlans = e...<Field>.Single(Function(x) x.Attribute("Name").Value = "usedPlans").Elements.ToList
                                          Select New myReleases With {.relName = relName, .relEndDate = relEndDate, .relReqCount = relReqCount, .relUsedPlans = relUsedPlans}).ToList

                resp.Good = True
                resp.result = releaseInformation

        End If
    Catch ex As Exception
        resp.Good= False
        resp.Error= ex
    End Try

    Return resp
End Function

myReleases class

Public Class myReleases
    Public relName As String
    Public relEndDate As Date
    Public relReqCount As Integer
    Public relUsedPlans As List(Of XElement)
    Public ReadOnly Property usedPlans As List(Of String)
        Get
            Dim plans As List(Of String) = (From p In RelUsedPlans Where Trim(p.Value) <> "" Select p.Value).ToList()
            Return plans                
        End Get
    End Property
End Class

Edit: Changed code to return used plans as a list of values

Upvotes: 3

User9995555
User9995555

Reputation: 1556

Try something like this.... this code reads your XML from a file 'xml.xml' into a string then deserialises it to an object, you can then easily get the data you want.....

EDIT...... New Code....... (includes your ALMReleases class)

Imports System.IO
Imports System.Text
Imports System.Xml
Imports System.Xml.Serialization

Module Module1

    Sub Main()
        Dim deserializedXML As Entities
        Dim xmlString As String = File.ReadAllText("xml.xml")

        Dim bufXML As Byte() = ASCIIEncoding.UTF8.GetBytes(xmlString)
        Dim ms1 As MemoryStream = New MemoryStream(bufXML)

        Dim serializer As XmlSerializer = New XmlSerializer(GetType(Entities))

        Try
            Using reader As XmlReader = New XmlTextReader(ms1)
                deserializedXML = DirectCast(serializer.Deserialize(reader), Entities)

                Dim releaseInformation = (From e In deserializedXML.Entity Select New ALMReleases With {
                                                                         .relName = e.Fields.Field(0).Value.FirstOrDefault,
                                                                         .relEndDate = e.Fields.Field(1).Value.FirstOrDefault,
                                                                         .relReqCount = e.Fields.Field(2).Value.FirstOrDefault,
                                                                         .relUsedPlans = e.Fields.Field(3).Value.ToList
                                                                         }).ToList
                Dim i = 0
            End Using
        Catch ex As Exception

        End Try
        Console.ReadKey()

    End Sub

End Module

Public Class ALMReleases
    Friend relEndDate As String
    Friend relName As String
    Friend relReqCount As String
    Friend relUsedPlans As List(Of String)
End Class

<XmlRoot(ElementName:="Field")>
Public Class Field
    <XmlElement(ElementName:="Value")>
    Public Property Value() As List(Of String)
        Get
            Return m_Value
        End Get
        Set
            m_Value = Value
        End Set
    End Property
    Private m_Value As List(Of String)
    <XmlAttribute(AttributeName:="Name")>
    Public Property Name() As String
        Get
            Return m_Name
        End Get
        Set
            m_Name = Value
        End Set
    End Property
    Private m_Name As String
End Class

<XmlRoot(ElementName:="Fields")>
Public Class Fields
    <XmlElement(ElementName:="Field")>
    Public Property Field() As List(Of Field)
        Get
            Return m_Field
        End Get
        Set
            m_Field = Value
        End Set
    End Property
    Private m_Field As List(Of Field)
End Class

<XmlRoot(ElementName:="Entity")>
Public Class Entity
    <XmlElement(ElementName:="Fields")>
    Public Property Fields() As Fields
        Get
            Return m_Fields
        End Get
        Set
            m_Fields = Value
        End Set
    End Property
    Private m_Fields As Fields
    <XmlElement(ElementName:="RelatedEntities")>
    Public Property RelatedEntities() As String
        Get
            Return m_RelatedEntities
        End Get
        Set
            m_RelatedEntities = Value
        End Set
    End Property
    Private m_RelatedEntities As String
    <XmlAttribute(AttributeName:="Type")>
    Public Property Type() As String
        Get
            Return m_Type
        End Get
        Set
            m_Type = Value
        End Set
    End Property
    Private m_Type As String
End Class

<XmlRoot(ElementName:="Entities")>
Public Class Entities
    <XmlElement(ElementName:="Entity")>
    Public Property Entity() As List(Of Entity)
        Get
            Return m_Entity
        End Get
        Set
            m_Entity = Value
        End Set
    End Property
    Private m_Entity As List(Of Entity)
    <XmlAttribute(AttributeName:="TotalResults")>
    Public Property TotalResults() As String
        Get
            Return m_TotalResults
        End Get
        Set
            m_TotalResults = Value
        End Set
    End Property
    Private m_TotalResults As String
End Class

to use the code....

  1. Create a new VB.NET console application
  2. Copy and paste the code above, into 'Module1' file (replacing the code that was auto generated)
  3. Open file explorer and navigate to '\…\bin\Debug' folder (where the application exe is compiled too)
  4. create a new text file and rename it 'xml.xml'
  5. open the xml.xml in Notepad, paste in your XML (exactly as it is in your question) and save the file
  6. Back in Visual Studio, press F5 to run the code.....

A console window will appear displaying the results that you required

Once you have this code working, you can then see how its working and modify it to suit your specific needs.....

Upvotes: 2

Related Questions