libxml2 parser DOM dla C++ czwartek, 8 grudnia 11



Podobne dokumenty
Wykorzystywanie parsera DOM w programach Java i PL/SQL

Zasady programowania Dokumentacja

Zaawansowane aplikacje WWW - laboratorium

Perl a XML. Narzędzia informatyczne w językoznawstwie. Generowanie danych XML - Przykład. Generowanie danych XML. Perl - Przetwarzanie XML

Język C++ Różnice między C a C++

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Programowanie proceduralne INP001210WL rok akademicki 2018/19 semestr letni. Wykład 6. Karol Tarnowski A-1 p.

Ćwiczenie nr 6. Poprawne deklaracje takich zmiennych tekstowych mogą wyglądać tak:

Podstawy programowania skrót z wykładów:

Wykład I. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Programowanie obiektowe i C++ dla matematyków

Wykład II. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Wskaźniki. Informatyka

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 12. Karol Tarnowski A-1 p.

Struktury. Przykład W8_1

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

DYNAMICZNE PRZYDZIELANIE PAMIECI

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

XML i nowoczesne technologie zarządzania treścią 2007/08

akademia androida Składowanie danych część VI

Projektowanie klas c.d. Projektowanie klas przykład

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Języki programowania obiektowego Nieobiektowe elementy języka C++

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

utworz tworzącą w pamięci dynamicznej tablicę dwuwymiarową liczb rzeczywistych, a następnie zerującą jej wszystkie elementy,

INFORMATYKA Studia Niestacjonarne Elektrotechnika

Ćwiczenie 7 z Podstaw programowania. Język C++, programy pisane w nieobiektowym stylu programowania. Zofia Kruczkiewicz

Szablony klas, zastosowanie szablonów w programach

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Podstawy programowania. Wykład: 9. Łańcuchy znaków. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Wskaźniki. Przemysław Gawroński D-10, p marca Wykład 2. (Wykład 2) Wskaźniki 8 marca / 17

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Programowanie i struktury danych. Wykład 4 Dr Piotr Cybula

Podstawy programowania w języku C++

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Programowanie w języku C++

29. Poprawność składniowa i strukturalna dokumentu XML

Extensible Markup Language (XML) Wrocław, Java - technologie zaawansowane

Język C++ wykład VIII

Część 4 życie programu

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

Programowanie Obiektowo Zorientowane w języku c++ Przestrzenie nazw

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

Biblioteka standardowa - operacje wejścia/wyjścia

Programowanie w językach

Wstęp do Programowania 2

1 Atrybuty i metody klasowe

Operacje wejścia/wyjścia (odsłona druga) - pliki

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

SAX i DOM wykorzystanie XML-a we własnych aplikacjach. Simple API for XML Parsing Document Object Model

Zmienne, stałe i operatory

Pliki. Informacje ogólne. Obsługa plików w języku C

Opis: Instrukcja warunkowa Składnia: IF [NOT] warunek [AND [NOT] warunek] [OR [NOT] warunek].

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

Programowanie obiektowe

WYKŁAD 3 XML DOM XML DOCUMENT OBJECT MODEL CZĘŚĆ 1

Języki programowania. Przetwarzanie tablic znaków. Część druga. Autorzy Tomasz Xięski Roman Simiński

Uwagi dotyczące notacji kodu! Moduły. Struktura modułu. Procedury. Opcje modułu (niektóre)

Języki i metodyka programowania. Typy, operatory, wyrażenia. Wejście i wyjście.

Programowanie obiektowe w C++ Wykład 12

UML a kod w C++ i Javie. Przypadki użycia. Diagramy klas. Klasy użytkowników i wykorzystywane funkcje. Związki pomiędzy przypadkami.

Listy powiązane zorientowane obiektowo

Programowanie obiektowe Wykład 3. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21

Języki i metodyka programowania. Wprowadzenie do języka C

Podstawy programowania w języku C++

Podstawy programowania

Tablice, funkcje - wprowadzenie

Smarty PHP. Leksykon kieszonkowy

XML w.net. Dominik Baś nr alb Wrocław, 29 maja 2007

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 16 kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 27

Wyjątki. Wyjątki. Bogdan Kreczmer. Katedra Cybernetyki i Robotyki Politechnika Wrocławska

Zmienne i struktury dynamiczne

Wykład 4: Klasy i Metody

I - Microsoft Visual Studio C++

Programowanie w Ruby

Programowanie i struktury danych

Laboratorium 03: Podstawowe konstrukcje w języku Java [2h]

Programowanie Komputerów

Obsługa wyjątków. Język C++ WW12

Wykład 3 Składnia języka C# (cz. 2)

Oprogramowanie i wykorzystanie stacji roboczych. Wykład 4

// Liczy srednie w wierszach i kolumnach tablicy "dwuwymiarowej" // Elementy tablicy są generowane losowo #include <stdio.h> #include <stdlib.

Dzisiejszy wykład. Klasa string. wersja prosta wersja ze zliczaniem odwołań. Wyjątki Specyfikator volatile Semafory

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 26 marca kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 40

Funkcje zawarte w bibliotece < io.h >

Programowanie obiektowe w C++ Wykład 1

Programowanie w C++ Wykład 11. Katarzyna Grzelak. 21 maja K.Grzelak (Wykład 11) Programowanie w C++ 1 / 24

XML extensible Markup Language. Paweł Chodkiewicz

Programowanie obiektowe

Rodzina protokołów TCP/IP. Aplikacja: ipconfig.

Kurs WWW. Paweł Rajba.

Kurs języka Python Wykład 8. Przetwarzanie tekstu Wyrażenia regularne Biblioteka urllib Parsowanie html'a XML

Techniki Programowania wskaźniki 2

Transkrypt:

libxml2 parser DOM dla C++ 1

