Válí se ti projekty v šuplíku? Dostaň je mezi lidi a získej cool tričko a body na profi IT kurzy v soutěži ITnetwork summer 2017!
Přidej si svou IT školu do profilu a najdi spolužáky zde na síti :)

7. díl - Čtení XML SAXem v VB.NET

Ostatní jazyky Visual Basic .NET Práce se soubory Čtení XML SAXem v VB.NET

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulém dílu našeho seriálu tutoriálů o VB.NET jsme si představili formát XML a ukázali si, jak pomocí SAXu vytvořit jednoduché XML. Nyní na minulý díl navážeme a napíšeme si proces opačný, tedy načtení XML souboru s uživateli a sestavení příslušné objektové struktury (listu uživatelů).

Pro úplnost si opět uvedeme náš XML soubor soubor.xml:

<?xml version="1.0" encoding="utf-8"?>
<uzivatele>
  <uzivatel vek="22">
    <jmeno>Pavel Slavík</jmeno>
    <registrovan>21.3.2000</registrovan>
  </uzivatel>
  <uzivatel vek="31">
    <jmeno>Jan Novák</jmeno>
    <registrovan>30.10.2012</registrovan>
  </uzivatel>
  <uzivatel vek="16">
    <jmeno>Tomáš Marný</jmeno>
    <registrovan>12.1.2011</registrovan>
  </uzivatel>
</uzivatele>

A naši třídu Uzivatel.vb:

Public Class Uzivatel
        Private _jmeno As String
        Public Property Jmeno As String
                Get
                        Return _jmeno
                End Get
                Private Set(ByVal value As String)
                        _jmeno = value
                End Set
        End Property

        Private _vek As Integer
        Public Property Vek As Integer
                Get
                        Return _vek
                End Get
                Set(ByVal value As Integer)
                        _vek = value
                End Set
        End Property

        Private _registrovan As DateTime
        Public Property Registrovan As DateTime
                Get
                        Return _registrovan
                End Get
                Set(ByVal value As DateTime)
                        _registrovan = value
                End Set
        End Property

        Public Sub New(jmeno As String, vek As Integer, registrovan As DateTime)
                Me.Jmeno = jmeno
                Me.Vek = vek
                Me.Registrovan = registrovan
        End Sub

        Public Overrides Function ToString() As String
                Return Me.Jmeno
        End Function
End Class

Založme si nový projekt, půjde opět o konzolovou aplikaci. Pojmenujeme ji XmlSaxCteni a do složky bin/debug nakopírujeme náš XML soubor. K projektu připojíme také třídu Uzivatel. Uživatele budeme chtít načíst do nějaké kolekce, vytvořme si tedy prázdný list uzivatele. Kód budeme kvůli jednoduchosti psát do metody Main, jak to udělat dobře objektově jsme si v této sekci již ukazovali.

Dim uzivatele As New List(Of Uzivatel)

Čtení XML přes SAX

Ke čtení XML přes SAX nám .NET framework poskytuje třídu XmlReader. Pojďme si vytvořit její instanci. Jako tomu bylo u třídy XmlWriter, i zde k tomu využijeme tovární metody Create, jejímž parametrem je název souboru. Nezapomeneme do Imports připsat System.Xml. Vše bude v bloku using, který se nám postará o uzavření souboru:

Using xr As XmlReader = XmlReader.Create("soubor.xml")

End Using

Připravíme si pomocné proměnné pro vlastnosti uživatele. Nemůžeme ukládat přímo do instance, protože vlastnosti jsou read-only. Druhou možností může být povolit modifikaci zvenčí, tím ale ztrácíme část zapouzdření. Vlastnosti naplníme výchozími hodnotami, ty se dosadí v případě, že daná hodnota nebude v XML zapsána. Budeme potřebovat někam ukládat jméno aktuálního elementu, k tomu si zadefinujeme stringovou proměnnou element. Kód píšeme pochopitelně do using bloku.

Dim jmeno As String = ""
Dim vek As Integer = 0
Dim registrovan As DateTime = DateTime.Now
Dim element As String = ""

Začneme načítat soubor. XmlReader načítá soubor řádek po řádku, odshora dolů. Na jeho instanci voláme metodu Read. Ta nám při každém zavolání načte další tzv. uzel. Uzlem může být element, případně atribut nebo textová hodnota elementu (nás bude zajímat Element, Text a EndElement), dalším typem uzlu může být např. komentář, které pro nás nyní nebudou důležité. Pokud je čtečka na konci souboru, vrátí metoda read false, v opačném případě vrací true. Postoupíme tedy k postupnému načítání všech uzlů v dokumentu pomocí while cyklu:

While xr.Read()

End While

