【问题标题】:How to read xml file using VB.NET by using XElement parsing?如何通过 XElement 解析使用 VB.NET 读取 xml 文件?
【发布时间】:2016-03-31 12:00:54
【问题描述】:

我对解析 xml 很陌生。我尝试了为类似问题提供的解决方案,但我拥有的 xml 格式不同。我有一个来自外部工具的 xml 文件,如下所示。我从该工具得到这个作为网络响应。

<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>

我需要获取以下详细信息 发布名称、结束日期、请求计数、UsedPlans 等

第一个版本的示例输出为

发布名称:Release1 结束日期:2015-05-15 请求数:29 使用的计划:Plan1、Plan2

VB.NET 代码:

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

在控制台中输出为

29
10

有没有更好的方法来做到这一点?

我有以下代码来使用 C# 执行 linq 查询,它工作正常。不幸的是,我无法将其转换为 vb.net 我尝试了许多转换器,但他们没有给我正确的 vb.net 版本的查询。我不擅长 linq 来纠正它。谁能帮我转换一下代码。

工作 C# 代码:

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();

编辑:为 linq 查询添加了工作 C# 代码。有人可以将其转换为 vb.net。注意:在线转换器和其他工具无法提供有效的转换代码。

【问题讨论】:

  • 你读过documentation吗?请注意,页面底部有示例。
  • 我尝试了一些东西,请参阅编辑后的代码。但我对此并不满意。我认为这不是正确的做法。
  • 好吧,从.Descendants 调用中,您会得到XElements 的枚举值。循环遍历它们并获取您需要的值怎么样?
  • 对不起,我没听懂。你能给我一个示例代码吗?
  • 对不起,我对 VB.NET 中的 LINQ 和 XML 不太擅长。但是看看Elements()Element()Attributes() - 这应该会让你走得很远。

标签: xml vb.net linq xelement


【解决方案1】:

感谢大家的帮助。我设法为我的问题找到了解决方案。 这是有效的代码

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

【讨论】:

  • 干得好,但是,我可以看到一个小问题。您正在将 usedPlans 连接成一个字符串“Plan1Plan2”...我已经修改了我的答案,既简化了您的 LINQ,又将 usedPlans 分成了一个列表...。
  • 是的,我知道这个问题,希望我能解决这个问题。另一个问题是字段名称。如果 xml 中不存在这些字段中的任何一个,则上述代码将失败。它会给出一个例外。
  • 我修复了连接问题。查看新代码。
【解决方案2】:

尝试这样的事情......此代码将您的 XML 从文件 'xml.xml' 读取为字符串,然后将其反序列化为对象,然后您可以轻松获取所需的数据.....

编辑......新代码......(包括你的 ALMReleases 类)

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

使用代码....

  1. 创建一个新的 VB.NET 控制台应用程序
  2. 将上面的代码复制并粘贴到“Module1”文件中(替换自动生成的代码)
  3. 打开文件资源管理器并导航到“\...\bin\Debug”文件夹(应用程序 exe 也在其中编译)
  4. 创建一个新的文本文件并将其重命名为“xml.xml”
  5. 在记事本中打开 xml.xml,粘贴您的 XML(与您的问题完全相同)并保存文件
  6. 返回 Visual Studio,按 F5 运行代码.....

将出现一个控制台窗口,显示您需要的结果

一旦你的代码工作了,你就可以看到它是如何工作的,并修改它以满足你的特定需求.....

【讨论】:

  • Dim ms1 As MemoryStream = New MemoryStream(bufXML) 抛出错误。
  • Exception thrown: 'System.IO.FileNotFoundException' in mscorlib.dllException thrown: 'System.IO.FileNotFoundException' in mscorlib.dllException thrown: 'System.Xml.XmlException' in System.Xml.dllException thrown: 'System.Reflection.TargetInvocationException' in mscorlib.dllException thrown: 'System.InvalidOperationException' in System.Xml.dllException thrown: 'System.InvalidOperationException' in mscorlib.dll
  • 确保您将 XML 保存在名为“xml.xml”的文件中,并且该文件与应用程序 .exe 位于同一文件夹中(通常位于 bin\Debug文件夹)....我还需要查看实际的错误“消息”,您发布的是堆栈跟踪并调试我需要您的代码...可以通过选择“查看详细信息”找到错误消息[从您运行代码时的错误弹出窗口] 然后在树视图中展开异常,您将看到“消息”条目....
  • 正如我在问题中所说,我将 xml 作为网络响应。我没有把它保存在任何地方。我已经更改了您引用文件的位置。喜欢这个Dim releaseXML = XElement.Parse(myQueriedVal)Dim deserializedXML As EntitiesDim xmlString As String = releaseXMLDim bufXML As Byte() = ASCIIEncoding.UTF8.GetBytes(xmlString)
  • 将 'Dim xmlString As String = releaseXML' 替换为 'Dim xmlString As String = myQueriedVal'
猜你喜欢
  • 2012-02-23
  • 1970-01-01
  • 1970-01-01
  • 2013-08-30
  • 2012-09-09
  • 2011-04-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多