R11-T, Informatyka, ASP.NET


Rozdział 11.
Użycie XML w ASP.NET

Aktualnie powinieneś już doskonale znać metody dostępu do danych wykorzystywane w technologii ASP.NET. Wiesz jak uzyskać dostęp i jak wyświetlać dane przy użyciu ADO.NET oraz jak je modyfikować; a co więcej, potrafisz to zrobić na kilka różnych sposobów. Jednak żadne rozważania na temat baz danych oraz Internetu nie będą kompletne bez choćby pobieżnego przedstawienia języka XML — Extensible Markup Language (rozszerzalnego języka znaczników).

XML jest nowym, uniwersalnym językiem służącym do reprezentacji danych na Sieci. Ostatnio poświęcano mu bardzo wiele uwagi, gdyż eliminuje on dużo typowych problemów związanych z dostępem do danych i ich rozpowszechnianiem, takich jak — bezpieczeństwo, możliwość odczytania i rozumienia informacji oraz ich konwersji.

ASP.NET oraz środowisko .NET zostały, w znacznej mierze, zaprojektowane pod kątem wykorzystania XML-a. Fakt ten nie tylko poszerza ich możliwości lecz także czyni je prostszymi w użyciu. W tym rozdziale zajmiemy się właśnie XML-em oraz jego miejscem w środowisku .NET, dużo uwagi poświęcimy odczytywaniu, zapisywaniu oraz konwersji danych XML.

W tym rozdziale omówione zostaną następujące zagadnienia:

Wprowadzenie do języka XML

XML jest tekstowym formatem służącym do reprezentacji danych. Niesie on z sobą nowe sposoby dostarczania informacji do aplikacji internetowych, dając możliwość przesyłania ich w dowolne miejsce i wykorzystania danych niemal każdego rodzaju. Można by przypuszczać, że XML to niemal „czarodziejska różdżka”, jednak jego niezwykła przydatność wynika z dwóch prostych cech. Po pierwsze, język XML jest rozszerzalny (stąd też pochodzi jego nazwa — rozszerzalny język znaczników); co oznacza, że bardzo łatwo można go rozbudowywać dodając własne znaczniki i strukturę dokumentu. Po drugie, XML jest językiem tekstowym, czyli dokumenty XML można tworzyć w każdym edytorze tekstowym, na przykład w programie Notatnik.

XML podobnie jak język HTML opisuje zawartość przy użyciu prostych znaczników. Jednak w XML-u można tworzyć własne znaczniki, co odróżnia go od języka HTML, w którym udostępniana jest pewna grupa standardowych znaczników. I właśnie na tym polega cała potęga XML-a — język ten pozwala na tworzenie własnych znaczników, dzięki czemu istnieje możliwość reprezentacji dowolnych danych. Poza tym, fakt iż są to dokumenty tekstowe zawierające znaczniki sprawia, iż dokumenty XML są łatwe do odczytania i modyfikacji.

Na przykład, można stworzyć następujące znaczniki, które XML, w odróżnieniu od przeglądarki WWW, bez trudu zrozumie:

<Nazwisko>...</Nazwisko>

<Zawod>...</Zawod>

<UlubRestauracja>...</UlubRestauracja >

Kod XML jest zapisywany w postaci zwyczajnego tekstu — jeśli tylko chcesz, możesz tworzyć dokumenty XML w programie Notatnik. Takie informacje można bez trudu przesyłać w dowolne miejsca. W przeważającej większość baz danych wewnętrzne informacje zapisywane są w pewnym specyficznym formacie. Jeśli w jednym projekcie wykorzystywane są różne źródła danych (lub źródła działające na różnych platformach komputerowych), to zazwyczaj konieczne jest przeprowadzanie złożonych konwersji pomiędzy różnymi typami danych. W XML-u dane prezentowane są w strukturalnej, tekstowej postaci, dzięki czemu nie ma potrzeby wykonywania jakichkolwiek archaicznych konwersji. Ta tekstowa natura sprawia, że użytkownicy nie mają większych problemów z odczytywaniem i zrozumieniem zawartości dokumentów XML. Język ten pozwala także na omijanie wyrafinowanych mechanizmów zabezpieczających, które niejednokrotnie uniemożliwiają użycie innych sposobów przesyłu informacji lub stwarzają konieczność stosowania złożonych rozwiązań umożliwiających transmisję danych. Te mechanizmy zabezpieczające bardzo często pozwalają na przesyłanie zwyczajnych plików tekstowych, a zatem XML doskonale nadaje się do przesyłania danych.

Notatka
Aplikacje internetowe bardzo często wykorzystują wiele źródeł danych, działających na różnych platformach. W takich aplikacjach, XML jest doskonałym sposobem reprezentacji danych.

Model danych XML

Listing 11.1 przedstawia przykład pliku XML prezentującego książki dostępne księgarni.

Listing 11.1 Książki dostępne w księgarni zapisane w formie dokumentu XML

Nowe określenie

Zapisz ten plik pod nazwą books.xml. Więcej szczegółowych informacji na temat konstrukcji tego pliku znajdziesz w dalszej części rozdziału, w podrozdziale poświęconym schematom XML. Jak na razie wystarczy, abyś zwrócił uwagę, że XML składa się ze strukturalnych, hierarchicznych znaczników. W naszym przykładowym dokumencie znajdują się --> cztery[Author:p8R] znaczniki <book>, z których każdy posiada własne atrybuty (genre oraz style) i kilka podelementów (title, author, price). Cały ten zbiór został zapisany wewnątrz znaczników <bookstore>, które opisują zawartość dokumentu. Ten sposób reprezentacji danych, określany jest często mianem drzewa dokumentu lub drzewa danych.

W tradycyjnych bazach danych, takich jak Microsoft Access, dane wyglądają, mniej więcej, w sposób przedstawiony na rysunku 11.1

Genre

Style

Title

AuFurstName

AuLastName

Price

novel

hardcover

The Handmaid's Tale

Margaret

Atwood

19.95

novel

paperback

The Poisonwood Bible

Barbara

Kingsolver

11.99

novel

hardcover

Hannibal

Richard

Harris

27.95

novel

hardcover

Focault's Pendulum

Umberto

Eco

22.95

Rysunek 11.1. Dane XML pochodzące z dokumentu przedstawionego na listingu 11.1, wyświetlone w programie Microsoft Access

Informacje zapisane w języku XML są łatwiejsze do przenoszenia, ich odczytanie i zrozumienie jest prostsze, a co więcej, ich stworzenie nie wymaga użycia żadnych złożonych mechanizmów. Zapisz te dane w pliku tekstowym o nazwie books.xml i umieść go w folderze C:\inetpub\wwwroot\aspnetdlakazdego\rozdzial11 (lub w dowolnym innym miejscu, którego nazwę z łatwością zapamiętasz). A teraz spróbuj wyświetlić ten plik w swojej przeglądarce. Jeśli korzystasz z którejś z nowszych wersji przeglądarek (Internet Explorer 5.5 lub z wersji późniejszej) to, to zawartość dokumentu zostanie zaprezentowana w sposób przedstawiony na rysunku 11.2.

0x01 graphic

Rysunek 11.2. Dokument XML wyświetlony w przeglądarce WWW.

Internet Explorer jest w stanie automatycznie przetworzyć dokument XML i wyświetlić jego zawartość w formie hierarchicznej listy. Gałęzie tej listy można „zwijać” klikając znaki „-” wyświetlone z lewej strony znaczników, oraz „rozwijać” klikając znaki „+”. XML udostępnia wspaniały mechanizm służący do reprezentacji danych.

Schematy XML

Jeśli zdefiniujesz swoje własne znaczniki, to w jaki sposób inne osoby będą wiedzieć jaki rodzaj informacji chcesz przedstawić? Otóż format informacji zapisanych w pliku XML definiują, tak zwane, schematy XML. Przyjrzyjmy się schematowi definiującemu informacje przedstawione na listingu 11.1.

