Usar o XmlReader para obter um nome e um valor de um ficheiro XML em VB.NET

estou a usar o seguinte ficheiro XML e código VB. Eu quero ser capaz de obter o nome do projeto que está na tag do projeto e também o valor do que está entre as tags. Obter o valor "Nome" funciona bem, mas eu não consigo descobrir como ler qualquer um dos sub-itens. Quero preencher uma lista ou, possivelmente, um DataGrid com 2 colunas de dados:

project   |  description
------------------------
file001   |  ABC Project
file002   |  DEF Project

o ficheiro XML:

<?xml version="1.0"?>
<menu>
    <header>
        <listname>Files list</listname>
        <lastlistupdate>02/08/2018</lastlistupdate>
    </header>
    <project name="file001" index="true" image="'">
        <description>ABC Project</description>
        <month>January</month>
    </project>
    <project name="file002" index="true" image="'">
        <description>DEF Project</description>
        <month>February</month>
    </project>
        <project name="file003" index="true" image="'">
        <description>Not really important project</description>
        <month>March</month>
    </project>
</menu>

o que é estranho neste código é que o teste" se " passa, o que significa xr.Name deve ser "projecto". Contudo, a minha linha de teste log (XR.Name.ToString) mostra .o nome é "Descrição". Não percebo como.

Dim xmlfile As String = ""
Dim filename As String = ""
Dim title As String = ""
ListViewFiles.Items.Clear()
xmlfile = Application.StartupPath & "\projectlist.xml"

Dim xr As XmlReader = XmlReader.Create(xmlfile)
While xr.Read()
    If xr.NodeType = XmlNodeType.Element AndAlso xr.Name = "project" Then
        filename = xr.GetAttribute(0) 'Gets "name" correctly (ex: file001)
        title = Trim(xr.ReadString()) '<<<<-- will not work
        WriteLog("xr.name: " & xr.Name.ToString) <-shows the tag "description"???
        ListViewFiles.Items.Add(New ListViewItem(New String() {filename, title}))
    End If
End While
xr.Close()
Author: Marco Sadowski, 2018-06-28

2 answers

Você pode obter VS para fazer uma classe que corresponde ao arquivo XML, e então você pode usar essa classe para obter os dados, às vezes muito simplesmente.

Coloquei uma DataGridView num formulário e usei este código:

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

Public Class Form1

    Class Project
        Property Filename As String
        Property Description As String
    End Class

    Private Sub LoadData()
        Dim xmlFile = "C:\temp\projectlist.xml"
        Dim projectsData As Projects.menu

        Dim serializer = New XmlSerializer(GetType(Projects.menu))
        Using fs As New FileStream(xmlFile, FileMode.Open, FileAccess.Read, FileShare.Read)
            Using rdr = XmlReader.Create(fs)
                projectsData = DirectCast(serializer.Deserialize(rdr), Projects.menu)
            End Using
        End Using

        Dim projectsList = projectsData.project.Select(Function(p) New Project With {.Filename = p.name, .Description = p.description}).ToList()

        DataGridView1.DataSource = projectsList

    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        LoadData()
        DataGridView1.AutoResizeColumn(0)
        DataGridView1.AutoResizeColumn(1)

    End Sub

End Class

Para obter isto:

enter image description here

Por favor, ajuste os nomes das classes e propriedades conforme necessário.

Claro, você precisa da classe para ir com o arquivo XML. Para fazer isso, copie os dados XML e, em seguida, no Visual Studio escolha "Editar" - > " Colar Especial"-> "colar XML como classes". Escolhi colá-lo numa classe chamada "Projectos" e consegui isto:

