/** ******************************************************************************* @file /common/xml/xml.h @brief Zaklady uchovavani XML dat @author Vta @version 0.1 ******************************************************************************/ // K prelozeni // - pripojit knihovnu libexpat.lib // Specialni znaky v xml souborech: // Znak Znacka // < < // > > // & & #ifndef XML #define XML #include #include #include #include #include #include #include "common/da.h" #include "common/Log.h" #include "common/priority.h" #include "common/types.h" #include "common/xml/strda.h" #include "common/xml/myhash.h" #ifndef WIN32 #define _wtoi(a) (int)wcstol(a, 0, 10) ///< Vyreseni absence wtoi() v Linuxu #endif typedef struct container xmlcontainer; ///< Jednoduche pojmenovani typu kvuli zprehledneni typedef struct containersmall xmlcontainersmall; ///< Jednoduche pojmenovani typu kvuli zprehledneni typedef struct interior xmlinterior; ///< Jednoduche pojmenovani typu kvuli zprehledneni typedef struct memory xmlmemory; ///< Jednoduche pojmenovani typu kvuli zprehledneni typedef int (*lookThroughHandler) (void *data,xmlcontainer * xml,int depth,int id); ///< Funkce pristupujici k obsahu tagu typedef int (*lookThroughHandlerAccess) (void *data,xmlcontainer ** xml,int depth,int id); ///< Funkce pristupujici ke strukture v niz je xml ulozene #define XML_ERROR_WRONG_INPUT -2 ///< Syntakticka chyba v xml #define XML_ERROR_FILE_IS_MISSING -3 ///< Nenalezen soubor, ktery se ma nacitat // #define XML_ERROR_DTD_MISSING -4 // Chybi dtd, neni fatalni chyba - lze nastavit pozdeji, pred ulozenim #define XML_ERROR_CANNOT_CREATE_FILE -5 ///< Nelze vytvorit soubor pri zapisu #define XML_ERROR_NO_SUCH_A_PATH -1 ///< Pozadovany soubor neexistuje #define XML_ERROR_INVALID_INDEX -6 ///< Index nejakeho prvku je mensi nez 0 #define XML_ERROR_OK 0 ///< XML je v poradku #define NULL_PARENTS 0 ///< Zda-li chci udrzovat obsahy "nelistovych" tagu #define BUFF_INT_TO_STR 100 ///< velikost bufferu pro prevod cisel na retezce /** Trida schopna udrzet XML data v jejich strukturovane podobe. */ class TXMLdata // CLSDBG1 { public: /** Konstruktor. @param imp roven 1 urcuje, ze v dokumentu mam ukladat veskera data. Pri 0 jen vyznamova. @param fo pokud je fo nastaveno na 1, poradi xml tagu bude v souboru presne v poradi, v jakem se do tridy TXMLdata vlozily. */ TXMLdata(int imp=1,int fo=0); // konstruktor, imp je importance ~TXMLdata(); ///< Destruktor /** @name Vlozeni obsahu jednoho tagu */ //@{ /** Nastavi obsah tagu daneho cestou, vraci 0. Posledni parametr musi byt NULL, strida se vzdy tag a jeho id. @param data2 vlastni data @param firsttag prvni nekorenovy tag na ceste k mistu kam se vklada @param firstid id prvniho nekorenoveho tagu na ceste k mistu kam se vklada */ void setData(const char * data2,char * firsttag,int firstid,...); /** Ulozi data, tags je DA s celou cestou a ids jsou prislusne id tagu, vraci 0. @param data2 vlastni obsah @param ids id tagu po ceste k mistu vlozeni @param tags jmena tagu po ceste k mistu vlozeni bez korenoveho tagu K8 @param onlyleaf zda vlozit hodnotu jen pokud je dany uzel list */ void setData(const char * data2,DA *ids,DA* tags, int onlyleaf); /** Ulozi data, tags je pole s celou cestou a ids jsou prislusne id tagu, vraci 0. @param data2 vlastni obsah @param ids id tagu po ceste k mistu vlozeni @param tags jmena tagu po ceste k mistu vlozeni bez korenoveho tagu K8 @param number pocet tagu v poli tags (delka cesty bez korenoveho tagu) @param onlyleaf zda vlozit hodnotu jen pokud je dany uzel list */ void setData(const char * data2,int *ids,char **tags, int number, int onlyleaf); /** Nastavi data zadana v podobe cisla (pro uchovavani ve strukture budou prevedane na char), vraci 0. Posledni parametr musi byt NULL, strida se vzdy tag a jeho id. @param data2 vlastni data @param firsttag prvni nekorenovy tag na ceste k mistu kam se vklada @param firstid id prvniho nekorenoveho tagu na ceste k mistu kam se vklada */ void setDataInt(const int data2,char * firsttag,int firstid,...); /** Nastavi data zadana v podobe double (pro uchovavani ve strukture budou prevedane na char), vraci 0. Posledni parametr musi byt NULL, strida se vzdy tag a jeho id. @param data2 vlastni data @param firsttag prvni nekorenovy tag na ceste k mistu kam se vklada @param firstid id prvniho nekorenoveho tagu na ceste k mistu kam se vklada */ void setDataDouble(const double data2,char * firsttag,int firstid,...); //@} /** @name Ziskani obsahu jednoho tagu */ //@{ /** Ziska obsah tagu v podobe retezce. Posledni parametr musi byt NULL, strida se vzdy tag a jeho id. @param data2 budou obsahovat vysledek dotazu, bude vzdy ukoncen 0 @param size velikost pole data2 @param firsttag prvni nekorenovy tag na ceste k mistu kam se vklada @param firstid id prvniho nekorenoveho tagu na ceste k mistu kam se vklada @return Vraci \ref XML_ERROR_NO_SUCH_A_PATH pokud cesta neexistuje, jinak delku obsahu tagu (nezavisle na size) bez koncove 0 */ int getData(char * data2,int size, char * firsttag,int firstid,...); /** Ziska cely obsah tagu v podobe retezce. Posledni parametr musi byt NULL, strida se vzdy tag a jeho id. @param data2 budou obsahovat cely vysledek dotazu, bude vzdy ukoncen 0. V pripade potreby muze dojit k realokaci. @param size puvodni velikost pole data2 @param firsttag prvni nekorenovy tag na ceste k mistu kam se vklada @param firstid id prvniho nekorenoveho tagu na ceste k mistu kam se vklada @return Vraci \ref XML_ERROR_NO_SUCH_A_PATH pokud cesta neexistuje, jinak delku obsahu tagu (nezavisle na size) bez koncove 0 */ int getDataResize(char ** data2,size_t &size, char * firsttag,int firstid,...); /** Ziska obsah tagu prevedeny na int. Posledni parametr musi byt NULL, strida se vzdy tag a jeho id. Vraci XML_ERROR_NO_SUCH_A_PATH pokud cesta neexistuje, jinak prevedeny obsah na cislo @param firsttag prvni nekorenovy tag na ceste k mistu kam se vklada @param firstid id prvniho nekorenoveho tagu na ceste k mistu kam se vklada @return Vraci \ref XML_ERROR_NO_SUCH_A_PATH pokud cesta neexistuje, jinak obsahu tagu prevedeny na int */ int getDataInt(char * firsttag,int firstid,...); /** Ziska obsah tagu prevedeny na realne cislo. Posledni parametr musi byt NULL, strida se vzdy tag a jeho id. Vraci XML_ERROR_NO_SUCH_A_PATH pokud cesta neexistuje, jinak prevedeny obsah na realne cislo @param firsttag prvni nekorenovy tag na ceste k mistu kam se vklada @param firstid id prvniho nekorenoveho tagu na ceste k mistu kam se vklada @return Vraci \ref XML_ERROR_NO_SUCH_A_PATH pokud cesta neexistuje, jinak obsahu tagu prevedeny na int */ double getDataDouble(char * firsttag,int firstid,...); /** Ziska obsah tagu v podobe retezce. @param data2 budou obsahovat cely vysledek dotazu, bude vzdy ukoncen 0. V pripade potreby muze dojit k realokaci. @param size velikost pole data2 @param ids pole id jednotlivych tagu @param tags cesta k pozadovanemu obsahu @param number delka cesty bez korenoveho tagu (take pocet prvku pole tags a ids) @return Vraci \ref XML_ERROR_NO_SUCH_A_PATH pokud cesta neexistuje, jinak delku obsahu tagu (nezavisle na size) */ int getData(char * data2,int size,int *ids,char ** tags, int number); /** Ziska okaz primo na data ulozena v xml. Tato funkce se musi pouzivat s opatrnosti pouze na cteni dat. Posledni parametr musi byt NULL. @param firsttag prvni nekorenovy tag na ceste k mistu kam se vklada @param firstid id prvniho nekorenoveho tagu na ceste k mistu kam se vklada @return Vraci NULL pokud cesta neexistuje, jinak obsah tagu */ char * getDataRaw(char * firsttag,int firstid,...); //@} /** @name Smazani dat */ //@{ /** Smaze tag dany cestou a vse co obsahuje (vcetne subtagu). Posledni parametr musi byt NULL. Operace delete je casove narocnejsi oproti vkladani nebo cteni. @param ifempty pokud se ma mazat jen kdyz je prazdny @param firsttag prvni nekorenovy tag na ceste k mistu kam se vklada @param firstid id prvniho nekorenoveho tagu na ceste k mistu kam se vklada @return Vraci \ref XML_ERROR_OK pokud se akce povedla jinak \ref XML_ERROR_NO_SUCH_A_PATH */ int delData(int ifempty,char * firsttag,int firstid,...); /** Smaze tag dany cestou a vse co obsahuje (vcetne subtagu). Operace delete je casove narocnejsi oproti vkladani nebo cteni. @param ifempty pokud se ma mazat jen kdyz je prazdny @param ids pole id jednotlivych tagu @param tags cesta k pozadovanemu obsahu @param number delka cesty bez korenoveho tagu (take pocet prvku pole tags a ids) @return Vraci \ref XML_ERROR_OK pokud se akce povedla jinak \ref XML_ERROR_NO_SUCH_A_PATH */ int delData(int ifempty,int * ids, char ** tags,int number); //@} /** @name Vlozeni dat z XML */ //@{ /** Nacte soubor a zachova strukturu. @param file jmeno souboru, ktery se nacte @return nektera hodnota z \ref XML_ERROR_OK, \ref XML_ERROR_WRONG_INPUT, \ref XML_ERROR_FILE_IS_MISSING */ int readFile(const char * file); /** Nacte "hlavicku" souboru a zachova strukturu. Hlavicku tvori jista podmnozina tagu, parsovani konci ve chvili, kdy se nalezne ukoncujici tag se jmenem, ktere udava stop @param file jmeno souboru, ktery se nacte @param stop po kterem tagu skonci parsovani @return nektera hodnota z \ref XML_ERROR_OK, \ref XML_ERROR_WRONG_INPUT, \ref XML_ERROR_FILE_IS_MISSING */ int readFile(const char * file,const char * stop); /** Nacte retezec, ktery obsahuje XML @param input Vstupni data @return nektera hodnota z \ref XML_ERROR_OK, \ref XML_ERROR_WRONG_INPUT */ int readChar(char * input); //@} /** @name Vraceni dat v podobe XML */ //@{ /** Zapise strukturu do souboru. @param file jmeno souboru @return XML_ERROR_OK v pripade uspechu jinak XML_ERROR_CANNOT_CREATE_FILE */ int saveToFile(const char * file); /** Prevede strukturu do retezce. Vlozi radkovani a mezery do dat tak, aby pri vypsani retezce na obrazovku byl obsah snadno citelny. @param output retezec, kam se data vlozi @param size velikost pole output @return Pocet znaku v output */ int toNiceXML(char * output,int size); /** Prevede strukturu do pole znaku a vlozi radkovani, aby to xml bylo lepe citelne pro uzivatele. @param output pole, kam se data vlozi */ int toNiceXML(DA * output); /** Prevede strukturu do retezce. @param output retezec, kam se data vlozi @param size velikost pole output @return Pocet znaku v output */ int toXML(char * output,int size); /** Prevede strukturu do pole znaku. @param output pole, kam se data vlozi */ int toXML(DA * output); //@} /** @name Ziskani dat resp. pouzitych id u tagu, splnujici nejakou podminku */ //@{ /** Ziska pole textu, kde v poli ids na indexu "id" bude obsah tagu s timto indexem. @param ids data @return maxId tj. nejvetsi pouzity index. */ int getListOfData(DA * ids); /** Ziska pole indexu (id), takze v pole[id] bude 0, pokud se nekde v XML objevuje tag s timto indexem @param ids indexy @return Nejvetsi pouzity index u synu korene */ int getListOfIds(DA * ids); /** Naplni ids tak, ze ids[i]==1 pokud nejaky subtag od tagu specifikovaneho cestou ma id==i, jinak 0. V ceste se strida jmeno tagu a jeho id. Posledni parametr musi byt NULL. Pokud firsttag je NULL, chape se to jako dotaz na koren. @param ids indexy @param firsttag jmeno prvniho nekorenoveho tagu @param firstid id prvniho nekorenoveho tagu @return Nejvetsi pouzity index u tagu, ktere jsou syny korene */ int getListOfIds(DA * ids,char * firsttag,int firstid,...); /** Naplni pole tak, ze na structure[ID] zapise data, ktera jsou nekde obsahuje konstruckci DATA. V tag je jen ID struktury a data jsou az v subtagu - zadam data z subtagu (char * subtag) a chci id. Pokud searched text neni NULL omezi se vyber struktur pouze na ty, jejichz data=seachedText. V ceste se strida jmeno tagu a jeho id. Posledni parametr musi byt NULL. @param structure data @param searchedText text, ktery vyhledavam @param firsttag jmeno prvniho nekorenoveho tagu @param firstid id prvniho nekorenoveho tagu @return Nejvetsi index nejakeho primeho syna od uzlu, ktery byl nalezen */ int getListOfStructs(DA * structure,char *searchedText, char *subtag,char * firsttag,int firstid,...); /** Vraci id tagu, jehoz nejaky primy syn obsahuje data=searchedText (prohledava se jen do hloubky 1). Pokud nenajde vraci \ref XML_ERROR_NO_SUCH_A_PATH. Cesta se zadava k rodicovi tagu, ptam se na id syna, pro koren je firsttag=NULL a id=0. V ceste se strida jmeno tagu a jeho id. Posledni parametr musi byt NULL. @param searchedText text, ktery vyhledavam @param firsttag jmeno prvniho nekorenoveho tagu @param firstid id prvniho nekorenoveho tagu @return Index tagu, ktery byl nalezen, pokud nebyl, pak \ref XML_ERROR_NO_SUCH_A_PATH */ int getIdOfTagWhoseChildContains(char *searchedText, char * firsttag,int firstid,...); /** Vrati pocet tagu, jehoz nejaky primy syn obsahuje data shodna s searchedText (prohledava se jen do hloubky 1). Pokud nenajde vraci \ref XML_ERROR_NO_SUCH_A_PATH. Id jednotlivych tagu bude v poli ids. Cesta se zadava k rodicovi tagu, ptam se na id syna. V ceste se strida jmeno tagu a jeho id. Posledni parametr musi byt NULL. @param arrayofid pole id - data @param searchedText text, ktery vyhledavam @param firsttag jmeno prvniho nekorenoveho tagu @param firstid id prvniho nekorenoveho tagu */ int getIdsOfTagsWhoseChildrenContain(DA * arrayofid,char *searchedText, char * firsttag,int firstid,...); //@} /** @name Ziskani minima, maxima a poctu id */ //@{ /** Vraci nejvetsi pouzite id u tagu hned pod korenem. */ int getMaxId(void); /** Vraci nejmensi pouzite id u tagu hned pod korenem. */ int getMinId(void); /** Vraci pocet pouzitych id u tagu hned pod korenem. */ int getNumId(void); /** Vraci nejvetsi pouzite id v nejakem subtagu. Cesta se zadava az k tagu, na jehoz indexy se ptam, s id rovno 0. */ int getMaxId(char * firsttag,int firstid,...); /** Vraci nejmensi pouzite id v nejakem subtagu. Cesta se zadava az k tagu, na jehoz indexy se ptam, s id rovno 0. */ int getMinId(char * firsttag,int firstid,...); /** Vraci pocet pouzitych id v nejakem subtagu. Cesta se zadava az k tagu, na jehoz indexy se ptam, s id rovno 0. */ int getNumId(char * firsttag,int firstid,...); //@} /** @name Operace s DTD */ //@{ void setDTD(DA * newdtd); // zapise DTD daneho XML do promenne this->DTD void setDTD(char * newdtd); // zapise DTD daneho XML do promenne this->DTD size_t sizeofDTD(void); // vrati velikost this->DTD, vsechny zapisy DTD do souboru se ale provadi v xml.cpp void getDTD(char * output,int size); // zapise do output this->DTD nejvyse size znaku, vsechny zapisy DTD do souboru se ale provadi v xml.cpp //@} /** @name Operace na stromove strukture */ //@{ /** Metoda na ziskani substromu tagu daneho jeho cestou. V pripade ze to byl doposud list, vytvori se u nej moznost pridavat potomky. @param ids pole indexu @param tags pole tagu @param number delka cesty (pocet prvku v poli tags nebo ids) @return Tag, ktery je urcen cestou */ xmlcontainersmall * getSubtag(int *ids,char **tags, int number); /** Pouzije jiz zkonstruovany strom. Puvodni data se mazou. @param st jiz vybudovany strom */ void createFromSubtag(xmlcontainersmall * st); //@} /** @name Ruzne funkce */ //@{ void forgetData(void); ///< Zapomene data, ktera v sobe uchovava. //@} private: /** Pomocna metoda na nacteni parametru u metod s libovolnym poctem parametru. @param marker odkaz na parametry @param tags ukazatel na pole retezcu ziskanych z parametru @param ids ukazatel na pole indexu @param firstwch jmeno prvniho tagu @param firstid id prvniho tagu @return Delka cesty */ int readAttrib(va_list * marker,char ***tags,int **ids,char * firstwch, int firstid); /** Ziska cely tag, ktery se naleza na ceste jako u getData. @param output ukazatel na ukazatel na uzel @param ids pole indexu @param tags pole nazvu tagu @param number delka cesty @return Vraci \ref XML_ERROR_OK pokud se akce povedla jinak \ref XML_ERROR_NO_SUCH_A_PATH */ int getTag(xmlcontainer ** output,int *ids,char ** tags, int number); /** Udrzuje nejvetsi pouzity index u primych potomku korene */ int maxId; /** Udrzuje nejmensi pouzity index u primych potomku korene */ int minId; /** Udrzuje pocet pouzitych index u primych potomku korene */ int numId; /** Zrusi veskery xml obsah */ void delXML(); /** Zapise tag (dalsi prvek cesty) do "pameti", pro rychlejsi pristup na dane misto Staci kopirovat pointery. @param xc pridavany tag @param firsttag ukazatel na jmeno tagu (tzn. xc->tag) @param id id tagu @param memoryindex volny index v poli mem */ void saveToMemory(xmlcontainer * xc,char *firsttag,int id,int &memoryindex); /** Metoda na prohledani stromove struktury @param start tag u nehoz se zacne prohledavat @param userData data predavana handlerum @param before handler, ktery se ma provest pred zanorenim do potomku tagu @param middle handler pro vlastni tag @param after handler po vynoreni z potomka tagu @param out handler pristupujici ke vlastni stromove strukture @param depth hloubka do niz se prohledava */ void lookThrough(xmlcontainersmall * start,void *userData,lookThroughHandler before,lookThroughHandler middle,lookThroughHandler after,lookThroughHandlerAccess out,int depth); /// projede celou strukturu xml, depth je maximalni hloubka zanoreni (-1 je nekonecno) /** Vlasni data */ xmlcontainersmall *data; /** Kolik vraci hashovaci fce hodnot */ int hashcount; /** Pamatovani si posledniho pristupu */ DA * mem; /** Informace, zda je dulezite vse (1) nebo prevazne data (0) */ int importance; /** Uchovani DTD nacteneho xml */ char * DTD; /** Pokud chci uchovat strom presne v poradi jako je v souboru (napr. pro jeho pozdejsi zapsani a dodrzeni DTD) */ int fixedorder; }; /** Jedna bunka z pameti. Ulozeni je pak v poli, pri vkladani/cteni prvku nejdriv zkousim pamet predpokladam, ze se vse bude vkladat "na jedno misto", cimz pamet usetri cas. */ struct memory { char * tag; ///< Jmeno pouziteho tagu int id; ///< ID pouziteho tagu xmlcontainer * pointer; ///< Ukazatel na data tagu do xml struktury }; /// Pomocna struktura, slouzici jako "hlava" k seznamum podobnych tagu v xmlcontainer. struct containersmall { xmlcontainer * next; }; /// Pomocna struktura k uchovani subtagu a dat. struct interior { xmlcontainersmall * subtag; // pole o velikosti hashcount char * data; }; /// Struktura udrzujici odkazy na data na jedne urovni zanoreni v nejkem sub-stromu v XML struct container { char * tag; ///< Nazev tagu. xmlcontainer * next; ///< Odkaz na dalsi tag s podobnym nazvem. DA * content; ///< Pole uchovavajici pro dane ID vlastni data a subtag int maxId; ///< Nejvetsi pouzite ID mezi primymi potomky int minId; ///< Nejmensi pouzite ID mezi primymi potomky int numId; ///< Pocet ruznych ID mezi primymi potomky }; /// Struktura prenasejici this a cestu tagu - pouzita pri parsovani XML struct dataHandlerStruct { void *that; ///< Ukazatel na XML strukturu DA * piece; ///< Postupne budovane data na vlozeni, dynamicke, jelikoz potrbuji zacit od indexu -1 DA * ids; ///< Atributy ID int Depth; ///< Jak hluboko jsem zanoren int imp; ///< Hodnotka TXMLdata::importance DA * pcdata; ///< Vlastni obsah tagu, ktery vlozim az po opusteni tagu DA * dtd; ///< Obsah doctype XML_Parser * parser; ///< Odkaz na parser, kvuli dealokovani modelu DTD v handleru const char * stop; ///< Tag u ktereho chci parsovani skoncit, resp. NULL }; /// Struktura slouzici pri prenosu dat do metody lookThrough - v pripade ze chci vratit slozitejsi strukturu struct lookThroughStruct { char * searchedText; ///< Vybiram pouze ty "struktury" jejich subtag obsahuje tento retezec DA * data; ///< Vlastni data char * subtag; ///< Informace ktery sub-tag mam vzit na data int fixedorder; ///< Hodnota TXMLdata::fixedorder }; /// Struktura, ktera se vyuziva pro zjisteni, zda-li tag obsahuje data nebo ne struct contentData { int datafound; ///< Informace, jestli byly data nalezeny }; /// Struktura slouzici pri prenosu dat do metody lookThrough - v pripade, ze chci najit id od nejake "struktury" struct lookThroughStruct2 { char * searchedText; ///< Text, ktery hledam a chci id nejvyssiho tagu, ktery obsahuje nekde v podstrome tag (jelikoz prohledavam do hloubky 1 je to syn), jehoz data je prave ten seachedText int found; ///< Nalezeno - ve vsech endHandlerech budu prepisovat id (tim se pouzije id nejvyssiho tagu) int id; ///< To id ktere vracim }; /// Struktura slouzici pri prenosu dat do metody lookThrough - v pripade, ze chci znovu nastavit min,max,num struct lookThroughStruct3 { int min; ///< Nejmensi nalezeny prvek int max; ///< Nejvetsi nalezeny prvek int num; ///< Pocet nalezenych prvku }; /// Struktura slouzici pri prenosu dat do metody lookThrough - v pripade, ze chci najit vsechny id od nejakych "struktury" struct lookThroughStruct4 { char * searchedText; ///< Text, ktery hledam a chci id nejvyssiho tagu, ktery obsahuje nekde v podstrome tag (jelikoz prohledavam do hloubky 1 je to syn), jehoz data je prave ten seachedText int found; ///< Nalezeno - ve vsech endHandlerech budu prepisovat id (tim se pouzije id nejvyssiho tagu) DA * ids; ///< Ta id ktere vracim }; /// Struktura slouzici pri prenosu dat do metody lookThrough - pouzivana na kompresi XML struct lookThroughStruct5 { DA * counts; DA * strings; }; #endif // DEFINE XML /*****************************************************************************/