Na instanci XmlReaderu máme několik užitečných vlastností, budeme používat NodeType, ve které je uložen typ aktuálního uzlu, na kterém se čtečka nachází. Dále použijeme vlastnosti Name a Value, ve kterých je uloženo jméno aktuálního uzlu a jeho hodnota (pokud nějakou má).

Nás budou nyní zajímat 2 typy uzlů, Element a Text. Pojďme na ně reagovat, zatím napíšeme prázdné podmínky:

If xr.NodeType = XmlNodeType.Element Then
End If

Nyní vložíme kód do první podmínky. Budeme tedy reagovat na načtení elementu. Je zde potřeba provést 2 akce.

Klíčovou akcí bude uložení názvu elementu do proměnné element. Tak budeme vzápětí schopni v druhé podmínce zjistit, kterého elementu je text, který právě čteme.

Pokaždé, když narazíme na element uzivatel, načteme atribut věk pomocí metody GetAttribute(), jejímž parametrem je název atributu. Atribut aktuálního elementu lze načíst takto jednoduše. S hodnotou to tak jednoduché není, sice existují metody ReadContentAsTyp, ale pozor, ty z nevysvětlitelného důvodu provedou Read a tak rozbijí běh while cyklu. V nezanořených XML by čtečka nefungovala správně. Nějakou dobu jsem se snažil problém vyřešit, ale řešení byla natolik krkolomná, že jsem došel k závěru ReadContentAs vůbec nepoužívat. Obsah první podmínky tedy bude vypadat takto:

If xr.NodeType = XmlNodeType.Element Then
        element = xr.Name
        If element = "uzivatel" Then
                vek = xr.GetAttribute("vek")
        End If
ElseIf xr.NodeType = XmlNodeType.Text Then
End If

Přejděme do další větve, tedy do zpracování hodnoty elementu. Zde využijeme předem uložené hodnoty názvu elementu, kterou si vložíme do Select Case. Podle elementu uložíme hodnotu do dané vlastnosti uživatele:

Select Case element
        Case "jmeno"
                jmeno = xr.Value
        Case "registrovan"
                registrovan = DateTime.Parse(xr.Value)
End Select

Již jsme velmi blízko, bystřejší si jistě všimli, že uživatele nikde nepřidáváme. Jeho přidání nastane ve chvíli načtení uzavíracího elementu uzivatel. K našim dvoum podmínkám tedy přidáme třetí:

' načítáme konec elementu
ElseIf xr.NodeType = XmlNodeType.EndElement And xr.Name = "uzivatel" Then
        uzivatele.Add(New Uzivatel(jmeno, vek, registrovan))

Máme hotovo :)

Pro jistotu přikládám kompletní kód načtení souboru:

Using xr As XmlReader = XmlReader.Create("soubor.xml")
        Dim jmeno As String = ""
        Dim vek As Integer = 0
        Dim registrovan As DateTime = DateTime.Now
        Dim element As String = ""

        While xr.Read()
                If xr.NodeType = XmlNodeType.Element Then
                        element = xr.Name
                        If element = "uzivatel" Then
                                vek = xr.GetAttribute("vek")
                        End If
                ElseIf xr.NodeType = XmlNodeType.Text Then
                        Select Case element
                                Case "jmeno"
                                        jmeno = xr.Value
                                Case "registrovan"
                                        registrovan = DateTime.Parse(xr.Value)
                        End Select
                ElseIf xr.NodeType = XmlNodeType.EndElement And xr.Name = "uzivatel" Then
                        uzivatele.Add(New Uzivatel(jmeno, vek, registrovan))
                End If
        End While
End Using

Zbývá uživatele vypsat, abychom věděli, že jsme je načetli správně. Upravíme si metodu ToString() ve třídě Uzivatel tak, aby vypisovala všechny hodnoty:

Public Overrides Function ToString() As String
        Return String.Format("{0}, {1}, {2}", Jmeno, Vek, Registrovan.ToShortDateString())
End Function

Uživatele jednoduše vypíšeme:

' výpis načtených objektů
For Each u As Uzivatel In uzivatele
        Console.WriteLine(u)
Next
Console.ReadKey()

a výsledek:

Výsledek načtení objektů z XML SAXem v Visual Basic .NET

Pokud se vám načítání příliš nelíbilo, dám vám za pravdu. Zatímco generování nového XML souboru je SAXem velmi jednoduché a přirozené, načítání je opravdu krkolomné. Příště se podíváme na DOM, tedy objektový přístup k XML dokumentu.


 

Stáhnout

Staženo 151x (67.87 kB)
Aplikace je včetně zdrojových kódů v jazyce VB

 

 