SAX vs. DOM Dwa podstawowe typy API do przetwarzania dokumentów XML: Oparte na drzewach (ang. Tree-based API) - mapują strukturę dokumentu do drzewa i pozwalają użytkownikowi nawigować po tym drzewie. Oparte na zdarzeniach (ang. Event based API) - zgłaszają zdarzenia występujące podczas parsowania (np. początek/ koniec elementu). Zdarzenia są zgłaszane do aplikacji za pomocą callback'u. Aplikacja implementuje metody (handlery) przechwytujace te zdarzenia w sposób podobny do obsługi zdarzeń generowanych przez GUI. 2

SAX vs. DOM DOM - czesto użyteczne, ale wykorzystują dużo zasobów, szczególnie w przypadku dużych dokumentów. Jesli aplikacje wykorzystują swoje własne struktury danych niekorzystne jest budowanie drzewa tylko po to, żeby na jego podstawie zbudować obiekty wewnętrznych struktur danych. SAX pozwala na parsowanie dokumentów dużo większych niż dostępne zasoby pamięciowe. Własne struktury danych mogą być tworzone za pomocą metod wykorzystywanych do obsługi zdarzeń. 3

Kiedy używać SAX - przykład ZADANIE: W dokumencie XML wielkosci 20MB znaleźć element zawierający słowo "Częstochowa" Wykorzystanie DOM - tworzenie drzewa dla tak dużego dokumentu tylko po to, żeby znaleźć jeden element w zbiorze danych byłoby bardzo nie korzystne. Wykorzystanie SAX - możliwe znalezienie elementu (w metodach obsługi zdarzeń) wykorzystując minimalną ilość pamięci. 4

SAX - jak to działa. <?xml version="1.0"?> <doc> <para>hello, world!</para> </doc> Podczas przetwarzania dokumentu zgłoszone zostaną zdarzenia: 1. start document 2. start element: doc 3. start element: para 4. characters: Hello, world! 5. end element: para 6. end element: doc 7. end document 5

SAX SAX nie wymaga cache'owania całego dokumentu, umożliwia przechwytywanie zdarzeń parsowania tak jakby były to zdarzenia interesu użytkownika. Za pomocą API bazujacego na zdarzeniach możliwe jest utworzenie struktury drzewa i zmapowanie dokumentu XML do tej struktury. 6

LibXML2 typy danych xmlchar - znak kodowany w UTF-8. Jeśli dane są kodowane w innym standardzie muszą zostać przekształcone do UTF-8. xmldoc - struktura zawierająca drzewo utworzone przez parser. xmldocptr - wskaźnik na strukturę xmldoc. xmlnode - struktura zawierająca pojedynczy węzeł. xmlnodeptr - wskaźnik na strukturę xmlnode wykorzystywany do przechodzenia po drzewie. 7

xmlnode Najwazniejsze pola składowe struktury _xmlnode xmlelementtype type - typ węzła const xmlchar * name - nazwa węzła _xmlnode * children - wskaźnik na pierwsze dziecko _xmlnode * last - wskaźnik na ostatnie dziecko _xmlnode * parent - wskaźnik na rodzica _xmlnode * next - wskaźnik na następne rodzeństwo _xmlnode * prev - wskaźnik na poprzednie rodzeństwo _xmldoc * doc - wskaźnik na węzeł dokumentu xmlchar * content zawartość węzła (value) _xmlattr * properties - wskaźnik na pierwszy atrybut 8

Typ węzła - enum xmlelementtype XML_ELEMENT_NODE = 1 XML_ATTRIBUTE_NODE = 2 XML_TEXT_NODE = 3 XML_CDATA_SECTION_NODE = 4 XML_ENTITY_REF_NODE = 5 XML_ENTITY_NODE = 6 XML_PI_NODE = 7 XML_COMMENT_NODE = 8 XML_DOCUMENT_NODE = 9 XML_DOCUMENT_TYPE_NODE = 10 XML_DOCUMENT_FRAG_NODE = 11 XML_NOTATION_NODE = 12 XML_HTML_DOCUMENT_NODE = 13 XML_DTD_NODE = 14 XML_ELEMENT_DECL = 15 XML_ATTRIBUTE_DECL = 16 XML_ENTITY_DECL = 17 XML_NAMESPACE_DECL = 18 XML_XINCLUDE_START = 19 XML_XINCLUDE_END = 20 XML_DOCB_DOCUMENT_NODE = 21 9

Węzeł dokumentu - xmldoc Najważniejsze pola składowe struktury _xmldoc xmlelementtype type - XML_DOCUMENT_NODE char * name - nazwa pliku/adres URI dokumentu _xmlnode * children - wskaźnik na pierwsze dziecko _xmldoc * doc - autoreferencja, wskaźnik na samego siebie const xmlchar * version - wersja dokumentu XML const xmlchar * encoding - kodowane dokumentu int properties - zestaw właściwości xmldocproperties 10

Właściwości dokumentu XML xmldocproperties XML_DOC_WELLFORMED = 1 - poprawna składnia XML (well formed) XML_DOC_NSVALID = 2 - poprawna przestrzeń nazw XML_DOC_OLD10 = 4 - dokument parsowany z wykorzystaniem starszej wersji parsera 1.0 XML_DOC_DTDVALID = 8 - poprawna walidacja DTD XML_DOC_XINCLUDE = 16 - wykonane podstawienie XInclude XML_DOC_USERBUILT = 32 - dokument utworzony za pomocą API (nie przez parsowanie XMLa) XML_DOC_INTERNAL = 64 - zbudowany dla wewnętrznego przetwarzania XML_DOC_HTML = 128 - dokument HTML 11

Węzeł atrybutu Najważniejsze pola składowe struktury _xmlattribute xmlelementtype type - XML_ATTRIBUTE_DECL const xmlchar * name - nazwa atrybutu _xmldoc * doc - wskaźnik na węzeł dokumentu _xmlattribute * nexth - wskaźnik na następny atrybut xmlattributetype atype - typ wartości atrybutu xmlattributedefault def - rodzaj wartości domyślniej const xmlchar * defaultvalue - wartość domyślna atrybutu const xmlchar * elem - wartość atrybutu 12

