Lekce 7 - Čtení XML SAXem ve VB.NET
V minulém dílu našeho seriálu tutoriálů o VB.NET, Úvod do XML a zápis SAXem ve 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:

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ě, Práce s XML soubory pomocí DOM ve VB.NET, se podíváme na DOM, tedy objektový přístup k XML dokumentu.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 166x (67.87 kB)
Aplikace je včetně zdrojových kódů v jazyce VB