Grafikus C# – Windows Forms tanfolyam › 10.7 lecke

Windows Forms · 10.7 lecke · XML

XML alapjai

Az XML (eXtensible Markup Language) a JSON „idősebb testvére”: címkékkel (elemekkel) és attribútumokkal leírt, fa szerkezetű szöveges formátum. A weben a JSON vette át a főszerepet, az XML viszont mindenütt jelen van: az Office dokumentumok (.docx, .xlsx), az SVG képek, a .csproj projektfájlok, a konfigurációs fájlok, a hírcsatornák (RSS) és sok oktatási rendszer cseréje. Ebben a leckében a System.Xml.Linq névtér XDocument és XElement osztályaival létrehozol, mentesz, betöltesz és lekérdezel XML-t, megismered az XmlSerializer lehetőségét, az XML hibáinak kezelését, és összeveted a JSON-nal, hogy tudj választani.

  • kb. 100 perc
  • közepes–haladó szint
  • XML
Diák C# programozást gyakorol egy tanulósarokban

A lecke végére

  • olvasod az XML szerkezetét (gyökérelem, elem, attribútum, szöveg, megjegyzés);
  • XML-t építesz XElement és XAttribute objektumokkal (funkcionális építés), mentesz és betöltesz (XDocument);
  • lekérdezel LINQ to XML-lel (Elements, Descendants, Attribute, Where, OrderBy);
  • biztonságosan olvasol értéket ((int?), (string), ?.Value), és kezeled a hiányzó elemeket;
  • ismered az XmlSerializer használatát és korlátait;
  • kezeled az XmlException hibát, és tudod, mikor jobb az XML, mikor a JSON.

Mielőtt elkezded

Ehhez a leckéhez a 10.1–10.3 lecke (fájlkezelés, kódolás), a 8.4 lecke (listák) és a 4.2 lecke (LINQ alapok, ha korábban volt) szükséges; a lecke a szükséges LINQ elemeket magyarázza.

10.6 JSON →

Az XML felépítése

receptek.xmlXML
<?xml version="1.0" encoding="utf-8"?>
<receptkonyv verzio="1">
<!-- a konyv receptjei -->
<recept id="1" nehezseg="konnyu">
<nev>Palacsinta</nev>
<ido perc="30" />
<hozzavalok>
<hozzavalo mennyiseg="250" egyseg="g">liszt</hozzavalo>
<hozzavalo mennyiseg="3" egyseg="db">tojás</hozzavalo>
</hozzavalok>
<leiras>Keverd össze, & süsd ki.</leiras>
</recept>
</receptkonyv>
ElemNyitó és záró címke közötti egység: <nev>Palacsinta</nev>. Az elemek egymásba ágyazhatók: fa keletkezik. Az üres elem rövid alakja: <ido />.
AttribútumAz elem nyitó címkéjében álló név="érték" pár (id="1"): egyszerű tulajdonságokra jó. A bonyolultabb vagy többször előforduló adatnak elem való.
GyökérelemMinden XML dokumentumnak pontosan egy gyökéreleme van (receptkonyv), amelyben minden más foglal helyet.
Különleges karakterekA <, & és az idézőjel az XML-ben különleges: <, &, " alakban írandók. A .NET ezt automatikusan elvégzi, ha az XElement objektumot használod (nem kézzel fűzöl szöveget).

Jósolj!

Kézzel összefűzöl XML-t: "<nev>" + nev + "</nev>", és a felhasználó a nevet Tom & Jerry módon adja meg. Mi történik a fájl beolvasásakor?

Jóslat ellenőrzése

Az & jel érvénytelen XML-t eredményez: a beolvasás XmlException kivételt dob (hibás entitás-hivatkozás). Az XElement("nev", nev) a szöveget helyesen kódolja (&), ezért soha ne fűzz XML-t kézzel.

XDocument építése, mentése és betöltése