Wartości domyślne i typy atrybutów xmlattributedefault XML_ATTRIBUTE_NONE = 1 - brak wartości domyślniej XML_ATTRIBUTE_REQUIRED = 2 - atrybut wymagany XML_ATTRIBUTE_IMPLIED = 3 - wartość domyślna (używana jeśli brak atrybutu) XML_ATTRIBUTE_FIXED = 4 - wartość ustalona xmlattributetype XML_ATTRIBUTE_CDATA = 1 XML_ATTRIBUTE_ID = 2 XML_ATTRIBUTE_IDREF = 3 XML_ATTRIBUTE_IDREFS = 4 XML_ATTRIBUTE_ENTITY = 5 XML_ATTRIBUTE_ENTITIES = 6 XML_ATTRIBUTE_NMTOKEN = 7 XML_ATTRIBUTE_NMTOKENS = 8 XML_ATTRIBUTE_ENUMERATION = 9 XML_ATTRIBUTE_NOTATION = 10 13

libxml2 Aby rozpoczac przetwarzanie dokumentu XML nalezy: Utworzyć wskaźnik wskazujący na parsowany dokument (węzeł dokumentu). Sprawdzić poprawność parsowania dokumentu. Jednym z częstych błędów jest próba przetworzenia dokumentu wykorzystujacego inne kodowane niż UTF-8, który nie ma jawnie zadeklarowanego kodowania. Jeśli dokument wykorzystuje inne kodowane i posiada poprawna deklaracje dokumentu xml zawierającą kodowane, libxml automatycznie przekształci dokument do UTF-8 i poprawnie wykona parsowanie. Pobrać korzeń dokumentu i sprawdzić czy cokolwiek zawiera (czy dokument nie jest pusty). Rozpocząć przetwarzanie drzewa, np. od sprawdzenia nazwy węzła będącego korzeniem drzewa. 14

libxml2 xmldocptr doc = xmlreadfile(docname); if (doc == NULL ) { std::cerr << "błąd parsowania" << std::endl; return; } xmlnodeptr cur = xmldocgetrootelement(doc); if (cur == NULL) { std::cerr << "dokument pusty" << std::endl; xmlfreedoc(doc); return; } if (xmlstrcmp(cur->name, (const xmlchar *) "story")) { std::cerr << "korzeń dokumentu!= story" << std::endl; xmlfreedoc(doc); return; } 15

libxml2 xmldocptr xmlreaddoc (const xmlchar * cur, const char * URL, const char * encoding, int options) tworzy drzewo na podstawie dokumentu XML przekazanego jako ciąg znaków cur doc = xmlreaddoc(bad_cast "<a></a>", NULL, NULL, 0); xmldocptr xmlreadfile (const char * filename, const char * encoding, int options) tworzy drzewo na podstawie dokumentu XML, którego nazwa lub adres URL jest przekazany jako filename doc = xmlreadfile("http://www.w3schools.com/xml/note.xml", NULL, 0); xmlnodeptr xmldocgetrootelement (xmldocptr doc) pobiera korzeń dokumentu doc->children może zwrócić węzeł będący komentarzem, xmldocgetrootelement pomija komentarze 16

Enum xmlparseroption XML_PARSE_RECOVER = 1 : recover on errors XML_PARSE_NOENT = 2 : substitute entities XML_PARSE_DTDLOAD = 4 : load the external subset XML_PARSE_DTDATTR = 8 : default DTD attributes XML_PARSE_DTDVALID = 16 : validate with the DTD XML_PARSE_NOERROR = 32 : suppress error reports XML_PARSE_NOWARNING = 64 : suppress warning reports XML_PARSE_PEDANTIC = 128 : pedantic error reporting XML_PARSE_NOBLANKS = 256 : remove blank nodes XML_PARSE_SAX1 = 512 : use the SAX1 interface internally XML_PARSE_XINCLUDE = 1024 : Implement XInclude substitition XML_PARSE_NONET = 2048 : Forbid network access XML_PARSE_NODICT = 4096 : Do not reuse the context dictionnary XML_PARSE_NSCLEAN = 8192 : remove redundant namespaces declarations XML_PARSE_NOCDATA = 16384 : merge CDATA as text nodes XML_PARSE_NOXINCNODE = 32768 : do not generate XINCLUDE START/END nodes XML_PARSE_COMPACT = 65536 : compact small text nodes; no modification of the tree allowed afterwards (will possibly crash if you try to modify the tree) XML_PARSE_OLD10 = 131072 : parse using XML-1.0 before update 5 XML_PARSE_NOBASEFIX = 262144 : do not fixup XINCLUDE xml:base uris XML_PARSE_HUGE = 524288 : relax any hardcoded limit from the parser XML_PARSE_OLDSAX = 1048576 : parse using SAX2 interface from before 2.7.0 17

libxml2 xmlchar * xmlstrdup (const xmlchar * cur) tworzy kopię łańcucha znakowego i zwraca wskaźnik do niego int xmlstrlen (const xmlchar * str) zwraca długość łańcucha znakowego int xmlstrcmp (const xmlchar * str1, const xmlchar * str2) porównuje dwa łańcuchy znakowe (const xmlchar*), zwraca 0 jeśli ciągi znakowe są takie same int xmlstrcasecmp (const xmlchar * str1, const xmlchar * str2) porównuje dwa łańcuchy znakowe (const xmlchar*) nie biorąc pod uwagę wielkości znaków xmlchar * xmlstrsub (const xmlchar * str, int start, int len) tworzy nowy łańcuch znaków na podstawie str, rozpoczynając od znaku start o długości len 18