Listing 11.2 Schemat XML dla dokumentu z listingu 11.1

Analiza

Zapisz ten dokument w pliku o nazwie books-schema.xdr i umieść go w tym samym folderze, w którym znajduje się plik books.xml. Zawartość tego dokumentu także przypomina zwyczajny kod HTML, jest jednak czymś więcej. Przyjrzyjmy się jej dokładniej. W wierszu 1. określany jest typ tworzonego dokumentu XML — w tym przypadku używamy XML w wersji 1.0. Wiersz tej jest konieczny, aby nasze przykłady mogły działać poprawnie. W wierszu 2. otwierany jest znacznik <schema>. xmlns to określenie przestrzeni nazw XML, stanowiącej standardową grupę znaczników XML, które ktoś zebrał by ułatwić ich dalszą standaryzację. W tej chwili nie musisz wiedzieć niczego więcej na temat przestrzeni nazw XML — zazwyczaj, jeśli w ogóle będziesz z jakiejś korzystał, to będzie to któraś ze standardowych przestrzeni, na przykład schemas-microsoft-com:xml-data (jak w powyższym przykładzie).

Znaczniki <ElementType> są stosowane do definiowania formatu danych. Wiersze do 4. do 7. definiują elementy first-name, last-name, name oraz price, które zostaną użyte w dalszej części schematu. Umieszczenie tych definicji na początku dokumentu, przypomina deklarowanie zmiennych na samym początku stron ASP.NET.

Atrybut content znaczników <ElementType> określa rodzaj informacji jakie mogą być umieszczane wewnątrz definiowanego znacznika; natomiast atrybut dt:type podaje kilka dodatkowych cech, takich jak typ danych zawartości znacznika oraz jej format.

Wiersze od 9. do 17. definiują kolejny element — author. Także ten element zawiera kilka innych znaczników, zdefiniowanych wcześniej w wierszach od 4. do 7. Wiersze od 18. do 21. definiują kilka kolejnych elementów i atrybutów, które można używać w schemacie.

I w końcu, w wierszu 22. definiowany jest element book, który zawiera wszystkie zdefiniowane wcześniej elementy. Ta część schematu powinna odpowiadać formatowi dokumentu XML. W wierszu 29. został zdefiniowany ostatni element, który zawiera elementy book.

Notatka
Nie trzeba definiować elementów przed ich użyciem w schemacie — równie dobrze można zdefiniować je wszystkie wewnątrz elementu
book. Niemniej jednak, wcześniejsze definiowanie elementów jest lepszym sposobem tworzenia schematów; podobnie jak definiowanie zmiennych nim zostaną po raz pierwszy użyte w dokumencie ASP.NET.

Schemat — books-schema.xdr — definiuje kolumny tabeli bazy danych, natomiast plik books.xml definiuje jej wiersze. Dzięki temu, te dwa pliki mogą reprezentować niemal każdy rodzaj informacji.

Nowe określenie

Plik XML zgodny ze schematem, zawierający znaczniki zapisane w poprawny sposób (czyli zgodnie ze standardem języka XML określonym przez konsorcjum W3C), nazywany jest poprawnie sformułowanym dokumentem XML. Tworzenie poprawnie sformułowanych dokumentów XML gwarantuje, że wszystkie aplikacje wykorzystujące język XML będą w stanie je odczytać. Ogólnie rzecz biorąc, poprawnie sformułowany dokument XML musi spełniać następujące warunki:

Więcej informacji o dokumentacjach standardów W3C znajdziesz pod adresem http://webreference.com/xml/reference/standards.html.

Dostęp do danych XML w dokumentach ASP.NET

Korzystanie z danych XML przypomina operowanie na informacjach przechowywanych w bazach danych przy wykorzystaniu ADO.NET. Środowisko .NET udostępnia wiele obiektów, które zapewniają różny stopień kontroli nad danymi, a każdy z nich ma swoje zalety i wady. W tej części rozdziału przedstawię dwa najprostsze obiekty służące do operowania na danych XML — XmlTextReader oraz XmlTextWriter, oba zostały zdefiniowane w przestrzeni nazw System.Xml.

Odczyt danych XML

Klasa XmlTextReader udostępnia prosty i szybki mechanizm dostępu do nieprzetworzonej zawartości dokumentów XML. Ze względu na możliwość jednokierunkowego odczytu informacji (od początku ku końcowi dokumentu) i brak nadmiernych kosztów występujących przy stosowaniu obiektów DataSet, klasa XmlTextReader przypomina nieco klasę OleDbDataReader.

Aby otworzyć plik XML wystarczy stworzyć nowy obiekt XmlTextReader i przekazać do niego nazwę pliku XML. Przykładowo, jeśli stworzymy stronę ASP.NET o nazwie XMLReader.aspx i umieścimy ją w folderze zawierającym pliki XML, to będzie można je otwierać przy wykorzystaniu następującej instrukcji:

Dim reader As new XmlTextReader(nazwa_pliku_ze_sciezka)