Public Class Projects

    <System.SerializableAttribute(),
 System.ComponentModel.DesignerCategoryAttribute("code"),
 System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True),
 System.Xml.Serialization.XmlRootAttribute([Namespace]:="", IsNullable:=False)>
    Partial Public Class menu

        Private headerField As menuHeader

        Private projectField() As menuProject

        '''<remarks/>
        Public Property header() As menuHeader
            Get
                Return Me.headerField
            End Get
            Set
                Me.headerField = Value
            End Set
        End Property

        '''<remarks/>
        <System.Xml.Serialization.XmlElementAttribute("project")>
        Public Property project() As menuProject()
            Get
                Return Me.projectField
            End Get
            Set
                Me.projectField = Value
            End Set
        End Property
    End Class

    '''<remarks/>
    <System.SerializableAttribute(),
System.ComponentModel.DesignerCategoryAttribute("code"),
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)>
    Partial Public Class menuHeader

        Private listnameField As String

        Private lastlistupdateField As String

        '''<remarks/>
        Public Property listname() As String
            Get
                Return Me.listnameField
            End Get
            Set
                Me.listnameField = Value
            End Set
        End Property

        '''<remarks/>
        Public Property lastlistupdate() As String
            Get
                Return Me.lastlistupdateField
            End Get
            Set
                Me.lastlistupdateField = Value
            End Set
        End Property
    End Class

    '''<remarks/>
    <System.SerializableAttribute(),
System.ComponentModel.DesignerCategoryAttribute("code"),
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)>
    Partial Public Class menuProject

        Private descriptionField As String

        Private monthField As String

        Private nameField As String

        Private indexField As Boolean

        Private imageField As String

        '''<remarks/>
        Public Property description() As String
            Get
                Return Me.descriptionField
            End Get
            Set
                Me.descriptionField = Value
            End Set
        End Property

        '''<remarks/>
        Public Property month() As String
            Get
                Return Me.monthField
            End Get
            Set
                Me.monthField = Value
            End Set
        End Property

        '''<remarks/>
        <System.Xml.Serialization.XmlAttributeAttribute()>
        Public Property name() As String
            Get
                Return Me.nameField
            End Get
            Set
                Me.nameField = Value
            End Set
        End Property

        '''<remarks/>
        <System.Xml.Serialization.XmlAttributeAttribute()>
        Public Property index() As Boolean
            Get
                Return Me.indexField
            End Get
            Set
                Me.indexField = Value
            End Set
        End Property

        '''<remarks/>
        <System.Xml.Serialization.XmlAttributeAttribute()>
        Public Property image() As String
            Get
                Return Me.imageField
            End Get
            Set
                Me.imageField = Value
            End Set
        End Property
    End Class


End Class

P. S. pus a codificação na declaração do ficheiro XML: <?xml version="1.0" encoding="utf-8" ?>.

 1
Author: Andrew Morton, 2018-06-28 11:09:39

Escrevi este código para o seu XML obter o nome do ficheiro(projecto/nome) e o título (descrição). Espero que compreendas.

Dim filename As String = ""
Dim title As String = ""
Dim XMLReader As XmlReader = XMLReader.Create(xmlfile)
With XMLReader
    'As long as the reader hasnt come to the end of the document, this loop is executed'
    Do While .Read
    If .IsStartElement() Then
        Select Case .Name
        Case "project"
            filename = .GetAttribute(0)
            Console.WriteLine(filename)
        Case "description"
            title = .ReadElementString
            Console.WriteLine(title)
            Console.WriteLine("Found: " & filename & " - " & title) 
            'you can place your "final" code here.'
            Exit Select
        Case Else
            .Read()
            'continue reading if nothing is special'
        End Select
    End If
    Loop
    .Close() 'close the reader. All done!'
End With

Pode testar o código aqui: https://dotnetfiddle.net/3CDd6Q

No seu código original estavam alguns erros como o que usou xr.Name para obter o elemento da marca de descrição, mas com {[2] } só consegue o nome da marca <name>. Tem de usar .ReadElementString Se quiser obter o elemento entre as marcas <>element<>.

 1
Author: Marco Sadowski, 2018-06-28 09:04:46