Form1.cs (using System.Xml.Linq; using System.Linq;)C#
// funkcionális építés: a gyerek elemek és attribútumok a konstruktor paraméterei
XDocument dok = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("receptkonyv",
new XAttribute("verzio", 1),
recept.Select(r =>
new XElement("recept",
new XAttribute("id", r.Id),
new XAttribute("nehezseg", r.Nehezseg),
new XElement("nev", r.Nev),
new XElement("ido", new XAttribute("perc", r.Perc)),
new XElement("hozzavalok",
r.Hozzavalok.Select(h => new XElement("hozzavalo", new XAttribute("mennyiseg", h.Mennyiseg), new XAttribute("egyseg", h.Egyseg), h.Nev))),
new XElement("leiras", r.Leiras)))));

dok.Save(ut); // UTF-8, a deklarációnak megfelelően; a kimenet tagolt (olvasható)

// betöltés
XDocument beolvasott = XDocument.Load(ut);
XElement gyoker = beolvasott.Root;
Funkcionális építésAz XElement konstruktora tetszőleges számú tartalmat fogad: attribútumot, gyerek elemet, szöveget, vagy felsorolást (például Select eredményét), amelyet automatikusan elemekre bont. Egyetlen kifejezéssel építhető az egész fa.
Attribútum értékeAz XAttribute("id", 1) a számot szöveggé alakítja, kultúra-függetlenül (a tizedes pont jelent). Beolvasáskor ugyanezt a konverziót használd ((double)attr).
Save és LoadA Save(ut) az XML-t UTF-8-ban (a deklaráció szerint), tagolva írja ki; a XDocument.Load(ut) beolvassa. Mindkettő kivételt dobhat (fájl-, XML-hiba): try–catch.
Szöveg → XMLXML szövegből: XDocument.Parse(szoveg); XML-ből szöveg: dok.ToString() (a deklaráció nélkül).

Jósolj!

A new XElement("ido", new XAttribute("perc", 30)) hogyan kerül az XML-be?

Jóslat ellenőrzése

Üres elemként: <ido perc="30" />. Szöveges tartalom nincs, csak attribútum.

Lekérdezés LINQ to XML-lel

Form1.csC#
XElement gyoker = XDocument.Load(ut).Root;

// a gyökér közvetlen gyerekei: Elements; minden szinten: Descendants
foreach (XElement r in gyoker.Elements("recept"))
{
string nev = (string)r.Element("nev"); // az elem szövege (null, ha nincs ilyen elem)
int id = (int)r.Attribute("id"); // attribútum számként (FormatException, ha nem szám!)
int? perc = (int?)r.Element("ido")?.Attribute("perc"); // nullázható: hiányzó elem vagy attribútum → null
string nehezseg = (string)r.Attribute("nehezseg") ?? "ismeretlen"; // alapérték
}

// szűrés és rendezés: könnyű receptek időrendben
var konnyuek = gyoker.Elements("recept")
.Where(r => (string)r.Attribute("nehezseg") == "konnyu")
.OrderBy(r => (int?)r.Element("ido")?.Attribute("perc") ?? int.MaxValue)
.Select(r => (string)r.Element("nev"))
.ToList();

// keresés hozzávaló szerint: minden szinten (Descendants)
var tojasosak = gyoker.Descendants("hozzavalo")
.Where(h => ((string)h).IndexOf("tojás", StringComparison.CurrentCultureIgnoreCase) >= 0)
.Select(h => (string)h.Parent.Parent.Element("nev")) // hozzávaló → hozzavalok → recept → nev
.Distinct();

// módosítás: érték és attribútum átírása, elem törlése, új elem hozzáadása
XElement egy = gyoker.Elements("recept").First(r => (int)r.Attribute("id") == 1);