W tym przypadku nie istnieją żadne łańcuchy połączenia ani nazwy DNS, którymi trzeba by się przejmować. Należy jednak podać pełną ścieżkę dostępu do pliku. Można ją uzyskać przy wykorzystaniu metody Server.MapPath (patrz rozdział 4., pt.: „Stosowanie obiektów ASP.NET w językach C# i VB.NET”). Dostęp do danych XML zapewnia metoda Read, przypominająca analogiczną metodę klasy OleDbDataReader. Oto przykład:

Do While (reader.Read())

'zrób coś z danymi

Loop

Każde wywołanie metody Read powoduje automatyczne przejście do następnego elementu pliku XML. Na listingu 11.3 przedstawiłem stronę ASP.NET, która wykorzystując możliwości klasy XmlTextReader odczytuje i wyświetla zawartość pliku books.xml.

Listing 11.3. Odczyt danych XML przy wykorzystaniu obiektu XmlTextReader (XMLReader.aspx)

Analiza

Zapisz kod przedstawiony na powyższym listingu w pliku XMLReader.aspx. Pierwszą nową rzeczą na którą należy zwrócić uwagę, jest instrukcja Import umieszczona w 2. wierszu. Instrukcja ta importuje przestrzeń nazw System.Xml, dzięki czemu możliwe będzie wykorzystanie klas związanych z obsługą języka XML, takich jak na przykład XmlTextReader.

Następnie, w wierszu 6. deklarowany jest obiekt XmlTextReader. Cała dalsza część kodu, która będzie odczytywać zawartość pliku XML została zapisana wewnątrz bloku try. (Pamiętaj, że za każdym razem gdy korzystasz z zasobów pochodzących spoza ASP.NET, fragment kodu operujący na nich należy umieścić wewnątrz bloku try.) W wierszu 9. tworzony jest obiekt czytelnika, który odczyta zawartość naszego pliku XML. Przy tworzeniu tego obiektu konieczne jest podanie pełnej ścieżki dostępu do pliku, którą można określić przy użyciu metody Server.MapPath. Konkretnie rzecz biorąc wywołanie tej metody zwróci ścieżkę c:\inetpub\wwwroot\aspnetdlakazdego\rozdzial11\books.xml.

I w końcu, przy użyciu metody Read cyklicznie pobierane są wszystkie elementy dokumentu XML, a w przeglądarce zostają wyświetlone ich nazwy (Name) i wartości (Value). Nie należy zapominać o zamknięciu obiektu czytelnika — stosowne czynności są wykonywane w bloku finally zapisanym w wierszach 17. i 18. Wyniki wykonania strony z listingu 11.3 zostały przedstawione na rysunku 11.3

0x01 graphic

Rysunek 11.3 Prezentacja zawartości pliku books.xml

Na rysunku 11.3 zostały wyświetlone wszystkie znaczniki zapisane w pliku books.xml — nie tylko znaczniki otwierające lecz także zamykające. Nie zawsze rozwiązanie takie będzie pożądane. Niestety możliwości funkcjonalne klasy XmlTextReader są bardzo ograniczone — klasa ta nie przykłada znaczenia do tego jakie znaczniki są zwracane i dlatego zwraca je wszystkie!

Aby rozwiązać ten problem, klasa XmlTextReader udostępnia właściwość NodeType, która określa typ aktualnie analizowanych informacji. Wybrane, najczęściej spotykane typy węzłów zostały podane w tabeli 11.1.

Tabela 11.1 Wartości właściwości NodeType stosowane w klasie XmlTextReader.

Typ

Opis

All

wszystkie węzły;

Attribute

atrybut;

CDATA

te fragmenty zawierają tekst, który w inaczej zostałby rozpoznany jako kod zapisany w jakimś języku znaczników, na przykład w HTML-u;

Comment

komentarze zapisane pomiędzy znacznikami <!-- oraz -->;

Document

element główny drzewa danych XML;

Element

element, zazwyczaj są to faktyczne dane zapisane w pliku XML;

EndTag

znacznik zamykający elementu;

None

aktualnie nie jest analizowany żaden węzeł;

Text

zwracana jest tekstowa zawartość elementu;

XMLDeclaration

węzeł zawierający deklarację XML, taką jak
<?XML version='1.0'?>.

Wykorzystajmy teraz właściwość NodeType i zmodyfikujmy przykład z listingu 11.3 tak, aby zwracane były tylko interesujące nas informacje.

Listing 11.4 Zwracanie informacji przy wykorzystaniu właściwości NodeType (XMLReader2.aspx).

Analiza

W wierszu 13. została wstawiona instrukcja select, która przed wyświetleniem jakichkolwiek informacji sprawdza typ aktualnie przetwarzanego węzła. Pierwszy blok case, rozpoczynający się w wierszu 14., jest wykonywany gdy właściwości NodeType ma wartość Element. Jeśli węzeł ma jakiekolwiek atrybuty, to są one kolejno pobierane, a do określenia ich wartości używana jest metoda GetAttribute. Jeśli węzeł jest zwyczajnym fragmentem tekstu to jest on wyświetlany w wierszu 23. Wyniki wykonania strony z listingu 11.4 przedstawiłem na rysunku 11.4

0x01 graphic

Rysunek 11.4 Wyświetlenie zawartości pliku books.xml przy wykorzystaniu właściwości NodeType

Jeśli struktura pliku XML jest znana (przy czym chodzi tu, na przykład, o nazwy elementów oraz ich atrybutów) to można jeszcze bardziej zmodyfikować kod odczytujący zawartość pliku i wyświetlać wyłącznie te informacje, które nas interesują. Na przykład, gdyby interesował nas wyłącznie gatunek książki (atrybut genre), to zamiast instrukcji select zapisanej w wierszach od 16. do 20., moglibyśmy wykorzystać następujący fragment kodu:

Response.Write(reader.Item("genre") & "<br>")

Zapis danych XML

Dzięki klasie XmlTextWriter zapisywanie plików XML jest równie łatwe jak ich odczytywanie przy użyciu obiektów klasy XmlTextReader. Klasa XmlTextWriter udostępnia metodę Write, która generuje odpowiednie dane wyjściowe.

Na przykład, strona ASP.NET przedstawiona na listingu 11.5 tworzy nową wersję pliku XML zawierającego informacje o księgarni.

Listing 11.5 Zapis plików XML przy wykorzystaniu obiektu XmlTextWriter (XMLWriter.aspx)

Analiza

Struktura kodu przedstawionego na powyższym listingu przypomina strukturę przykładów wykorzystujących obiekty klasy XmlTextReader. Obiekt pisarza (XmlTextWriter) jest deklarowany w wierszu 6., a pozostała część kodu została umieszczona wewnątrz bloku try. Obiektu pisarza jest tworzony w wierszu 9. Pierwszym argumentem przekazywanym w wywołaniu konstruktora jest nazwa tworzonego pliku XML, a drugim — sposób kodowania jaki ma zostać użyty (domyślnie stosowany jest kod UTF-8). Jeśli plik o podanej nazwie nie istnieje, to ASP.NET go utworzy; w przeciwnym przypadku zostanie użyty istniejący plik.

Ostrzeżenie
Wykorzystanie tego sposobu tworzenia plików XML sprawi, że zawartość istniejącego pliku o podanej nazwie zostanie usunięta. Oznacza to, że zawartość istniejącego pliku
books2.xml zostanie bezpowrotnie utracona. A zatem, zanim coś zapiszesz, upewnij się, że nie usuniesz żadnych ważnych informacji!

W wierszu 12. w tworzonym pliku XML zapisywany jest znacznik deklaracji XML — <?XML version='1.0'?>. Jest on elementem, który musi się znaleźć we wszystkich poprawnie sformułowanych dokumentach XML. W wierszach 13. i 14. definiowany jest sposób, w jaki ma być zapisywany generowany kod XML. Wiersz 13. informuje ASP.NET, iż należy stosować wcięcia, a wiersz 14. — że pojedyncze wcięcie ma mieć wielkość 3 znaków odstępu. Dzięki wykorzystaniu wcięć, odczytanie i analiza zawartości pliku XML będzie znacznie łatwiejsza. Właściwości Formatting można przypisać wartość Indented bądź None. Znak stosowany przy tworzeniu wcięć można określić przy wykorzystaniu właściwości IndentChar.

Generacja danych rozpoczyna się w wierszu 15. Znaczniki otwierające i zamykające elementów generowane są odpowiednio przy użyciu metod WriteStartElement oraz WriteEndElement. W wierszu 15. w pliku zapisywany jest znacznik otwierający <bookstore>, natomiast w wierszu 32. odpowiadający mu znacznik zamykający — </bookstore>. W wierszu 16. generowany jest otwierający znacznik <book>, a w wierszu 31. — odpowiadający mu znacznik zamykający.

W wierszach 17. i 18. generowane są atrybuty genre oraz style znacznika <book> oraz ich wartości. Metoda WriteElementString daje możliwość wygenerowania prostego elementu składającego się ze znacznika otwierającego, zamykającego oraz pewnej, podanej zawartości. Metoda ta została wykorzystana w wierszu 20.

writer.WriteElementString("title", "Vietnam")

Jej użycie powoduje wygenerowanie poniższego fragmentu kodu XML:

<title>Vietnam</title>

Jak widać metoda ta generuje dwa znacznik — otwierający i zamykający — określone za pomocą pierwszego argumentu, a wewnątrz nich umieszcza łańcuch znaków podany jako drugi argument.

Po zamknięciu wszystkich wygenerowanych wcześniej znaczników otwierających, zawartość pliku jest „opróżniana” (wiersz 32.). Proces ten przypomina nieco opróżnianie bufora wyjściowego (patrz rozdział 5., pt.: „Podstawowe wiadomości o tworzeniu formularzy internetowych”), z tą różnicą, iż dane są zapisywane w pliku, a nie przekazywane do przeglądarki. I w końcu, w wierszu 38., obiekt pisarza jest zamykany.

Notatka
Standardowo, wywołanie metody
Close spowoduje zapisanie wygenerowanego kodu XML w pliku. Wywoływanie metody Flush nie jest konieczne, chyba że ten sam obiekt ma być ponownie wykorzystany do stworzenia innego pliku.

Wywołanie metody Close powoduje także automatyczne zamknięcie wszystkich otworzonych znaczników elementów i atrybutów; jednak zaleca się, aby zawsze robić to własnoręcznie.

Wyniki wykonania strony z listingu 11.5 zostały przedstawione na rysunku 11.5.

0x01 graphic

Rysunek 11.5 Plik books2.xml wygenerowany przez stronę ASP.NET z listingu 11.5

Walidacja dokumentów XML

Dokumenty XML muszą być poprawnie sformułowane — w końcu ma to być uniwersalny język służący do reprezentacji danych. Gdyby dokument XML nie był poprawnie sformułowany, to osiągnięcie tego standardu byłoby niezwykle trudne.

Wyobraź sobie dwie firmy próbujące wymienić informacje zapisane w pliku XML. Plik niepoprawnie sformułowany umożliwiałby różną interpretację danych, co mogłoby doprowadzić do tragicznych skutków; zwłaszcza gdyby obie firmy faktycznie zinterpretowały zawartość pliku w odmienny sposób.

ASP.NET pozwala na walidację danych XML na podstawie schematu lub definicji typu dokumentu (ang.: Document Type Definition, w skrócie DTD). DTD to kolejny sposób opisu formatu danych XML, którego dokładniejsze omówienie wykracza poza ramy niniejszej książki. Aby sprawdzić poprawność dokumentu XML należy stworzyć nowy obiekt — XmlValidatingReader — oraz określić typ walidacji jaką należy przeprowadzić:

'tutaj tworzymy obiekt czytelnika

dim validator as new XMLValidatingReader(reader)

validator.ValidationType = ValidationType.DTD

jeśli jest używany plik DTD, lub:

validator.ValidationType = ValidationType.XDR

jeśli używamy schematów (plików .xdr).

Następnie dodawana jest procedura obsługi zdarzenia wykorzystywana przy walidacji. Użyje ona podanego schematu lub definicji typu dokumentu (DTD) określonego w przestrzeni nazw dokumentu XML. W tym rozdziale do walidacji dokumentów XML, będziemy używali schematów. Dodajmy teraz odpowiednią deklarację do nowego pliku XML — books2.xml. Wystarczy zmienić element bookstore w poniższy sposób:

<bookstore xmlns="x-schema:books-schema.xdr">

Jak na razie nie musisz się przejmować dokładnym zrozumieniem składni tego elementu. Informuje ona ASP.NET, że do walidacji dokumentu należy użyć schematu zapisanego w pliku books-schema.xdr. Jeśli plik XML będzie poprawnie sformułowany i zgodny ze schematem, to nie powinieneś zauważyć żadnej różnicy, a wyniki będą przypominać te uzyskane w poprzednich przykładach.

Listing 11.6 przedstawia początkową część naszego przykładowego kodu (jego pozostałą część przedstawiłem na listingu 11.7).

Listing 11.6 Walidacja danych XML (XMLValidate.aspx)

Analiza

Powyższy listing przypomina nieco wszystkie przykłady przedstawione we wcześniejszej części tego rozdziału. Zwróć uwagę, iż w wierszu 3. importowana jest dodatkowa przestrzeń nazw — System.Xml.Schema. Będzie ona konieczna do sprawdzenia poprawności dokumentu XML na podstawie schematów. Proces walidacji rozpoczynany jest od stworzenia obiektu XmlTextReader (w wierszu 6.) i otworzenia pliku XML o nazwie books2.xml (w wierszu 11.). Następnie, w wierszu 13., jest tworzony obiekt XmlValidatingReader, przy czym, przy jego utworzeniu zostaje wykorzystany obiekt XmlTextReader. Dzięki temu utworzony obiekt będzie wiedział, który plik należy sprawdzić. W wierszu 14. określamy, że walidacja ma zostać przeprowadzona na podstawie pliku schematu zdefiniowanego w analizowanym pliku XML.

Większość wbudowanych zdarzeń ASP.NET dysponuje predefiniowanymi procedurami obsługi (na przykład, zdarzenie Load obiektu Page obsługiwane jest przez procedurę Page_Load). Jednak zdarzenia związane z walidacją dokumentów XML nie dysponują żadnymi predefiniowanymi procedurami obsługi. Z tego powodu konieczne jest własnoręczne zdefiniowanie procedury obsługi tego zdarzenia, przy użyciu metody AddHandler (wiersze 16. i 17.). Pierwszym argumentem wywołania tej metody jest zdarzenie, które ma być obsługiwane, a drugim — wskaźnik do metody która ma je obsługiwać. Operator addressof użyty w wierszu 17. zwraca wskaźnik do procedury ShowError, która wykona pewne czynności w przypadku gdy walidacja dokumentu nie zakończy się pomyślnie. Metodzie tej można nadać całkowicie dowolną nazwę. Nie trzeba zwracać bacznej uwagi na szczegóły działania tego mechanizmu, lecz warto znać składnię jakiej należy użyć — przyda się ona w przypadku gdybyś kiedyś musiał sprawdzać poprawność dokumentów XML.

Warto także zwrócić uwagę na pustą pętlę while zapisaną w wierszach 19. i 20. Standardowo należałoby w niej odczytywać dane i w jakiś sposób wyświetlać interesujące nas informacje. Niemniej jednak w przypadku sprawdzania poprawności danych XML, nie jest to konieczne. Teraz interesuje nas tylko odczytanie danych i sprawdzenie czy są poprawne; nie mamy zamiaru ich wyświetlać.

Pozostałą część naszej przykładowej strony ASP.NET stanowi kod procedury ShowError, przedstawiony na listingu 11.7.

Listing 11.7 Procedura ShowError

Analiza

Na powyższym listingu została zdefiniowana procedura ShowError, wywoływana za każdym razem, gdy w odczytywanym pliku XML zostaną odnalezione jakiekolwiek nieprawidłowości. Zwróć uwagę na drugi argument, typu ValidationEventArgs umieszczony w jej definicji. Zawiera on właściwość Message, w której są zapisywane opisy wszystkich błędów odnalezionych w analizowanym dokumencie XML. W wierszach 28. i 29. opis ten jest wyświetlany na wynikowej stronie WWW w kolorze czerwonym. W wierszach od 32. do 34. wyświetlane jest położenie kodu XML, w którym wykryto błąd. Informacje te, niezwykle przydatne przy lokalizacji i poprawianiu wszelkich problemów, można określić za pomocą właściwości LineNumber oraz LinePosition klasy XmlValidatingReader.

Notatka
Być może zauważyłeś, że w kodzie przedstawionym na listingu 11.6 deklaracja obiektu klasy
XmlTextReader została przeniesiona poza procedurę Page_Load. Dzięki temu, obiekt ten będzie mógł być używany we wszystkich funkcjach i metodach zdefiniowanych na tej samej stronie ASP.NET, a nie wyłącznie w procedurze Page_Load. Właśnie dzięki temu, można go wykorzystać także wewnątrz procedury ShowError.

Gdyby deklaracja tego obiektu pozostała wewnątrz procedury Page_Load, to odwołanie się do obiektu czytelnika w procedurze ShowError spowodowałoby zgłoszenie błędu.

Jeśli zawartość pliku books2.xml będzie taka sama jak zawartość pliku books.xml, to żadne błędy nie powinne się pojawić i wszystko pójdzie zgodnie z planem. Jednak zmodyfikujmy nieznacznie kod tego pliku, tak aby efekty działania walidacji stały się widoczne. Spójrz na kod XML przedstawiony na listingu 11.8.

Listing 11.8. Books2.xml — błędnie zapisany dokument XML

Zgodnie ze schematem zdefiniowanym w pliku --> books-schema.xdr[Author:p8R] , w powyższym pliku można doszukać się dwóch nieprawidłowości. Pierwszą z nich jest brak atrybutu style elementu book, a drugą — zapisanie zwykłego łańcucha znaków w elemencie pirce (który powinien zawierać liczbę). Na rysunku 11.6 przedstawiłem komunikaty o błędach wyświetlone w przeglądarce w wyniku wykonaniu strony ASP.NET przedstawionej na listingach 11.6. oraz 11.7.

0x01 graphic

Rysunek 11.6. Błędy wyświetlone podczas sprawdzania poprawności dokumentu XML

Gdyby w pętli while na listingu 11.6. został umieszczony kod prezentujący informacje odczytywane z pliku XML, to na rysunku 11.6. zostałyby one wyświetlone wraz z informacjami o błędach.

Model obiektów dokumentu XML

Model obiektów dokumentu XML (określany w skrócie jako DOM) jest specyfikacją opracowaną przez W3C szczegółowo opisującą jak powinny zachowywać się aplikacje korzystające z informacji zapisanych w języku XML. Specyfikacja ta określa klasy jakie powinne być stosowane, sposoby odczytu i zapisu kodu XML oraz cechy jakimi powinne charakteryzować się używane klasy. Samą specyfikację możesz znaleźć na witrynie W3C, na poniższych stronach WWW:

http://www.w3.org/TR/REC-DOM-Level-1/

oraz

http://www.w3.org/TR/DOM-Level-2-Core/

Jak na razie nie zwracaliśmy żadnej uwagi na DOM XML. Obiekty XmlTextReader oraz XmlTextWriter nie implementują DOM-u, gdyż jego użycie wiąże się ze zbyt dużymi kosztami. Obie te klasy zostały stworzone z myślą o szybkim dostępie do danych XML, który nie wymagałby wykorzystania wielu zasobów systemowych. Niemniej jednak, czasami może się okazać, że do edycji, modyfikacji oraz poruszania się po dokumencie XML będą nam potrzebne pełne możliwości funkcjonalne udostępniane przez DOM.

Podstawowe możliwości funkcjonalne opisane przez XML DOM udostępnia klasa XmlNode. Reprezentuje ona pojedynczy element należący do drzewa dokumentu XML i może zostać wykorzystana do przejścia do węzłów podrzędnych oraz do węzła nadrzędnego, jak również do edycji i usuwania informacji. XmlDocument — klasa potomna XmlNode — pozwala na wykonywanie czynności (takich jak otwieranie bądź zapis) na całym dokumencie XML. W XML DOM dostępnych jest wiele innych klas bazujących na klasie XmlNode, takich jak --> XmlElement czy też XmlAttribute[Author:p8R] , jednak w tej książce nie zostaną one omówione. Sposób wzajemnego współdziałania poszczególnych klas XML DOM przedstawiłem na rysunku 11.7.

Rysunek 11.7. Wzajemne współdziałanie klas służących do obsługi danych XML, opracowanych przez firmę Microsoft

Opis rysunku:

XML Data - dane XML

wszystkie pozostałe nazwy użyte na rysunku pozostają w oryginalnej postaci

XmlNode reprezentuje gałąź pliku XML, która zawiera wszystkie elementy podrzędne, atrybuty oraz znaczniki otwierający i zamykający elementu. Na przykład, znaczniki <title>...</title> stosowane w pliku books.xml to dwa elementy, lecz jeden węzeł. Każdy węzeł może posiadać wiele węzłów podrzędnych; każdy węzeł reprezentuje także inną gałąź. A zatem, operując na danych XML przy wykorzystaniu XML DOM robi się to w sposób przypominający działanie na danych przechowywanych w tradycyjny sposób.

Na przykład, operując na danych przy użyciu programu Microsoft Access, nie traktuje się początku i końca tego samego pola jako dwóch różnych obiektów — stanowią one części tego samego pola. Klasy XmlTextReader oraz XmlTextWriter traktują każdy element dokumentu XML jako niezależną jednostkę, natomiast w przypadku wykorzystania DOM-u znacznik otwierający oraz dopowiadający mu znacznik zamykający są uważane za jedno pole. Pojęcie węzłów w pliku XML przedstawiłem na rysunku 11.8.

<?xml version="1.0"?>

1 <bookstore>

2 <book genre="novel" style="hardcover">

3 <title>The Handmaid's Tale</title>

4 <author>

5 <first-name>Margaret</first-name>

6 <last-name>Atwood</last-name>

</author>

7 <price>19.95</price>

</book>

8 <book genre="novel" style="paperback">

9 <title>The Poisonwood Bible</title>

10 <author>

11 <first-name>Barbara</first-name>

12 <last-name>Kingsolver</last-name>

</author>

13 <price>11.99</price>

</book>

</bookstore>

Rysunek 11.8. Węzły pliku XML

Pobieranie danych XML

Dane XML można pobrać do obiektu XmlDocument na kilka różnych sposobów. Dwa najczęściej stosowane to pobranie ich z obiektu XmlTextReader bądź bezpośrednio z oryginalnego pliku XML. Poniżej przedstawione zostały oba te sposoby:

dim xmldocument as XmlDocument = new XmlDocument()

'pobranie informacji z obiektu XmlTextReader

dim reader as new XmlTextReader(server.MapPath("books.xml"))

xmldocument.Load(reader)

'pobranie bezpośrednio z pliku

xmldocument.Load(server.MapPath("books.xml"))

Ale po co korzystać z obiektu XmlTextReader skoro można pominąć etap jego tworzenia i wczytać dane bezpośrednio z pliku XML? Czasami użycie obiektu XmlDocument nie będzie konieczne i wystarczy zastosowanie obiektu XmlTextReader. Niemniej jednak, jeśli okaże się, że konieczne jest wykorzystanie pełnych możliwości funkcjonalnych obiektu XmlDocument, to nie trzeba będzie bezustannie pobierać jego zawartości. Zamiast tego wystarczy odczytać ją z używanego obiektu czytelnika (XmlTextReader).

Po pobraniu danych można je przeglądać przy wykorzystaniu obiektu XmlNode. Na przykład, można analizować poszczególne węzły i wyświetlać zawarte w nich informacje w sposób przypominający pobieranie kolejnych elementów przy wykorzystaniu metody Read obiektu XmlTextReader. Stosowny przykład przedstawiłem na listingach 11.9 oraz 11.10.

Listing 11.9. Otwieranie dokumentu XML przy użyciu obiektu XmlDocument (XMLDOMRead.aspx)

Analiza

Pierwsza część kodu tej strony jest bardzo prosta. W wierszu 9. tworzony jest nowy obiekt XmlDocument, który zostaje zapisany w zmiennej xmldoc. Następnie, w wierszu 12., są do niego wczytywane informacje z pliku XML. Procedura ShowTree przedstawiona na listingu 11.10 analizuje wszystkie węzły tego pliku i wyświetla informacje o nich. Właściwość DocumentElement obiektu XmlDocument zwraca pierwszy element pliku XML (w naszym przypadku będzie to deklaracja stosowanej wersji języka XML). Ten początkowy element jest przekazywany do procedury ShowTree, dzięki czemu może ona wyświetlić zawartość całego pliku.

Listing 11.10. Analiza zawartości pliku XML przy wykorzystaniu obiektów XmlNode (ciąg dalszy XMLDOMRead.aspx)

Nowe określenie

Procedura ShowTree wykorzystuje pojęcie programistyczne nazywane rekurencją. Procedury rekurencyjne wywołują same siebie, aż do momentu spełnienia pewnego warunku. W naszym przypadku procedura ShowTree wyświetla informacje na temat węzła i, jeśli posiada on jakieś węzły podrzędne, wywołuje samą siebie dla każdego z nich, przekazując w wywołaniu węzeł, który ma zostać przeanalizowany. Jeśli natomiast nie ma żadnych węzłów podrzędnych, procedura przechodzi do analizy kolejnego węzła. W taki sposób metoda ShowTree schodzi „w głąb” hierarchii dokumentu XML i wyświetla informacje o wszystkich węzłach podrzędnych. Ogólną zasadę działania procedury ShowTree przedstawiłem na rysunku 11.9.

Rysunek 11.9. Wykorzystanie rekurencji do przeanalizowania wszystkich węzłów dokumentu XML

Opis rysunku:

Call function - Wywołanie funkcji

Dysplay… - Wyświetlenie danych dla danego węzła

Child node? - Czy są węzły podrzędne?

Yes - Tak

No - Nie

Move to sibling …- Przejście do kolejnego węzła (jeśli jest)

Go to… - Przejście do węzła podrzędnego

Time called - Kolejność wywołania

Current node - Analizowany węzeł

Children - Ilość węzłów podrzędnych

Move to… - Przejście do

(pierwsze trzy kolumny tabelki u dołu rysunku - bez zmian)

(w ostatniej kolumnie „Move to...”)

  1. bookstore child 1 - pierwszego węzła podrzędnego węzła bookstore

  2. book child 1 - pierwszego węzła podrzędnego węzła book

  3. ... - drugiego węzła podrzędnego węzła book

  4. ... - pierwszego węzła podrzędnego węzła author

  5. ... - drugiego węzła podrzędnego węzła author

  6. ... - trzeciego węzła podrzędnego węzła book

  7. ... - drugiego węzła podrzędnego węzła bookstore

  8. ... - pierwszego węzła podrzędnego węzła book

  9. ... - drugiego węzła podrzędnego węzła book

Analiza

Jeśli aktualnie analizowany węzeł nie ma żadnych węzłów podrzędnych (co sprawdza warunek umieszczony w wierszu 25.), to po prosty wyświetlana jest jego nazwa i wartość. Zmienna strOutput służy do gromadzenia informacji na temat analizowanego węzła, jej zawartość zostanie wyświetlona po zakończeniu analizy dokumentu (w wierszu 53.), jako tekst etykiety output. Jeśli jednak węzły podrzędne i dany węzeł jest elementem, to wyświetlane są jego wszystkie atrybuty. Obiekt XmlNamedNodeMap deklarowany w wierszu 23. i używany w wierszu 32. i 33. reprezentuje kolekcję atrybutów węzła. Wartości atrybutów można pobrać przetwarzając po kolei wszystkie elementy tej kolekcji (patrz wiersze od 33. do 37.).

Jeśli aktualnie analizowany węzeł posiada jakieś węzły podrzędne, to konieczne będzie rekurencyjne wywołanie procedury ShowTree. Wywołanie tej procedury dla każdego z węzłów podrzędnych realizowane jest przez blok kodu zapisany w wierszach od 42. do 48. W pierwszej kolejności zmiennej node przypisywany jest pierwszy węzeł podrzędny bieżącego węzła. Zmienna ta jest następnie przekazywana jako argument wywołania procedury ShowTree, która wyświetli informacje na temat przekazanego węzła. Jeśli także ten węzeł ma węzły podrzędne, to określany jest pierwszy z nich i cały proces rozpoczyna się ponownie. Pętla while rozpoczynająca się w wierszu 44. oraz wykorzystana wewnątrz niej właściwość NextSibling (wiersz 46.) umożliwia pobranie wszystkich węzłów podrzędnych, każdego z węzłów znajdujących się w dokumencie XML.

Wyobraź sobie otwieranie prezentów podczas świąt Bożego Narodzenia. Otwierasz jedno pudełko, sprawdzasz jego zawartość i przechodzisz do następnego. Jednak ktoś z rodziny chciał być dowcipny i dał Ci ogromne pudło, gdy je otworzyłeś, znalazłeś kolejne, nieco mniejsze. Wewnątrz niego znalazłeś jeszcze mniejsze pudełko i tak dalej, aż w końcu odnalazłeś właściwy prezent. Cały proces sprawdzania prezentów można by podsumować w następujący sposób: otwierałeś jeden prezent i jeśli nie było w nim żadnych mniejszych pudełek, to przechodziłeś do kolejnego prezentu. Jeśli jednak w prezencie były jakieś mniejsze pudełka, to otwierałeś je nim zająłeś się kolejnym prezentem. Rekurencja jest bardzo podobnym procesem — otwierasz wszystkie gałęzie pliku XML, a jeśli któraś z nich zawiera węzły podrzędne, to przed przejściem do kolejnej gałęzi, zostaną one otworzone i przeanalizowane.

Metoda ShowTree analizuje całą zawartość dokumentu XML i generuje wyniki przedstawione na rysunku 11.10.

0x01 graphic

Rysunek 11.10. Wyniki wykonania kodu przedstawionego na listingach 11.9 oraz 11.10, wyświetlone w przeglądarce

Tak

Nie

Obiektów XmlDocument oraz XmlNode używaj gdy będziesz musiał stworzyć lub zmodyfikować informacje zapisane w języku XML.

Nie używaj obiektów XmlDocument oraz XmlNode jeśli chcesz tylko odczytać informacje — wykorzystanie tych obiektów wiąże się z dodatkowymi kosztami, które mogą spowodować niepotrzebne pogorszenie efektywności działania aplikacji.

Modyfikacja danych XML

Obiekt XmlDocument udostępnia także wiele metod służących do tworzenia i modyfikacji dokumentów XML. Przy tworzeniu nowych elementów można posłużyć się którąś z metod Create, na przykład: CreateComment, CreateAttribute, CreateNode, itp. Posługując się tymi metodami można utworzyć praktycznie każdy rodzaj elementu. Oto przykład:

'tworzymy nowy element

dim eleBook as XmlElement = xmldoc.CreateElement("Book")

dim attStyle as XmlAttribute = xmldoc.CreateAttribute("style")

eleBook.SetAttributeNode(attStyle)

eleBook.SetAttribute("style", "hardcover")

dim root as XmlElement = xmldoc.Item("bookstore")

root.AppendChild(eleBook)

W wierszu 2. powyższego przykładu tworzony jest nowy obiekt XmlElement, a w wierszu 3. nowy obiekt XmlAttribute. Następnie, przy wykorzystaniu metody SetAttributeNode, atrybut ten dodawany jest do elementu, po czym zostaje określona jego wartość (służy do tego metoda SetAttribute). I w końcu, nowy element dodawany jest do głównego elementu dokumentu XML — bookstore.

Modyfikacja danych XML jest niezwykle prosta — sprowadza się ona do podania nowych wartości. Oto przykład:

if node.Name = "price" then

node.Value = "8.99"

end if

I to wszystko! Jeśli konieczne będzie zmodyfikowanie wszystkich wartości w pliku, to można to zrobić przy wykorzystaniu rekurencji, dzięki której pobranie wszystkich węzłów dokumentu nie przysparza żadnych problemów. W tabeli 11.2 przedstawiłem wybrane metody klasy XmlDocument służące o tworzenia i modyfikacji danych XML.


Tabela 11.2. Metody obiektu XmlDocument służące do modyfikacji danych XML

Metoda

Opis

AppendChild

Dodaje podany węzeł na końcu listy węzłów potomnych bieżącego węzła.

CreateAttribute

Tworzy obiekt XmlAttribute reprezentujący atrybut o podanej nazwie.

CreateCDataSection

Tworzy sekcję CData o podanej zawartości.

CreateComment

Tworzy obiekt XmlComment o podanej zawartości.

CreateElement

Tworzy obiekt XmlElement reprezentujący element o podanej nazwie.

CreateNode

Tworzy obiekt XmlNode reprezentujący węzeł określonego typu, o podanej nazwie i należący do przestrzeni nazw o podanym adresie URI (co zapewnia unikalność schematów nazw).

CreateTextNode

Tworzy obiekt XmlText o określonej zawartości.

CreateXmlDeclaration

Tworzy obiekt XmlDeclaration reprezentujący sekcję deklaracji XML; określa ona używaną wersję języka XML, sposób kodowania oraz podaje łańcuch znaków określający czy atrybuty są niezależne; numer używanej wersji języka XML musi mieć wartość "1.0".

GetElementById

Zwraca obiekt XmlElement reprezentujący element o określonym identyfikatorze.

GetElementByTagName

Zwraca kolekcję XmlNodeList zawierającą wszystkie elementy odpowiadające podanej nazwie.

ImportNode

Importuje wskazany węzeł z innego dokumentu XML; wartość logiczna (Boolean) określa czy należy także importować wszystkie węzły podrzędne.

InsertAfter

Wstawia pierwszy podany obiekt XmlNode po drugim podanym obiekcie XmlNode.

InsertBefore

Wstawia pierwszy podany obiekt XmlNode przed drugim podanym obiektem XmlNode.

PrependChild

Dodaje podany węzeł na samym początku listy węzłów podrzędnych.

RemoveAll

Usuwa wszystkie węzły podrzędne oraz atrybuty bieżącego węzła.

RemoveChild

Usuwa wskazany węzeł podrzędny.

ReplaceChild

Zastępuje drugi podany obiekt XmlNode, pierwszym podanym obiektem.

WriteContentTo

Zapisuje wszystkie węzły podrzędne bieżącego węzła w podanym obiekcie XmlWriter (na przykład, w XmlTextWriter).

WriteTo

Zapisuje bieżący węzeł w podanym obiekcie XmlWriter (na przykład, w XmlTextWriter).

Notatka
Zwróć uwagę, iż niektóre z tych metod są przeciążone, a ich inne wersje umożliwiają podawanie innych argumentów. Wszelkie informacje na ten temat znajdziesz w dokumentacji .NET SDK.

Wiele spośród metod klasy XmlDocument jest także dostępnych w klasie XmlElement oraz XmlNode.

Do zapisania wszelkich wprowadzanych modyfikacji służy metoda Save:

xmldoc.Save("books2.xml")

Podpowiedź
Jeśli chcesz dopisać nowe informacje do istniejącego pliku XML, wystarczy pobrać jego zawartość do obiektu
XmlDocument, wprowadzić niezbędne zmiany i zapisać dokument pod tą samą nazwą. Poprzednia wersja pliku zostanie „nadpisana”, jednak żadne zapisane w nim informacje nie będą utracone, gdyż wcześniej zostały w całości wczytane do obiektu XmlDocument.

Listing 11.11 przedstawia przykład strony ASP.NET, która wczytuje całą zawartość pliku XML i dopisuje do niego nowy węzeł.

Listing 11.11. Dopisywanie danych przy wykorzystaniu DOM (XMLDOMWrite.aspx).

Analiza

Kod umieszczony w wierszach do 1. do 9. jest całkowicie typowy — jest w nim tworzony obiekt XmlDocument, do którego jest następnie wczytywana zawartość pliku books3.xml. W wierszach od 10. do 14. tworzony jest nowy obiekt XmlElement reprezentujący element book oraz nowy obiekt XmlAttribute reprezentujący atrybut tego elementu. Zwróć uwagę, iż oba te obiekty tworzone są przy wykorzystaniu metod istniejącego obiektu XmlDocument zapisanego w zmiennej xmldoc. Dzięki temu tworzone elementy będą miały identyczny format co dane już zapisane w pliku.

Wiersz 16. deklaruje, że stworzony atrybut jest częścią elementu book, a wiersz 17. określa jego wartość. W wierszu 19. pobierany jest element główny pliku XML — element bookstore; do którego dopisujemy następnie nowy element book (w wierszu 20.). I w końcu, przy użyciu metody Save, wszystkie wprowadzone modyfikacje są z powrotem zapisywane w pliku books3.xml; przy czym żadne zapisane w nim informacje nie zostały utracone.

XML oraz DataSet

XML w środowisku .NET jest ściśle związany z ADO.NET. Dane wewnątrz obiektów DataSet są bowiem przechowywane właśnie w formacie XML. Oznacza to, że zawartość obiektów DataSet jest w pamięci komputera przechowywana jako dane XML, a nie jest reprezentowana przy wykorzystaniu jakiegoś abstrakcyjnego modelu danych. A zatem, na danych XML operujemy zarówno bezpośrednio przy użyciu klas służących do obsługi XML, jak również pośrednio podczas korzystania z ADO.NET. DataSet po prostu udostępnia inny sposób prezentacji danych XML.

Zastanówmy się zatem czym dysponujemy. Z jednej strony mamy ADO.NET oraz jego klasy. Dostępne są proste klasy zapewniające szybki i łatwy dostęp do danych, takie jak OleDbDataReader; jak również klasy bardziej złożone — na przykład: DataSet — które zawierają informacje relacyjne i udostępniają znacznie większe możliwości funkcjonalne niż klasa OleDbDataReader.

Dysponujemy także klasami operującymi bezpośrednio na danych XML. Wśród nich także można znaleźć klasy całkiem proste jak i bardzo złożone. Klasa XmlTextReader zapewnia proste możliwości odczytu zawartości plików XML, natomiast klasa XmlDocument dostarcza znacznie bogatsze możliwości funkcjonalne. Niemniej jednak klasa XmlDocument niezbyt dobrze reprezentuje dane relacyjne i właśnie z tego powodu została wprowadzona klasa XmlDataDocument.

XmlDataDocument jest dla XML tym, czym DataSet jest dla ADO.NET. Obiekty obu tych klas są do siebie bardzo podobne i każdy z nich, z łatwością można skonwertować na drugi. Dzięki temu, klasy te stanowią pomost pomiędzy ADO.NET oraz XML.

Obiekty klasy XmlDataDocument są zbliżone do obiektów klasy XmlDocument lecz w odróżnieniu od nich wykorzystują relacyjną reprezentację danych, zbliżoną do tej, stosowanej w obiektach DataSet. Obiekty XmlDataDocument można stosować wszędzie tam gdzie są używane obiekty XmlDocument, a co więcej, nawet metody i właściwości obu tych klas są identyczne.

Za każdym razem, gdy do obiektu XmlDataDocument ładowane są informacje, środowisko .NET automatycznie tworzy obiekt DataSet, który można pobrać za pośrednictwem właściwości o tej samej nazwie. Kolumny tego obiektu oraz ich typy określane są na podstawie schematu XML. Jeśli żaden schemat nie zostanie podany, to środowisko .NET samodzielnie określi strukturę danych.

Dzięki temu można modyfikować dane w dowolny sposób. Na przykład, można otworzyć plik XML przy wykorzystaniu klas XML a następnie przenieść je do obiektu DataSet i powiązać elementami kontrolnymi serwera. Można także pobrać informacje przechowywane w bazie danych przy użyciu obiektu DataSet i zapisać w formacie XML. Modyfikacje wprowadzane w obiektach XmlDataDocument mogą lecz nie muszą powodować zmian w obiektach DataSet. Jeśli nowe dane odpowiadają polom obiektu DataSet, to zostanie do niego dodany nowy wiersz.

Wzajemne związki pomiędzy obiektami klas XmlDataDocument oraz DataSet przedstawiłem na rysunku 11.11.

Rysunek 11.11. Wzajemny związek pomiędzy obiektami kas DataSet oraz XmlDataDocument

Opis rysunku

XML file - plik XML

Validations… - walidacja, transformacje kodu XML, i tak dalej

Database - baza danych

Managed Providers - Zarządzani dostawcy danych (np. ADO.NET)

Data binding… - wiązanie danych, wizualne narzędzia projektowania elementów sterujących, itp.

XmlTextReader, XmlDataDocument, DataSet - bez zmian

Przyjrzyjmy się wzajemnym związkom obiektów obu tych klas. W przedstawionym poniżej przykładzie, za pośrednictwem obiektu XmlDataDocument pobierzemy dane z pliku books.xml i zapiszemy je w obiekcie DataSet, a następnie wyświetlimy je na dwa różne sposoby. Przyjrzyjmy się teraz kodowi przykładu, który przedstawiłem na listingu 11.12, w którym został wykorzystany zarówno obiekt DataSet jak i XmlDataDocument (część HTML tej strony składa się jedynie z elementu Label oraz dwóch elementów DataGrid których zawartość jest generowana na serwerze).

Listing 11.12. Wyświetlanie danych przy wykorzystaniu obiektów DataSet oraz XmlDataDocument

Analiza

Listing rozpoczyna się od stworzenia obiektu XmlDataDocument. Jednak zamiast wczytywać dane bezpośrednio do tego dokumentu, są one pobierane za pośrednictwem metody ReadXml właściwości DataSet (patrz wiersz 14.). Metoda ta, jak się już wkrótce przekonasz, tworzy relacyjną reprezentacje pobieranych informacji.

Przejdźmy na razie do wiersza 27. Rozpoczyna się w nim pętla for pobierająca wszystkie tabele dostępne w obiekcie DataSet. Dla każdej z nich, wyświetlana jest nazwa oraz ilość kolumn (patrz wiersze od 27. do 32.). Kolejna pętla for (zapisana w wierszach od 34. do 40.) wyświetla nazwy oraz typy danych poszczególnych kolumn dostępnych w danej tabeli. Obiekt DataSet wie jakie typy danych reprezentuje każda z kolumn tabeli, gdyż określa jej schemat na podstawie struktury danych.

Jednak dzięki temu, że używasz obiektu DataSet istnieje prostszy sposób na wykonanie tych samych czynności. W wierszach od 17. do 22. informacje z obiektu DataSet są wiązane z dwoma różnymi elementami sterującymi DataGrid zdefiniowanymi na naszej przykładowej stronie (za chwilę dowiesz się, dlaczego wykorzystywane są dwa obiekty). Wyniki wykonania tej strony ASP.NET przedstawiłem na rysunku 11.12

0x01 graphic

Rysunek 11.12. Prezentacja relacyjnych danych XML przy wykorzystaniu obiektów XmlDataDocument oraz DataSet

Zaraz… ale na rysunku widoczne są dwie tabele, a dysponujemy tylko jednym plikiem XML. Co się zatem stało?

Otóż środowisko .NET odczytała schemat XML i zauważyła, że dane mogą zostać przedstawione w sposób relacyjny. Konkretnie rzecz biorąc, wydzielone i umieszczone w odrębnej tabeli zostały informacje o autorze. Środowisko .NET automatycznie wygenerowała także kolumnę klucza obcego, która połączyła obie tabele! W obu elementach kontrolnych DataGrid możesz zobaczyć dane przedstawione w bardziej tradycyjny sposób.

Ale w jaki sposób obiekt DataSet określił strukturę danych bez wykorzystania schematu? W rzeczywistości jest to całkiem proste:

Wszystkie pozostałe dane stają się kolumnami. Po określeniu struktury, wszelkie dane XML odpowiadające kolumnom zostają dodane do obiektu DataSet jako jego wiersze.

Jednak czy w rzeczywistości są to dane relacyjne? Co się stanie gdy do pliku XML dodamy kolejny węzeł book zawierający informacje o autorze podane w jednym z już istniejących węzłów? Na rysunku 11.13 przedstawiłem dane jakie zostaną wygenerowane w takiej sytuacji, w formie, w jakiej zostałyby one zaprezentowane przez elementy kontrolne DataGrid.

genre

style

title

book_Id

price

novel

hardcover

The Handmaid's Tale

0

19.95

novel

paperback

The Poisonwood Bible

1

11.99

novel

paperback

The Poisonwood Bible

2

13.99

first-name

last-name

book-Id

Margaret

Atwood

0

Barbara

Kingsolver

1

Barbara

Kingsolver

2

Rysunek 11.13. Dodawanie kolejnych danych relacyjnych

O rany! Ale to przecież nie jest to o co chodziło. Mechanizmy ASP.NET nie wykryły, że istnieje już autor Barbara Kingsolver i dodały nowy rekord do tabeli autorów. Próba stworzenia klucza głównego składającego się z kolumn first-name oraz last-name spowoduje wystąpienie błędów. Niestety nie ma prostego sposobu rozwiązania tego problemu. Aby poprawnie dodać dane, konieczna by była ręczna aktualizacja klucza głównego i usunięcie niepotrzebnego wiersza z tabeli autorów.

Jednak bez względu na to ograniczenie, możliwość reprezentacji danych w formie obiektów DataSet oraz w formie danych XML jest niezwykle przydatna i użyteczna. Informacje relacyjne mogą być tworzone w formie danych XML i przekazywane do obiektu DataSet w celu zapisania ich w bazie danych, lub w drugim kierunku — odczytane z bazy danych i zapisane w pliku XML w celu ich przesłania.

Zgodnie z tym czego dowiedziałeś się w kilku ostatnich rozdziałach, zapis danych w formie relacyjnej jest bardzo często spotykaną i efektywną metodą reprezentacji informacji, a XML bez wątpienia doskonale się do tego celu nadaje. Połączone możliwości klas XmlDataDocument oraz DataSet umożliwiają dostęp i operowanie na danych relacyjnych pochodzących z dowolnego źródła.

To nie jest ASP!

Jeśli znasz tradycyjną technologię ASP, to informacje zawarte w tym rozdziale mogą stanowić dla Ciebie całkowitą nowość, gdyż obsługa języka XML niemal w ogóle nie była w niej dostępna. Nie było żadnych wbudowanych obiektów służących do obsługi danych tego typu, a niejednokrotnie jedyną możliwością wykorzystania XML-a była implementacja pełnego modelu obiektów dokumentu XML (które niewątpliwie nie była łatwym i przyjemnym rozwiązaniem).

Na szczęście środowisko .NET (a zatem także ASP.NET) dysponuje w pełni zintegrowanymi możliwościami obsługi języka XML. Dostępne są także dwa różne sposoby wykorzystania danych XML — za pośrednictwem ADO.NET oraz architektury XML.

Niestety ta nowa architektura ma bardzo mało wspólnego z wcześniej stosowanymi metodami obsługi XML-a. Oznacza to że używane metodologie są zupełnie nowe i ich poznanie będzie wymagało nieco czasu. Na szczęście ASP.NET udostępnia dobrze zdefiniowane klasy i obiekty stanowiące spójny model programistyczny, które znacznie ułatwią naukę.

2 Część I Podstawy obsługi systemu WhizBang (Nagłówek strony)

2 Dokument2

autor pisze o dwóch, ale jak można policzyć są cztery.

na początku rozdziału jest mowa o pliku books-schema.xdr a nie .xml - odpowiednio zmieniłem.

obie klasy zaczynają się od "Xml" a nie "XML" - wg. dokumentacji .NET Framework



Wyszukiwarka

Podobne podstrony:
R15-T, Informatyka, ASP.NET
R12-T, Informatyka, ASP.NET
R13-T, Informatyka, ASP.NET
R20-T, Informatyka, ASP.NET
R17-T, Informatyka, ASP.NET
R14-T, Informatyka, ASP.NET
R21-T, Informatyka, ASP.NET
informatyka asp net 3 5 tworzenie portali internetowych w nurcie web 2 0 omar al zabir ebook
informatyka asp net ajax programowanie w nurcie web 2 0 christian wenz ebook
informatyka asp net mvc 4 programowanie jess chadwick ebook
informatyka asp net mvc 3 framework zaawansowane programowanie steven sanderson ebook
BizAgi Studio Cz, 5 Stworzeni aplikacji zewn trznej w ASP NET
ASP NET 2 0 Tworzenie witryn internetowych z wykorzystaniem C i Visual Basica aspntw
asp net introduction MM6QQFHOGEVK7FULUA
C i ASP NET Szybki start
ASP NET Vademecum profesjonalisty
asp net introduction to microsoft asp net 3R522NRLFCX55WSTS6WZOFPHBH4HEKDTR3EY47Q

więcej podobnych podstron