Zwalnianie zasobów void xmlfreedoc (xmldocptr cur) zwolnienie pamięci wykorzystywanej przez struktury tworzące dokument void xmlcleanupparser (void) zwolnienie pamięci wykorzystywanej przez bibliotekę. void xmlfreenode (xmlnodeptr cur) zwolnienie pamięci przydzielonej dla węzła, rekurencyjnie usuwa też wszystkie dzieci węzła. void xmlfreeprop (xmlattrptr cur), void xmlfreeproplist (xmlattrptr cur) zwalnia atrybut (listę atrybutów) oraz pamięć wykorzystywaną przez wartość atrybutu. 19

Dostęp do węzła Dostęp do węzła uzyskiwany jest poprzez przejście przez węzły dokumentu dopóki nie znajdziemy węzła, którego szukamy. cur = cur->xmlchildrennode; while (cur!= NULL) { if (!xmlstrcmp(cur->name, (const xmlchar *)"storyinfo")){ // przetwarzaj węzeł "storyinfo" } cur = cur->next; } 20

Tworzenie dokumentu xmldocptr xmlnewdoc (const xmlchar * version) tworzy nowy dokument version - wersja XMLa 1.0 doc = xmlnewdoc(bad_cast "1.0"); BAD_CAST - makro rzutujące stringa do xmlchar*. Powinno być używane tylko wtedy, kiedy jesteśmy pewni, że jest bezpieczne. xmlnodeptr xmlnewnode (xmlnsptr ns, const xmlchar * name) tworzy nowy element o podanej nazwie, ns jest opcjonalne (NULL) zwraca wskaźnik na utworzony węzeł nazwa nowego węzła jest tworzona za pomocą funkcji xmlstrdup() xmlnodeptr xmldocsetrootelement (xmldocptr doc, xmlnodeptr root) ustawia korzeń dokumentu zwraca stary korzeń jeśli istniał, jeśli nie NULL 21

Tworzenie węzłów xmlnodeptr xmlnewchild (xmlnodeptr parent, xmlnsptr ns, const xmlchar * name, const xmlchar * content) Tworzy nowy element i dodaje go na końcu listy dzieci elementu parent. ns i content to parametry opcjonalne. Jeśli content nie jest pusty tworzony jest węzeł tekstowy dodany jako dziecko nowego węzła. Wartość parametru content jest traktowana jako XML CDATA, co pozwala na wykorzystanie referencji do encji. zwracaany jest wskaźnik na nowo utworzony węzeł xmlnewchild(root_node, NULL, BAD_CAST "node1", BAD_CAST "content of node 1"); 22

Tworzenie atrybutów i węzłów tekstowych xmlattrptr xmlnewprop (xmlnodeptr node, const xmlchar * name, const xmlchar * value) tworzy i zwraca nowy węzeł atrybutu node - węzeł do którego dodawany jest atrybut xmlnodeptr xmlnewtextchild (xmlnodeptr parent, xmlnsptr ns, const xmlchar * name, const xmlchar * content) tworzy nowy węzeł tekstowy i dodaje go na końcu listy dzieci węzła parent. content i ns są opcjonalne content - wartość węzła tekstowego. Znaki specjalne XMLa (&, < itp.) są automatycznie przekształcane do sekwencji unikowych. void xmlnodeaddcontent (xmlnodeptr cur, const xmlchar * content) dodaje tekst (content) do obecnej wartości węzła tekstowego content - dane RAW (możliwe wystąpienie &,< itp) void xmlnodesetcontent (xmlnodeptr cur, const xmlchar * content) ustawia tekst (content) jako wartości węzła tekstowego - content XML CDATA content - dane XML CDATA 23

Dodawanie dzieci xmlnodeptr xmladdchild (xmlnodeptr parent, xmlnodeptr cur) Dodaje nowe dziecko do węzła parent na końcu listy dzieci (jako ostatnie dziecko). Jeśli dodawany węzeł jest atrybutem jest dołączany na końcu listy atrybutów. Jeśli atrybut o takiej nazwie istnieje jest on najpierw usuwany. Jeśli dodawanym węzłem jest węzeł tekstowy jego zawartość jest łączona z już istniejącą w tym miejscu treścią. Węzeł cur jest zwalniany. xmlnodeptr xmladdchildlist (xmlnodeptr parent, xmlnodeptr cur) Dodaje listę węzłów na końcu listy dzieci rodzica łącząc przyległe węzły tekstowe (węzeł cur może być zwolniony jeśli jest węzłem tekstowym) 24

Dodawanie rodzeństwa xmlnodeptr xmladdnextsibling (xmlnodeptr cur, xmlnodeptr elem) Dodaje nowy węzeł (elem) jako następne rodzeństwo (next sibling) węzła cur. xmlnodeptr xmladdprevsibling (xmlnodeptr cur, xmlnodeptr elem) Dodaje nowy węzeł jako poprzednie rodzeństwo Podczas dodawania rodzeństwa obowiązują następujące zasady: Jeśli węzeł istniał wcześniej w dokumencie jest najpierw odłączany od dokumentu (unlink). Jeśli węzeł elem jest typu tekstowego może zostać połączony z innym węzłem i w rezultacie zwolniony. Jeśli węzeł elem jest atrybutem jest dodawany do do listy atrybutów. Jeśli atrybut o podanej nazwie istnieje jest on najpierw niszczony. 25

libxml2 - przydatne funkcje unsigned long xmlchildelementcount (xmlnodeptr parent) zwraca liczbę dzieci węzła, które są węzłami elementu. xmlnodeptr xmlfirstelementchild (xmlnodeptr parent) zwraca pierwsze dziecko będące typu element xmlnodeptr xmlgetlastchild (xmlnodeptr parent) zwraca ostatnie dziecko węzła parent xmldocptr xmlcopydoc (xmldocptr doc, int recursive) tworzy kopię informacji o drzewie. Jeśli recursive jest różne od zera kopia wykonywana jest rekursywnie. xmlnodeptr xmlcopynode (const xmlnodeptr node, int extended) tworzy kopię węzła, extended == 1 - kopia rekursywna obejmująca atrybuty, przestrzenie nazw i dzieci extended == 2 - kopia węzła razem z atrybutami i przestrzenie nazw xmlattrptr xmlcopyprop (xmlnodeptr target, xmlattrptr cur) tworzy kopię atrybutu cur target - element, do którego atrybut jest dodawany 26

libxml2 - przydatne funkcje unsigned long xmlchildelementcount (xmlnodeptr parent) zwraca liczbę dzieci węzła, które są węzłami elementu. xmlnodeptr xmlfirstelementchild (xmlnodeptr parent) zwraca pierwsze dziecko będące typu element xmlnodeptr xmlgetlastchild (xmlnodeptr parent) zwraca ostatnie dziecko węzła parent xmldocptr xmlcopydoc (xmldocptr doc, int recursive) tworzy kopię informacji o drzewie. Jeśli recursive jest różne od zera kopia wykonywana jest rekursywnie. xmlnodeptr xmlcopynode (const xmlnodeptr node, int extended) tworzy kopię węzła, extended == 1 - kopia rekursywna obejmująca atrybuty, przestrzenie nazw i dzieci extended == 2 - kopia węzła razem z atrybutami i przestrzenie nazw xmlattrptr xmlcopyprop (xmlnodeptr target, xmlattrptr cur) tworzy kopię atrybutu cur target - element, do którego atrybut jest dodawany 27

Zapis drzewa int xmldocformatdump (FILE * f, xmldocptr cur, int format) zrzuca dokument do pliku (lub na standardowe wyjście) format == 1 - dodawane są znaki formatujące (koniec linii, spacje itp) zapis na standardowe wyjście: xmldocformatdump(stdout, doc, 1); zapis do pliku: FILE *fd = fopen ("doc.xml", "wt"); xmldocformatdump(fd, doc, 1); 28

libxml2 i XPath 29

libxml2 i xpath LibXML2 pozwala na wykorzystanie wyrażeń XPath do uzyskiwania dostępu do węzłów. XPath pozwala wybrać z dokumentu XML zbiór węzłów, które spełniają określone kryteria. Aby używać XPath należy utworzyć kontekst xmlxpathcontext i przekazać wyrażenie XPath oraz kontekst do funkcji xmlxpathevalexpression. Funkcja xmlxpathevalexpression zwraca wskaźnik na xmlxpathobject (xmlxpathobjectptr), który zawiera zbiór węzłów spełniających kryteria wyrażenia XPath. Aby używać XPath należy dołączyć pliki nagłówkowe <libxml/xpath.h> oraz <libxml/xpathinternals.h> 30

libxml2 i XPath xmldocptr doc = xmlreadfile("http://...", NULL, 0); // utworzenie kontekstu xmlxpathcontextptr context = xmlxpathnewcontext(doc); // pobranie węzłów zspełniających kryteria XPath xmlxpathobjectptr result = xmlxpathevalexpression(xpath, context); // jeśli zbiór elementów jest pusty zwalniamy pamięć if (xmlxpathnodesetisempty(result->nodesetval)){ } xmlxpathfreeobject(result); printf("no result\n"); Po zakończeniu przetwarzania dokumentu XML należy zwolnić kontekst za pomocą funkcji xmlxpathfreecontext(context) 31

Struktura xmlxpathobject Wskaźnik na xmlxpathobject zwrócony przez funkcję xmlxpathevalexpression zawiera zbiór węzłów i informacje potrzebne do przejścia po tych węzłach. Najważniejsze pola składowe struktury xmlxpathobject: xmlxpathobjecttype type - typ obiektu xmlnodesetptr nodesetval - wskaźnik na zbiór węzłów Po zakończeniu przetwarzania instancja struktury xmlxpathobject powinna zostać usunięta za pomocą funkcji xmlxpathfreeobject. 32

Typ obiektów xmlxpathobject Typ obiektu xmlxpath - typ wyliczeniowy xmlxpathobjecttype XPATH_UNDEFINED = 0 XPATH_NODESET = 1 XPATH_BOOLEAN = 2 XPATH_NUMBER = 3 XPATH_STRING = 4 XPATH_POINT = 5 XPATH_RANGE = 6 XPATH_LOCATIONSET = 7 XPATH_USERS = 8 XPATH_XSLT_TREE = 9 33

Zestaw węzłów xmlnodeset Obiekt xmlxpathobject zawiera wskaźnik na zestaw węzłów xmlnodeset (xmlnodesetptr). Są to węzły, które spełniają kryterium XPath. Pola składowe struktury xmlnodeset: int nodenr - liczba węzłów w zbiorze int nodemax - wielkość zaalokowanej pamięci xmlnodeptr * nodetab - tablica węzłów - nieuporządkowana (wskaźnik na pierwszy element tablicy) 34

Zestaw węzłów xmlnodeset if (xpathobj->nodesetval == NULL) { printf("coś poszło nie tak... :( "); return 0; } for (int i=0; i < xpathobj->nodesetval->nodenr; i++) { xmlnodeptr child = xpathobj->nodesetval->nodetab[i]->xmlchildrennode; const xmlchar * str = xmlnodelistgetstring(doc, child, 1); printf("str: %s\n", str); xmlfree((void*)str); } 35

xmlnodelistgetstring xmlchar * xmlnodelistgetstring (xmldocptr doc, xmlnodeptr list, int inline) Tworzy ciąg znakowy równy tekstowi zawartemu we wszystkich węzłach należących do listy węzłów. doc - węzeł dokumentu list - lista węzłów inline - czy zastępować encje Wartość zwracana przez funkcję to wskaźnik na kopię ciągu znakowego - wskaźnik ten musi zostać zwolniony za pomocą funkcji xmlfree(). Funkcja wywołana dla pola składowego xmlchildrennode węzła a dla dokumentu <a> x <b/> y <c/> z </a> zwróci wartość xyz. 36

Wywołanie zwrotne - callback 37

Wywołanie zwrotne - callback Technika programowania (wzorzec programowania) będąca odwrotnością wywołania funkcji. Zasada działania: Referencja do funkcji A jest przekazywana do funkcji B, najczęściej wywoływanej na osobnym wątku. Wątek główny nadal kontynuuje swoją pracę, w czasie gdy funkcja B działa niezależnie od niego. Gdy funkcja B zakończy swoje działanie, wywołuje funkcję A zwracając rezultat swojego działania. 38

Wywołanie zwrotne 39

Wywołanie zwrotne w językach obiektowych W językach obiektowych do funkcji przekazywany jest wskaźnik na obiekt, a czasami również nazwa metody, która ma być wywołana na rzecz tego obiektu jako wywołanie zwrotne. Przed wywołaniem funkcji powinno się sprawdzić czy obiekt, na rzecz którego wywoływana jest metoda nadal istnieje i czy udostępnia odpowiednią metodę! Interfejsy - mechanizm gwarantujący, że przekazany obiekt udostępnia wymaganą metodę. 40

Wywołanie zwrotne w językach obiektowych Klasa A: void fun(){ B b; b.dosomething(this, didfinishdoing ); Klasa B: } /* kontynuuj wykonywanie innych operacji */... /**************************************************************/ void didfinishdoing(resulttype result) { } /* wynik działania funkcji dosomething to result - możemy go np. zapisać do bazy lub pokazać użytkownikowi */ callback void dosomething(object obj, string method){ } // wykonaj czasochłonną operację resulttype res =... /* wykonaj wywołanie zwrotne i przekaż do metody method wynik znajdujący się w zmiennej res */ obj. callmethod[method](res); 41

SAX w libxml2 42

SAX - jak to działa. <?xml version="1.0"?> <doc> <para>hello, world!</para> </doc> Podczas przetwarzania dokumentu zgłoszone zostaną zdarzenia: 1. start document 2. start element: doc 3. start element: para 4. characters: Hello, world! 5. end element: para 6. end element: doc 7. end document 43

Rozpoczęcie parsowania dokumentu int xmlsaxuserparsefile(xmlsaxhandlerptr sax, void * user_data, const char * filename); int xmlsaxuserparsememory(xmlsaxhandlerptr sax, void * user_data, char * buffer, int size); sax - SAX handler, instancja struktury przechowująca wskaźniki na funkcje user_data - dane użytkownika przekazywane do funkcji podczas wywołań zwrotnych (callback) filename - nazwa pliku buffer - dokument XML size - długość dokumentu XML (w bajtach) Funkcje zwracają 0 jeśli operacja się powiedzie, w przeciwnym razie kod błędu. 44

Dane użytkownika user_data - dane użytkownika przekazywane do funkcji podczas wywołań zwrotnych (callback) Wskaźnik na obiekt (strukturę), w którym przechowywany jest stan parsera oraz dane odczytane z dokumentu XML. Wskaźnik ten jest przekazywany za każdym razem kiedy parser wywołuje funkcję za pomocą wywołania zwrotnego, dzięki czemu możemy zapisać dane związane z napotkanym zdarzeniem oraz aktualną pozycję w dokumencie XML (wewnątrz jakiego znacznika jesteśmy). 45

xmlsaxhandler Struktura xmlsaxhandler zawiera wskaźniki na metody, które będą wykonane w momencie wystąpienia zdarzenia - napotkania odpowiedniego elementu w dokumencie XML. Jeśli zdarzenia mają nie być obsługiwane wskaźnikom na funkcje można przypisać wartość NULL. 46

xmlsaxhandler - funkcje internalsubsetsaxfunc internalsubset; isstandalonesaxfunc isstandalone; hasinternalsubsetsaxfunc hasinternalsubset; hasexternalsubsetsaxfunc hasexternalsubset; resolveentitysaxfunc resolveentity; getentitysaxfunc getentity; entitydeclsaxfunc entitydecl; notationdeclsaxfunc notationdecl; attributedeclsaxfunc attributedecl; elementdeclsaxfunc elementdecl; unparsedentitydeclsaxfunc unparsedentitydecl; setdocumentlocatorsaxfunc setdocumentlocator; startdocumentsaxfunc startdocument; enddocumentsaxfunc enddocument; startelementsaxfunc startelement; endelementsaxfunc endelement; referencesaxfunc reference; characterssaxfunc characters; ignorablewhitespacesaxfunc ignorablewhitespace; processinginstructionsaxfunc processinginstruction; commentsaxfunc comment; warningsaxfunc warning; errorsaxfunc error; fatalerrorsaxfunc fatalerror; 47

Funkcje inicjujące i finalizujące startdocumentsaxfunc void startdocumentsaxfunc (void * ctx) ctx - kontekst parsera enddocumentsaxfunc void enddocumentsaxfunc (void * ctx) ctx - kontekst parsera Funkcje te są najczęściej wykorzystywane do zainicjowania struktur, w których będą przechowywane dane oraz zwolnienia zasobów. 48

Funkcje przetwarzające dane startelementsaxfunc void startelementsaxfunc (void * ctx, const xmlchar * name, const xmlchar ** atts) ctx - kontekst parsera ch - nazwa znacznika atts - tablica par nazwa/wartość zakończona wartością NULL endelementsaxfunc void endelementsaxfunc (void * ctx, const xmlchar * name) ctx - kontekst parsera ch - nazwa znacznika characterssaxfunc void characterssaxfunc (void * ctx, const xmlchar * ch, int len) ctx - kontekst parsera ch - string xmlchar len - liczba znaków 49

Odczyt nazw elementów XML class Fun{ public: static void startf (void * ctx, const xmlchar * name, const xmlchar ** atts) { } ((std::vector<const xmlchar *> *)ctx)->push_back(name); }; int main (int argc, const char * argv[]) { } xmlsaxhandler handler = {0}; handler.startelement = Fun::startF; std::vector<const xmlchar *> * v = new std::vector<const xmlchar *>(0); xmlsaxuserparsefile(&handler, v, "http://icis.pcz.pl/~wawszczak/tzt/przedszkole.xml"); for (int i =0; i<v->size(); ++i) std::cout<< (*v)[i] << std::endl; delete v; return 0; 50

Odczyt wartości elementów tekstowych class Fun { public: static void charactersf (void * ctx, const xmlchar * ch, int len) { ((std::vector<std::string> *)ctx)->push_back(std::string((char*)ch, len)); } }; int main (int argc, const char * argv[]) { xmlsaxhandler handler = {0}; handler.characters = Fun::charactersF; std::vector<std::string> * v = new std::vector<std::string>(0); xmlsaxuserparsefile(&handler, v, "http://icis.pcz.pl/~wawszczak/tzt/przedszkole.xml"); for (int i =0; i<v->size(); ++i) std::cout<< (*v)[i] << std::endl; return 0; } 51

Odczyt wartości elementów tekstowych class B{ public: bool insideimie; std::vector<std::string> v; B() { v = std::vector<std::string>(0); } }; class Fun{ public: static void startf (void * ctx, const xmlchar * name, const xmlchar ** atts) { if (xmlstrcmp(name, BAD_CAST"imie") == 0) ((B*)ctx)->insideImie=true; } static void endf (void * ctx, const xmlchar * name) { if (xmlstrcmp(name, BAD_CAST"imie") == 0) ((B*)ctx)->insideImie=false; } static void charactersf (void * ctx, const xmlchar * ch, int len) { if (((B*)ctx)->insideImie) ((B*)ctx)->v.push_back(std::string((char*)ch, len)); } }; int main (int argc, const char * argv[]){ xmlsaxhandler handler = {0}; handler.startelement = Fun::startF; handler.endelement = Fun::endF; handler.characters = Fun::charactersF; B * b = new B(); xmlsaxuserparsefile(&handler, b, "http://icis.pcz.pl/~wawszczak/tzt/przedszkole.xml"); for(int i =0; i<b->v.size(); ++i) std::cout<< b->v[i] << std::endl; delete b; return 0; } 52

Odczyt wartości elementów tekstowych class B{ public: bool insideimie; std::vector<std::string> v; B() { v = std::vector<std::string>(0); } }; class Fun{ public: static void startf (void * ctx, const xmlchar * name, const xmlchar ** atts) { if (xmlstrcmp(name, BAD_CAST"imie") == 0) ((B*)ctx)->insideImie=true; } static void endf (void * ctx, const xmlchar * name) { if (xmlstrcmp(name, BAD_CAST"imie") == 0) ((B*)ctx)->insideImie=false; } static void charactersf (void * ctx, const xmlchar * ch, int len) { if (((B*)ctx)->insideImie) ((B*)ctx)->v.push_back(std::string((char*)ch, len)); } }; int main (int argc, const char * argv[]){ xmlsaxhandler handler = {0}; handler.startelement = Fun::startF; handler.endelement = Fun::endF; handler.characters = Fun::charactersF; B * b = new B(); xmlsaxuserparsefile(&handler, b, "http://icis.pcz.pl/~wawszczak/tzt/przedszkole.xml"); for(int i =0; i<b->v.size(); ++i) std::cout<< b->v[i] << std::endl; delete b; return 0; } 53

Odczyt wartości elementów tekstowych class B{ public: bool insideimie; std::vector<std::string> v; B() { v = std::vector<std::string>(0); } }; class Fun{ public: static void startf (void * ctx, const xmlchar * name, const xmlchar ** atts) { if (xmlstrcmp(name, BAD_CAST"imie") == 0) ((B*)ctx)->insideImie=true; } static void endf (void * ctx, const xmlchar * name) { if (xmlstrcmp(name, BAD_CAST"imie") == 0) ((B*)ctx)->insideImie=false; } static void charactersf (void * ctx, const xmlchar * ch, int len) { if (((B*)ctx)->insideImie) ((B*)ctx)->v.push_back(std::string((char*)ch, len)); } }; int main (int argc, const char * argv[]){ xmlsaxhandler handler = {0}; handler.startelement = Fun::startF; handler.endelement = Fun::endF; handler.characters = Fun::charactersF; B * b = new B(); xmlsaxuserparsefile(&handler, b, "http://icis.pcz.pl/~wawszczak/tzt/przedszkole.xml"); for(int i =0; i<b->v.size(); ++i) std::cout<< b->v[i] << std::endl; delete b; return 0; } 54

libxml2 Podstawowe API - bazujące na drzewie DOM - wynik parsowania w całości ładowany do pamięci; proste w użyciu, ale nie pozwala na przetwarzanie bardzo dużych dokumentów. API sterowane zdarzeniami - skomplikowane w użyciu, nie jest w pełni formalnie zdefiniowane dla języka C, nie pozwala na walidację dokumentu XML XmlTextReader - łatwy i wydajny! 55

XmlTextReader XmlTextReader API zapewnia znacznie prostszy model programowania. XmlTextReader zachowuje się jak kursor, który przesuwa się do przodu po strumieniu dokumentu zatrzymując się na każdym węźle, który napotka. Użytkownik kontroluje przebieg procesu parsowania i wywołuje funkcję xmltextreaderread() w celu przetworzenia kolejnego węzła w kolejności w jakiej występują w dokumencie. 56

Przejście przez drzewo dokumentu XmlTextReader API pozwala na przejście przez drzewo tylko do przodu. Przetwarzanie XMLa odbywa się w następujących krokach: przygotowanie kontekstu czytnika (kursora) działającego na określonym wejściu, iteracyjne (w pętli) przejście po wszystkich węzłach w dokumencie i odczytanie ich za pomocą funkcji xmltextreaderread(), zwolnienie kontekstu. 57

Przetwarzanie drzewa XmlTextReader #include <libxml/xmlreader.h> void processnode(xmltextreaderptr reader) { /*... */ } int streamfile(char *filename) { xmltextreaderptr reader = xmlnewtextreaderfilename(filename); } if (reader!= NULL) { int ret = xmltextreaderread(reader); while (ret == 1) { processnode(reader); ret = xmltextreaderread(reader); } xmlfreetextreader(reader); if (ret!= 0) printf("%s : failed to parse\n", filename); } else printf("unable to open %s\n", filename); 58

Tworzenie kontekstu i zwalnianie pamięci xmltextreaderptr xmlnewtextreaderfilename (const char * URI) utworzenie kontekstu dla dokumentu XML przekazanego jako adres URI xmltextreaderptr xmlreaderfordoc (const xmlchar * cur, const char * URL, const char * encoding, int options) utworzenie kontekstu dla dokumentu XML przekazanego ciąg znaków xmltextreaderptr xmlnewtextreader (xmlparserinputbufferptr input, const char * URI) utworzenie kontekstu dla dokumentu XML przekazanego jako bufor wejściowy void xmlfreetextreader (xmltextreaderptr reader) zwolnienie pamięci wykorzystywanej przez kontekst parsera 59

Dostęp do węzła i odczyt jego wartości int xmltextreaderread (xmltextreaderptr reader) Przesuwa pozycję kursora do następnego węzła w strumieniu. Wartość zwracana: 1 - poprawny odczyt 0 - nie ma więcej węzłów -1 - wystąpienie błędu xmlchar * xmltextreaderreadstring (xmltextreaderptr reader) odczyt wartości tekstowej danego węzła 60

Dostęp do informacji dotyczących bieżącego węzła Dostęp do właściwości węzła możliwy jest za pomocą funkcji przyjmujących wskaźnik na xmltextreaderptr. Jeśli typem zwracanym przez funkcję jest ciąg znaków xmlchar *, pamięć musi zostać zwolniona za pomocą xmlfree(). xmlchar * name = xmltextreadername(reader); 61

Typ węzła int xmltextreadernodetype (xmltextreaderptr reader) 1 - początek elementu (znacznik otwierający), 15 - koniec elementy (znacznik zamykający), 2 - atrybut, 3 - węzeł tekstowy, 4 - sekcja CData, 5 - referencja do encji, 6 - deklaracja encji, 7 - instrukcja przetwarzania, 8 - komentarz, 9 - węzeł dokumentu, 10 - węzeł typu dokumentu DTD. 62

Nazwa węzła xmlchar * xmltextreadername (xmltextreaderptr reader) const xmlchar * xmltextreaderconstname (xmltextreaderptr reader) kwalifikowana nazwa węzła xmlchar * xmltextreaderlocalname (xmltextreaderptr reader) const xmlchar * xmltextreaderconstlocalname (xmltextreaderptr reader) lokalna nazwa węzła Różnica pomiędzy funkcjami Const i nie Const??? 63

Nazwa węzła xmlchar * xmltextreadername (xmltextreaderptr reader) const xmlchar * xmltextreaderconstname (xmltextreaderptr reader) kwalifikowana nazwa węzła xmlchar * xmltextreaderlocalname (xmltextreaderptr reader) const xmlchar * xmltextreaderconstlocalname (xmltextreaderptr reader) lokalna nazwa węzła W przypadku funkcji Const pamięć jest zwalniana przez parser, w przeciwnym przypadku musi zostać zwolniona przez użytkownika. 64

Odczyt informacji o węźle int xmltextreaderhasattributes (xmltextreaderptr reader) sprawdzenie czy węzeł ma atrybuty int xmltextreaderhasvalue (xmltextreaderptr reader) sprawdzenie czy węzeł ma wartość int xmltextreaderisemptyelement (xmltextreaderptr reader) sprawdzenie czy węzeł jest węzłem pustym Wartość zwracana: 1 - TAK 0 - NIE -1 - błąd 65

Odczyt wartości węzła xmlchar * xmltextreadervalue (xmltextreaderptr reader) const xmlchar * xmltextreaderconstvalue (xmltextreaderptr reader) zwraca wartość węzła jako ciąg znaków będący kopią lub jako stały ciąg znaków. 66

Odczyt atrybutów int xmltextreaderattributecount (xmltextreaderptr reader) zwraca liczbę atrybutów xmlchar * xmltextreadergetattribute (xmltextreaderptr reader, const xmlchar * name) zwraca wartość atrybutu o podanej nazwie xmlchar * xmltextreadergetattributeno (xmltextreaderptr reader, int no) zwraca wartość atrybutu numer no 67

Odczyt atrybutów int xmltextreadermovetofirstattribute (xmltextreaderptr reader) przejście do pierwszego atrybutu int xmltextreadermovetonextattribute (xmltextreaderptr reader) przejście do następnego atrybutu int xmltextreadermovetoattribute (xmltextreaderptr reader, const xmlchar * name) przejście do atrybutu o nazwie name int xmltextreadermovetoattributeno (xmltextreaderptr reader, int no) przejście do atrybutu o numerze no int xmltextreadermovetoelement (xmltextreaderptr reader) przesuniecie kursora do węzła elementu Zwracana wartość: 1 - OK, 0 - jeśli nie znaleziono węzła, -1 - w przypadku błędu. 68

xmltextreader + DOM xmlnodeptr xmltextreaderexpand (xmltextreaderptr reader) Odczytuje bieżący węzeł i całe poddrzewo tego węzła. Zwraca wskaźnik na xmlnode lub NULL jeśli wystąpił błąd Drzewo jest dostępne do następnego wywołanie xmltextreaderread() 69

Funkcje zwracające obiekty const cout << xmltextreadername(reader) << endl; 70

Funkcje zwracające obiekty const cout << xmltextreadername(reader) << endl; Wyciek pamięci! 71

Funkcje zwracające obiekty const xmlchar * name = xmltextreadername(reader); cout << name << endl; xmlfree(name); lub: cout<<xmltextreaderconstname(reader)<<endl; 72