Search code examples
xmlvb.netlinqxelement

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 r@.FirstAttribute = "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 r@.FirstAttribute = "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.


Solution

  • 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