egy.SetElementValue("nev", "Túrós palacsinta");
egy.SetAttributeValue("nehezseg", "kozepes");
egy.Remove(); // törlés a fából
gyoker.Add(new XElement("recept", new XAttribute("id", 2)));
Elements és DescendantsAz Elements("recept") csak a közvetlen gyerekeket adja, a Descendants("hozzavalo") minden mélységben keres. Az Element("nev") az első egyező gyereket adja (vagy null).
Konverzió castolássalAz (string)elem, (int)attribútum, (double?)elem az érték olvasása és átalakítása egyben. A null elemre az (string) null értéket ad (kivétel nélkül); az (int) null-ra ArgumentNullException, hibás szövegre FormatException: a nullázható (int?) a hiányt kezeli, a hibás szöveget nem.
?. operátorAz r.Element("ido")?.Attribute("perc") a hiányzó ido elemnél null-t ad, nem NullReferenceException kivételt (null-feltételes operátor).
Módosítás a memóriábanA SetElementValue, SetAttributeValue, Add, Remove a memóriában lévő fát változtatja; a fájlba a Save írja. Bejárás közben ne töröld az elemeket (.ToList() másolat kell).

Jósolj!

A (int)r.Attribute("id") olvasásnál egy kézzel szerkesztett fájlban az id="egy" szerepel. Mi történik?

Jóslat ellenőrzése

FormatException: az „egy” nem szám. A kézzel szerkesztett vagy külső forrásból érkező XML-nél a konverziókat védd (int.TryParse((string)attr, out id)), és a hibás elemet jelentsd.

XmlSerializer, hibák és az XML–JSON választás

Form1.cs (using System.Xml.Serialization; using System.Xml;)C#
// az osztály a JSON-hoz hasonlóan automatikusan XML-be alakítható
[XmlRoot("receptkonyv")]
public class Konyv
{
[XmlAttribute("verzio")]
public int Verzio { get; set; } = 1;

[XmlElement("recept")]
public List<Recept> Receptek { get; set; } = new List<Recept>(); // nyilvános, paraméter nélküli konstruktor kell!
}

XmlSerializer sz = new XmlSerializer(typeof(Konyv));

using (StreamWriter iro = new StreamWriter(ut, false, new UTF8Encoding(false))) { sz.Serialize(iro, konyv); }

try
{
using (StreamReader olvaso = new StreamReader(ut)) { konyv = (Konyv)sz.Deserialize(olvaso); }
}
catch (InvalidOperationException ex) // az XmlSerializer a hibát InvalidOperationException-be csomagolja (a belső kivétel az XmlException)
{
MessageBox.Show("Hibás XML: " + (ex.InnerException != null ? ex.InnerException.Message : ex.Message));
}

// XDocument.Load hibája: XmlException (sor- és pozíciószámmal)
try { var d = XDocument.Load(ut); }
catch (XmlException ex) { MessageBox.Show("Hibás XML (sor " + ex.LineNumber + ", pozíció " + ex.LinePosition + "): " + ex.Message); }
XMLJSON
OlvashatóságBőbeszédű (záró címkék), de önleíró.Tömörebb, könnyebben olvasható.
Attribútum, megjegyzésVan (attribútum, <!-- -->).Nincs megjegyzés, nincs attribútum.
TípusokMinden szöveg (a típust a program tudja).Szám, logikai, null saját típus.
Séma, névtérSzabványos séma (XSD), névterek, XPath, XSLT.Egyszerűbb; séma ritkább.
Jellemző használatDokumentumok, konfiguráció, régi/ipari rendszerek, SVG, RSS.Webes API-k, modern alkalmazásadat.
XmlSerializer vagy XDocument?Az XmlSerializer kevés kóddal alakít osztályt XML-é, de szigorú (nyilvános tulajdonságok, paraméter nélküli konstruktor), és a kimenet formáját attribútumokkal (XmlAttribute) irányítod. Az XDocument kézi irányítást és rugalmas lekérdezést ad: kisebb, vagy külső XML-hez jobb.
XmlExceptionA hibás XML XmlException kivételt dob a hiba sorával és pozíciójával. Mint a JSON-nál: jelezd, ne írd felül az eredeti fájlt.
XXE biztonságKülső, nem megbízható XML beolvasásakor a külső entitások (DTD) kockázatot jelenthetnek. A XDocument.Load és az XmlReader újabb .NET-ben alapból biztonságos beállításokat használ; idegen forrásnál ne kapcsold be a DTD feldolgozást.
NévterekSzabványos formátumoknál (SVG, Office) az elemnevek névtérben vannak: XNamespace ns = "..."; és ns + "elemnev". Ha a keresés „nem talál semmit”, gyakran a névtér hiányzik.

