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()
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:
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" ?>
.
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<>
.