Odczytywanie dokumentu XML w C#

Zacznijmy może od tego, że XML to skrót od od angielskich słów „Extensible Markup Language”, które można przetłumaczyć jako „Rozszerzalny Język Znaczników”. Do czego służy ów język? Jego zadaniem jest przechowywanie w sposób uporządkowany różnych danych. Nie należy jednak mylić go z bazą danych, bo po prostu nią nie jest. Dokumenty XML ze względu na swoją specyfikę, nie są uzależnione od żadnej konkretnej platformy. Można ich używać właściwie wszędzie, od komputera PC, aż do różnych innych dziwnych tworów typu inteligentna lodówka 😉

Jak zbudowany jest dokument XML?

Budowa dokumentów XML, jest bardzo intuicyjna i prosta. Całość opiera się, jak wskazuje sama nazwa – na znacznikach. Stwórzmy w takim razie, jakiś prosty dokument XML zawierający np. listę zakupów:

Każdy dokument XML powinien zaczynać się linijką, w której określana jest wersja standardu, z którego korzystamy, oraz kodowanie, w jakim został on zapisany. Powyższy przykład stosuje się do tego zalecenia. Dalsza część powyższego dokumentu opiera się o dwa znaczniki: <list>, oraz <item>. Pierwszy znacznik jest „rodzicem” dla znaczników znajdujących się w jego wnętrzu. My nazwaliśmy go list – w sumie logiczne, bo w jego wnętrzu znajduje się lista zakupów 😉 Z kolei drugi znacznik przechowuje informacje o pojedynczych produktach. Znaczniki inaczej nazywane są też węzłami. Nigdy nie może dojść do sytuacji, kiedy jakiś znacznik nie jest domknięty. Nazewnictwo znaczników jest sprawą dowolną.

Atrybuty

Oprócz znaczników, język XML udostępnia nam też tzw. atrybuty. Dzięki nim możemy nadać jakieś unikalne cechy znacznikowi, którego używamy dla różnych podobnych danych. Przykład:

Powyższy dokument dostarcza nam informacje, nie tylko o tym co należy kupić. Dzięki niemu wiemy również, że np. klucz kosztuje 15zł i jest narzędziem. Jednak to jeszcze nie koniec. Możemy pokusić się o rozbudowanie naszego przykładu, o podział listy zakupów na dni tygodnia:

Teraz wiemy, co należy kupić w poniedziałek, a co we wtorek 😉 Analogicznie możemy rozbudowywać naszą listę dalej. Możemy nawet podzielić ją dodatkowo na to, w jakim sklepie, jakie rzeczy trzeba kupić:

Chyba dalsze tłumaczenie jest zbędne, wystarczy popatrzeć na przykłady, żeby załapać o co chodzi. Skoro wszystko jasne, przejdźmy teraz do tego, jak odczytać powyższy przykład przy użyciu C#.

Odczytywanie danych z pliku XML w C#

Obsługę XML’a przez C# zawdzięczamy przestrzeni nazw System.Xml. Utwórzmy zatem nową klasę, której będziemy używać do odczytywania pliku XML:

Kod póki co, jest bardzo prosty. Tworzymy nowy obiekt klasy XmlDocument oraz ładujemy plik XML do pamięci, przy pomocy metody, jaką ta klasa udostępnia.

Czasami zdarza się, że potrzebujemy wyciągnąć z XML’a jedynie wartości z poszczególnych znaczników, bez względu na ich hierarchię. Do tego celu potrzebujemy dwóch informacji: Ile takich znaczników znajduje się w dokumencie oraz jaką noszą nazwę. Liczbę znaczników o danej nazwie z powodzeniem zwróci poniższa metoda:

Z kolei do wyciągnięcia wartości ze znacznika, o danym indeksie z powodzeniem można wykorzystać poniższą metodę:

Jak użyć tych dwóch metod? Bardzo prosto. Skoro wiemy jaka jest ilość elementów „item” w dokumencie, to do odczytania wartości przy pomocy metody GetElementValue(int number , string name) wystarczy zwykła pętla for:

Powyższy kod wyświetli nam „na sucho” wartości znajdujące się wewnątrz znaczników item:item

Podobnie sprawa ma się z atrybutami. Poniższa metoda zwróci wartość danego atrybutu dla danego znacznika o danym indeksie:

Przykład użycia:

item

Wszystko pięknie ładnie, ale… Czasami takie odczytywanie dokumentu XML nie wystarczy. Nie wynika z niego, które rzeczy gdzie mają zostać kupione. Nie wynika też, kiedy mają być kupione. Na szczęście temu też można zaradzić 😉

Odczytywanie wartości dla wybranego węzła

Załóżmy, że chcemy odczytać z naszego XML’a listę sklepów jakie odwiedzimy tylko w poniedziałek. Wcześniejsze sposoby do tego się nie nadają. Jak, więc temu zaradzić? To, również nie jest tak trudne, jak mogłoby się wydawać. Oto metoda, która zrealizuje takie zadanie:

Tak wygląda, natomiast jej użycie:

W wyniku działania kodu, otrzymamy informację, że w poniedziałek odwiedzimy jedynie sklep „FirstShop”, natomiast we wtorek sklepy „FirstShop” i „SecondShop” – wszystko się zgadza 🙂 To może teraz spróbujmy pobrać nazwy przedmiotów tylko dla sklepu numer dwa we wtorek:

Użycie metody jest identyczne, jak wcześniej:

Zwraca nam ona wartości: „Młotek” i „Długopis” – czyli wszystko w jak najlepszym porządku.

Jak zapewne zauważyłeś, całość operacji sprowadza się do wybrania odpowiedniego węzła w linijce XmlNodeList items = XmlDoc.SelectNodes(„//weekday[@name = ‚” + Day + „‚]//shop[@name = ‚” + Shop + „‚]”);, gdzie po ukośnikach podajemy nazwę znacznika, a po znaku @ nazwę atrybutu. Z kolei wyciąganie wartości niższych w hierarchii sprowadza się do użycia odpowiedniej instrukcji. W przypadku atrybutów jest to xn.Attributes[„name”].InnerText, natomiast w przypadku wartości pomiędzy znacznikami jest to pętla foreach (XmlNode item in xn.ChildNodes); Znając te zasady możemy odczytać z pliku XML dosłownie wszystko 😉

Cóż, to byłoby chyba na tyle. Zapisem pliku XML z poziomu C# zajmę się w osobnym wpisie. Jak zwykle zachęcam do zadawania pytań i zgłaszania ewentualnych błędów merytorycznych zawartych we wpisie w komentarzach.

8 przemyśleń nt. „Odczytywanie dokumentu XML w C#

  1. Zastanawiam się dlaczego używasz tutaj XmlDocument do odczytu czy nie lepiej skorzystać z XDocument i Linq2Xml? API jest przyjemniejsze w użyciu i da się obejść bez XPath’ów (które mają tą samą tendencji co regexy do bycia write-only, plus poza XMLQuire niewiele jest darmowych narzędzi do pisania/debugowania XPathów)

    • Dlaczego? Po prostu jeszcze do innych „narzędzi” nie dotarłem. Ostatnio potrzebowałem odczytywać xml’a w projekcie i na szybko znalazłem klasę XmlDocument, którą zacząłem się bawić. Zdała egzamin, więc postanowiłem coś o tym napisać. Niemniej jednak, widzę, że przydałoby się zgłębić bardziej w ten temat 🙂

      Pozdrawiam!

  2. Cześć! Przy okazji omawiania XML-a warto wspomnieć o opcji w Visual Studio > Menu > Edit > Paste Special > Paste XML/JSON As Classes. Fajna sprawa 🙂
    Pozdrawiam,
    Maciej

  3. Używanie tego: „XmlDoc.GetElementsByTagName(name).Count;” po to żeby wyliczyć ile jest elementów o danej nazwie a następnie iterować po całym XmlDocu jest bez sensu. Metoda GetElementsByTagName(string) od razu zwraca Ci to czego potrzebujesz 🙂

Możliwość komentowania jest wyłączona.