Článek pro vás napsal Michal Žůrek (misaz)
Avatar
Jak se ti líbí článek?
2 hlasů
Autor se věnuje tvorbě aplikací pro počítače, mobilní telefony, mikroprocesory a tvorbě webových stránek a webových aplikací. Nejraději programuje ve Visual Basicu a TypeScript. Ovládá HTML, CSS, JavaScript, TypeScript, C# a Visual Basic.
Miniatura
Předchozí článek
Úvod do XML a zápis SAXem
Miniatura
Všechny články v sekci
Práce se soubory v Visual Basic .NET
Aktivity (2)

 

 

Komentáře

Avatar
koncelikj
Člen
Avatar
koncelikj:10.5.2015 21:34

Hmm. A jak zachytit chybu, že soubor neexistuje? Popis na MSDN je na mě moc vědecký.

 
Odpovědět 10.5.2015 21:34
Avatar
Odpovídá na koncelikj
Michal Žůrek (misaz):10.5.2015 21:54

toto se neošetřuje jako chyba ale ošetřuje se to ještě před načítáním souboru podmínkou.

If Not System.IO.File.Exists(cestaKSouboru) Then
    ' soubor neexistuje
End If
Odpovědět 10.5.2015 21:54
Nesnáším {}, proto se jim vyhýbám.
Avatar
Josef Jeništa:17. března 1:38

Na konci souboru jsme měl posledního člena 2x. Kód jsem trochu upravil. Po přidání uživatele jsem element vymazal (element = "") a teď to chodí, jak má. Omlouvám se, nevím jak se tady upravuje zdroják, aby to nebylo vše na levé straně.

Dim uzivatele As New List(Of Uzivatel)
Dim poc As Integer = 0
Using xr As XmlReader = XmlReader.Cre­ate("soubor.xml")
Dim jmeno As String = ""
Dim vek As Integer = 0
Dim registrovan As DateTime = DateTime.Now
Dim element As String = ""

While xr.Read()
If xr.NodeType = XmlNodeType.Element Then
element = xr.Name
If element = "uzivatel" Then
vek = xr.GetAttribu­te("vek")
ElseIf element = "uzivatele" Then
poc += 1
End If

ElseIf xr.NodeType = XmlNodeType.Text Then
Select Case element
Case "jmeno"
jmeno = xr.Value
Case "registrovan"
registrovan = DateTime.Parse(xr­.Value)
End Select

ElseIf (xr.NodeType = XmlNodeType.En­dElement) And (element = "registrovan") Then
If poc <> 2 Then
uzivatele.Add(New Uzivatel(jmeno, vek, registrovan))
element = ""
End If
End If
End While
End Using

Odpovědět 17. března 1:38
Kolik jazyků umíš, tolikrát jsi programátorem.
Avatar
Josef Jeništa:17. března 1:41

Zapomněl jsem ze zdrojáku vyhodit načítání do poc (poc += 1) a dotaz na poc <> 2. Dal jsem si to tam kvůli ladění.

Odpovědět 17. března 1:41
Kolik jazyků umíš, tolikrát jsi programátorem.
Avatar
Odpovídá na Josef Jeništa
Michal Štěpánek:17. března 7:36

... nevím jak se tady upravuje zdroják, aby to nebylo vše na levé straně.

Zdroják se vkládá za pomoci tagů "code" - je to to druhé tlačítko zleva, hned vedle smajlíka...

Odpovědět 17. března 7:36
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Josef Jeništa:17. března 16:46

Takhle je to definitivně.

Dim uzivatele As New List(Of Uzivatel)
    Dim poc As Integer = 0
    Using xr As XmlReader = XmlReader.Create("soubor.xml")
      Dim jmeno As String = ""
      Dim vek As Integer = 0
      Dim registrovan As DateTime = DateTime.Now
      Dim element As String = ""

      While xr.Read()
        If xr.NodeType.ToString <> "Whitespace" Then
          If xr.NodeType = XmlNodeType.Element Then
            element = xr.Name
            If element = "uzivatel" Then
              vek = xr.GetAttribute("vek")
            End If

          ElseIf xr.NodeType = XmlNodeType.Text Then
            Select Case element
              Case "jmeno"
                jmeno = xr.Value
              Case "registrovan"
                registrovan = DateTime.Parse(xr.Value)
            End Select

          ElseIf (xr.NodeType = XmlNodeType.EndElement) And (element = "registrovan") Then
            uzivatele.Add(New Uzivatel(jmeno, vek, registrovan))
            element = ""
          End If
        End If
      End While
    End Using

    For Each u As Uzivatel In uzivatele
      Console.WriteLine(u)
    Next
    Console.ReadKey()
Odpovědět 17. března 16:46
Kolik jazyků umíš, tolikrát jsi programátorem.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 6 zpráv z 6.