Jósolj!

Egy SVG fájlt olvasol XDocument-tal, és doc.Descendants("rect") hívással keresed a téglalapokat, de nem talál egyet sem, pedig a fájlban vannak. Mi az oka?

Jóslat ellenőrzése

Az SVG elemei névtérben vannak (http://www.w3.org/2000/svg): a névtér nélküli "rect" név nem egyezik. Helyes: XNamespace ns = "http://www.w3.org/2000/svg"; doc.Descendants(ns + "rect").

📷 Képernyőkép helye

Mit tegyél ide: a receptkönyv: a receptlista, a hozzávalók, a keresés és az XML szöveges nézete.Javasolt fájlnév: winforms-10-7-receptkonyv.webp · Alt szöveg: A receptkönyv program XML nézettel

Hibakeresés: te vagy a hibadetektív

Mi a baj, és hogyan javítod?

Gondold végig az okot, és csak utána nyisd le a megoldást.

1. XmlException a betöltéskor: „invalid character”

string xml = "<nev>" + nev + "</nev>";   // kézi fűzés
Hiba és javítás

A &, < karakterek elrontják a szöveget. Használj XElement objektumot: new XElement("nev", nev), amely helyesen kódol.

2. NullReferenceException a lekérdezésnél

int perc = (int)r.Element("ido").Attribute("perc");   // az ido elem hiányzik
Hiba és javítás

Az Element(...) null-t ad, ha nincs ilyen elem. Használd a ?. operátort és a nullázható castot: (int?)r.Element("ido")?.Attribute("perc") ?? 0.

3. A keresés nem talál semmit

A Descendants("rect") üres.

Ok és javítás

Az elemek névtérben vannak. Használj XNamespace értéket (ns + "rect"); a gyökérelem xmlns attribútuma mutatja a névteret.

4. InvalidOperationException törlés közben

foreach (XElement r in gyoker.Elements("recept")) { if (...) { r.Remove(); } }   // bejárás közben törlés
Hiba és javítás

Bejárás közben a fa nem módosítható megbízhatóan. Készíts másolatot: foreach (var r in gyoker.Elements("recept").ToList()) vagy .Where(...).Remove().

5. Az ékezetek hibásak a fájlban

Szövegszerkesztőben az ő és ű rossz.

Ok és javítás

A fájl kódolása és a deklaráció (encoding="utf-8") eltér (például kézzel írt fájl Windows-1250 kódolással). A XDocument.Save az UTF-8-at helyesen kezeli; kézzel szerkesztve mentsd UTF-8-ban (10.3 lecke).

6. Az XmlSerializer nem tud létrehozni egy osztályt

public class Recept { public Recept(string nev) { ... } }   // nincs paraméter nélküli konstruktor
Hiba és javítás

Az XmlSerializer nyilvános, paraméter nélküli konstruktort igényel. Add hozzá (public Recept() { }).

Mini projekt: receptkönyv XML-ben

Készíts receptkönyvet, amelynek adatai XML-fájlban tárolódnak:

  1. Modell: Recept (Id, Nev, Nehezseg, Perc, Hozzavalok: List<Hozzavalo> (Nev, Mennyiseg, Egyseg), Leiras); a lista és az XDocument közötti két metódus (XmlbolBetolt, XmlbeMent).
  2. Felület: lstReceptek (név szerint), txtKereses (név vagy hozzávaló szerint), cmbNehezseg (szűrő: mind, könnyű, közepes, nehéz); szerkesztő: txtNev, cmbNehezseg2, nudPerc, dgvHozzavalok (DataGridView: Név, Mennyiség, Egység), txtLeiras; gombok: Új, Mentés, Törlés; fül: txtXml (az aktuális recept XML-je, csak olvasható).
  3. Betöltés: XDocument.Load; a hibás elem (hibás szám, hiányzó név) a hibalistára kerül, a többi recept betöltődik; hibás XML (XmlException) esetén sor- és pozícióüzenet, a fájl érintetlen.
  4. Mentés: ideiglenes fájlba, majd csere (10.9 lecke: File.Replace biztonsági másolattal); az XML tagolt és UTF-8.
  5. Keresés: LINQ: a név vagy bármelyik hozzávaló tartalmazza a szöveget (ékezetfüggetlenül); a találatok száma az állapotsorban; hozzávaló szerinti keresés a Descendants módszerrel.
  6. Szerkesztés: egy recept módosítása közvetlenül az XElement-en (SetElementValue, SetAttributeValue) vagy a modell újraépítésével; törlés megerősítéssel; az új recept Id értéke a legnagyobb meglévő + 1.
  7. XML-nézet: a kijelölt recept ToString() alakja (tagolva) a szövegmezőben; a kézi szerkesztés nem engedélyezett (csak olvasható).
  8. Export: a kijelölt recept önálló XML-fájlba; az összes recept HTML táblázatba (a System.Net.WebUtility.HtmlEncode a speciális karakterekre) a nyomtatáshoz.
  9. Teszteld: Tom & Jerry fánk név, ékezetes hozzávalók, hiányzó elemek (ido nélküli recept), hibás szám az attribútumban, kézzel elrontott (lezáratlan) XML, üres fájl, 500 recept, a kereső ékezetek nélkül (tojas → tojás).
Megoldás megnyitása (próbáld ki előbb önállóan!)

A központi rész az XElement → Recept konverzió (hibatűrő) és a Recept → XElement építés.

Tarolo.cs (using System.Xml; using System.Xml.Linq; using System.Linq; using System.IO; using System.Collections.Generic; using System.Globalization;)C#
public class Hozzavalo
{
public string Nev { get; set; } = "";
public double Mennyiseg { get; set; }
public string Egyseg { get; set; } = "";
}

public class Recept
{
public int Id { get; set; }
public string Nev { get; set; } = "";
public string Nehezseg { get; set; } = "konnyu";
public int Perc { get; set; }
public List<Hozzavalo> Hozzavalok { get; set; } = new List<Hozzavalo>();
public string Leiras { get; set; } = "";
}

public static class ReceptTarolo
{
// Recept → XElement (a speciális karaktereket az XElement kezeli)
public static XElement Elemme(Recept r)
{
return new XElement("recept",
new XAttribute("id", r.Id),
new XAttribute("nehezseg", r.Nehezseg),
new XElement("nev", r.Nev),
new XElement("ido", new XAttribute("perc", r.Perc)),
new XElement("hozzavalok", r.Hozzavalok.Select(h => new XElement("hozzavalo", new XAttribute("mennyiseg", h.Mennyiseg.ToString(CultureInfo.InvariantCulture)), new XAttribute("egyseg", h.Egyseg), h.Nev))),
new XElement("leiras", r.Leiras));
}

// XElement → Recept: hibatűrő; hibánál kivétel a sorszámmal együtt
public static Recept Receptte(XElement e)
{
int id;
string nev = ((string)e.Element("nev") ?? "").Trim();

if (nev.Length == 0) { throw new FormatException("hiányzó név"); }
if (!int.TryParse((string)e.Attribute("id"), out id)) { throw new FormatException("hibás azonosító: '" + (string)e.Attribute("id") + "'"); }

Recept r = new Recept { Id = id, Nev = nev, Nehezseg = (string)e.Attribute("nehezseg") ?? "konnyu", Leiras = (string)e.Element("leiras") ?? "" };

int perc;
string percSz = (string)e.Element("ido")?.Attribute("perc");

r.Perc = percSz != null && int.TryParse(percSz, out perc) && perc >= 0 ? perc : 0;

foreach (XElement h in e.Element("hozzavalok")?.Elements("hozzavalo") ?? Enumerable.Empty<XElement>())
{
double menny;

double.TryParse((string)h.Attribute("mennyiseg"), NumberStyles.Float, CultureInfo.InvariantCulture, out menny);

r.Hozzavalok.Add(new Hozzavalo { Nev = h.Value.Trim(), Mennyiseg = menny, Egyseg = (string)h.Attribute("egyseg") ?? "" });
}

return r;
}

public static List<Recept> Betolt(string ut, List<string> hibak)
{
List<Recept> lista = new List<Recept>();

if (!File.Exists(ut)) { return lista; }

XDocument dok = XDocument.Load(ut); // XmlException a hibás XML-re (a hívó kezeli)
int sorszam = 0;

foreach (XElement e in dok.Root.Elements("recept"))
{
sorszam++;

try { lista.Add(Receptte(e)); }
catch (FormatException ex) { hibak.Add(sorszam + ". recept: " + ex.Message); }
}

return lista;
}

public static void Ment(string ut, List<Recept> lista)
{
XDocument dok = new XDocument(new XDeclaration("1.0", "utf-8", null), new XElement("receptkonyv", new XAttribute("verzio", 1), lista.Select(Elemme)));
string ideiglenes = ut + ".tmp";

dok.Save(ideiglenes);

if (File.Exists(ut)) { File.Replace(ideiglenes, ut, ut + ".bak"); } else { File.Move(ideiglenes, ut); }
}

// keresés: név vagy hozzávaló (ékezetfüggetlenül)
public static IEnumerable<Recept> Keres(IEnumerable<Recept> lista, string szo, string nehezseg)
{
string kulcs = Egyseges(szo);

return lista.Where(r => (nehezseg == null || r.Nehezseg == nehezseg) && (kulcs.Length == 0 || Egyseges(r.Nev).Contains(kulcs) || r.Hozzavalok.Any(h => Egyseges(h.Nev).Contains(kulcs)))).OrderBy(r => r.Nev, StringComparer.CurrentCultureIgnoreCase);
}

private static string Egyseges(string s)
{
string bontott = s.Trim().ToLowerInvariant().Normalize(System.Text.NormalizationForm.FormD);

return new string(bontott.Where(c => CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark).ToArray());
}
}

// Form1.cs: a betöltés hibakezelése
private void Betolt()
{
List<string> hibak = new List<string>();

try { receptek = ReceptTarolo.Betolt(utvonal, hibak); }
catch (XmlException ex)
{
MessageBox.Show(this, "Hibás XML (sor " + ex.LineNumber + ", pozíció " + ex.LinePosition + "): " + ex.Message + Environment.NewLine + "A fájl nem változott.", "Betöltés", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}

lstHibak.Items.Clear();
foreach (string h in hibak) { lstHibak.Items.Add(h); }
}
📷 Képernyőkép helye

Mit tegyél ide: a kész receptkönyv a keresővel és az XML nézettel.Javasolt fájlnév: winforms-10-7-kesz.webp · Alt szöveg: A kész receptkönyv

Három önálló gyakorlófeladat

Egyszerre csak egyet csinálj: tervezd meg, írd meg, futtasd, ellenőrizd, és csak utána nyisd ki a megoldást.

1. Összes hozzávaló listája

A receptkönyv összes hozzávalóját add ki egyszer, betűrendben. Mit használsz?

Egy lehetséges megoldás

Descendants("hozzavalo"), Select, Distinct (kis- és nagybetű független összehasonlítóval), OrderBy.

Form1.csC#
var osszes = gyoker.Descendants("hozzavalo").Select(h => h.Value.Trim()).Distinct(StringComparer.CurrentCultureIgnoreCase).OrderBy(s => s, StringComparer.CurrentCultureIgnoreCase).ToList();

2. Átlagos elkészítési idő

Számold ki a receptek átlagos idejét, a hiányzó idejűeket kihagyva.

Egy lehetséges megoldás

Nullázható értékek ((int?)), Where(x => x != null), Average; üres sorozatnál az Average kivételt dob: DefaultIfEmpty(0) vagy Any() ellenőrzés.

3. XML → CSV

Alakítsd a receptek listáját CSV-vé (név; idő; hozzávalók száma). Mire kell figyelned?

Egy lehetséges megoldás

A 10.5 lecke Csv.Sor metódusával írj (idézés, képletvédelem); a szám kultúrát adj meg; a kódolás UTF-8 BOM-mal az Excelhez.

Gyakorlótár: 6 további feladat

Három szinten gyakorolhatsz: alap, közepes és kihívás. Csak a próbálkozás után nyisd le a megoldást.

Alap szint

1. Elem vagy attribútum?

Az azonosító (id) és a leírás (hosszú szöveg): melyik legyen attribútum, melyik elem?

Megoldás megnyitása

Az azonosító egyszerű érték: attribútum. A hosszú, több soros leírás elem (az attribútumban a sortörés rosszul kezelt).

2. Érvényes-e?

Miért érvénytelen: <a><b>szöveg</a></b>?

Megoldás megnyitása

Az elemek nem megfelelően egymásba ágyazottak: a b elemet előbb kell lezárni, mint az a elemet.

Közepes szint

3. Elemek számolása

Hány receptnek van legalább 5 hozzávalója?

Megoldás megnyitása

gyoker.Elements("recept").Count(r => r.Element("hozzavalok")?.Elements("hozzavalo").Count() >= 5); a ?. miatt a hiányzó elem null, ami nem >= 5 (a (int?) összehasonlítás hamis).

4. Sorrend a fájlban

Rendezd át az XML receptjeit név szerint a fájlban is. Hogyan?

Megoldás megnyitása

A recepteket OrderBy szerint ToList(), gyoker.RemoveNodes(), majd gyoker.Add(rendezett); vagy egyszerűbben a modell listáját rendezed mentés előtt.

Kihívás szint

5. XPath

Keresd az id="2" receptet XPath kifejezéssel. Mit használsz?

Megoldás megnyitása

A System.Xml.XPath névtér XPathSelectElement metódusa: doc.XPathSelectElement("//recept[@id='2']"). Egyszerű esetben a LINQ olvashatóbb; az XPath szabványos, sok eszköz használja.

6. Nagy XML streamelése

Egy 400 MB-os XML-ből soronként kell feldolgozni a recepteket. Mit használsz a XDocument.Load helyett?

Megoldás megnyitása

Az XmlReader előre haladó, memóriabarát olvasó: reader.ReadToFollowing("recept"), majd XNode.ReadFrom(reader) egy-egy XElement-be; így egyszerre csak egy recept van a memóriában.

Gyors önellenőrzés

Válaszolj fejben, és csak utána nyisd le a választ.

1. Mi az XML gyökéreleme?

A dokumentum egyetlen legfelső eleme, amelyben minden más foglal helyet.

2. Miért ne fűzz XML-t kézzel?

A speciális karakterek (&, <) érvénytelen XML-t okoznak; az XElement helyesen kódol.

3. Mi a különbség az Elements és a Descendants között?

Az Elements a közvetlen gyerekeket, a Descendants minden mélységet adja.

4. Mit ad az (string)elem, ha az elem nincs?

null-t (kivétel nélkül); az (int) a hiányzó értékre kivételt dob, az (int?) null-t ad.

5. Mit okoz a névtér?

Ha az elemek névtérben vannak, a névtér nélküli keresés nem talál; XNamespace + név kell.

6. Mikor jobb az XML, mikor a JSON?

XML: dokumentumok, szabványos formátumok, séma és megjegyzés; JSON: tömör alkalmazásadat, webes API.

7. Mit tegyél hibás XML-nél?

Jelezd a sort és pozíciót (XmlException), ne írd felül a fájlt.

Mit tudsz már?

  • Olvasod az XML szerkezetét, és XDocument segítségével építesz, mentesz, betöltesz.
  • Lekérdezel és módosítasz LINQ to XML-lel, hibatűrő olvasással.
  • Ismered az XmlSerializer lehetőségét és korlátait.
  • Kezeled a névtereket és az XML hibáit.
  • Tudsz választani az XML és a JSON között.

Következő lecke: Application Settings

A program beállításainak tárolása: Properties.Settings, felhasználói és alkalmazás-hatókör, ablakpozíció mentése, frissítés a verziók között és a hibás beállítások kezelése.