Artykuł

sie 01 2010
0

XML w C#: Odczyt elementów drzewa

Po dwóch poprzednich częściach z cyklu XML w C# poświęconych serializacji do XMLa oraz arkuszom styli i transformacji, przyszedł czas na część trzecią poświęconą odczytowi elementów drzewa. Głównie chciałbym się tu skupić na modelu DOM, o którym pisałem już kiedyś tu i tu. Tak więc, zapraszam do lektury:)

XmlDocument czy XPathDocument

Rozpoczynając pracę z danym XMLem, należy zadać sobie proste pytanie. Co chcemy osiągnąć? Czy nasz kod ma tylko odczytywać określone węzły dokumentu, czy ma również posiadać funkcjonalność umożliwiającą tworzenie nowych elementów drzewa. W zależności od wybranej funkcjonalności, należy użyć innej klasy służącej do obsługi takiego XMLa.

Jeśli planujemy stworzyć kod, który czyta i zapisuje do XMLa, to powinniśmy wykorzystać klasę XmlDocument, ale jeśli nasz kod, ma pozwalać tylko na odczyt elementów, to zdecydowanie lepiej jest wykorzystać klasę XPathDocument wraz z językiem XPath, która może zwiększyć wydajność naszego rozwiązania nawet o 30%.

Teraz, zaprezentuje oba rozwiązania szerzej w kontekście odczytu elementów (ponieważ taki jest cel tego wpisu). W obu przykładach, wykorzystamy plik Person.xml, na którym operowaliśmy w dwóch poprzednich wpisach z tego cyklu. Można go pobrać z działu Download.

XmlDocument

Spójrzmy na prosty kod, który wykorzysta klasę XmlDocument do otwarcia dokumentu XML, a następnie do odczytania wszystkich napotkanych wewnątrz węzłów Person:

XmlDocument oXmlDocument = new XmlDocument();
oXmlDocument.Load("Person.xml");
XmlNodeList oPersonNodesList = oXmlDocument.GetElementsByTagName("Person");
Console.WriteLine("W pliku XML, znaleziono dane następujących osób: ");
foreach (XmlNode oPerson in oPersonNodesList)
{
    Console.WriteLine("Imię: {0}, Nazwisko: {1}, Wiek: {2}",
        oPerson.FirstChild.NextSibling.InnerText,
        oPerson.LastChild.PreviousSibling.InnerText,
        oPerson.LastChild.InnerText);
}

Prześledźmy ten bardzo krótki listing. Na początku, w liniach 1-2, tworzymy obiekt klasy XmlDocument i wczytujemy do niego plik XML (podajemy ścieżkę do metody Load). Następnie, w linii 3, wykorzystujemy klasyczną metodę modelu DOM czyli GetElementsByTagName do pobrania wszystkich węzłów Person. Dzięki temu, otrzymujemy obiekt klasy XmlNodeList, będący listą wszystkich wymienionych wyżej węzłów.

W liniach 5-11 iterujemy po naszej liście węzłów. Podczas każdej iteracji, mamy dostęp do kolejnego obiektu typu XmlNode, który przechowuje informacje na temat określonej osoby. W liniach 7-10, wyświetlamy informacje na temat aktualnie przetwarzanej osoby. Właściwości FirstChild oraz LastChild dają nam dostęp do odpowiednio pierwszego i ostatniego podelementu określonego węzła (w specyficznych przypadkach może się zdarzyć, że wskazują one na ten sam element). Aby dostać się do 2 lub przedostatniego podelementu, musimy wykorzystać właściwości NextSibling oraz PreviousSibling.

Wykorzystanie właściwości typu FirstChild, NextSibling itp. nie jest do końca bezpieczne w sytuacji kiedy nie mamy pewności czy przetwarzany przez nas XML, został dobrze zbudowany. W tej sytuacji, lepszym rozwiązaniem mogą się okazać precyzyjne zapytania języka XPath.

XPathDocument

Teraz spróbujemy osiągnąć ten sam efekt z pomocą klasy XPathDocument przy użyciu języka XPath:

XPathDocument oXPathDocument = new XPathDocument("Person.xml");
XPathNavigator oXPathNavigator = oXPathDocument.CreateNavigator();
XPathNodeIterator oPersonNodesIterator = oXPathNavigator.Select("/Persons/Person");
Console.WriteLine("W pliku XML, znaleziono dane następujących osób: ");
foreach (XPathNavigator oCurrentPerson in oPersonNodesIterator)
{
    Console.WriteLine("Imię: {0}, Nazwisko: {1}, Wiek: {2}",
        oCurrentPerson.SelectSingleNode("FirstName").Value,
        oCurrentPerson.SelectSingleNode("LastName").Value,
        oCurrentPerson.SelectSingleNode("Age").Value);
}

Jak widać, kod wynikowy ma dokładnie tyle samo linii, ale zmieniła się cała mechanika. Prześledźmy zatem nowe rozwiązanie krok po kroku.

W pierwszej linii, wczytujemy nasz plik XML, a następnie tworzymy obiekt XPathNavigatora, który pozwoli nam na wędrowanie po naszym dokumencie. W linii trzeciej, tworzymy obiekt Iteratora, który zawierać będzie wszystkie węzły Person. Do pobrania danych wykorzystujemy język XPath. Wyrażenie to oznacza, że w węźle głównym Persons pobieramy wszystkie węzły Person.

W liniach 5-11 znajduje się już pętla foreach. Operujemy tutaj znowu na obiektach XPathNavigator. Każdy z nich, zawiera w sobie osobny węzeł Person.

W liniach 7-10, wyświetlamy dane konkretnej osoby. Wykorzystujemy tutaj ponownie wyrażenia języka XPath, dzięki czemu w precyzyjny sposób określamy o co nam konkretnie w danej chwili chodzi. Jest to rozwiązanie dużo lepszy, aniżeli konstrukcje typu FirstChild, LastChild itp.

Co można zrobić lepiej?

Oczywiście dwa powyższe przykłady, nie nadają się na kod produkcyjny. Tego co przede wszystkim brakuje w tym kodzie, to mechanizmów kontroli błędów, choćby jakiejś prostej konstrukcji try..catch.

Przy bardziej rozbudowanym kodzie, przydałaby się również przestrzenie nazw by dokładnie wyspecyfikować postać tworzonego drzewa.

Niezbędna może się okazać również obecność pliku schematu, który pozwoli na uniknięcie błędów podczas parsowania i niepotrzebnych wyjątków.

Mimo wszystko, mam nadzieję, że komuś treści zaprezentowane w tych ostatnich kilku wpisach, przydadzą się do czegoś sensownego:)

Data ostatniej modyfikacji: 05.06.2011, 17:18.

Podoba Ci się ten wpis? Powiedz o tym innym!

Send to Kindle

Komentarze

blog comments powered by Disqus