Różnice między wybraną wersją a wersją aktualną.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
xerces_dom [2008/04/15 02:01] kmioduszewski |
xerces_dom [2008/04/16 15:33] (aktualna) kmioduszewski |
||
|---|---|---|---|
| Linia 1: | Linia 1: | ||
| ====== biblioteka dla XML: Xerces (DOM) ===== | ====== biblioteka dla XML: Xerces (DOM) ===== | ||
| - | **Autor:** //[[kmioduszewski@polibuda.info|Krzysztof Mioduszewski]] 2008/04/14 23:59//\\ \\ | + | **Autor** //Krzysztof Mioduszewski - k.mioduszewski@stud.elka... 2008/04/16 02:12//\\ \\ |
| Xerces-C++ DOM jest częścią Xerces-C++ API zaprojektowanego do współpracy z plikami w formacie XML. API umożliwia parsowania, manipulowanie, walidowanie oraz generowanie poprawnych dokumentów. | Xerces-C++ DOM jest częścią Xerces-C++ API zaprojektowanego do współpracy z plikami w formacie XML. API umożliwia parsowania, manipulowanie, walidowanie oraz generowanie poprawnych dokumentów. | ||
| \\ \\ | \\ \\ | ||
| Linia 139: | Linia 139: | ||
| </code> | </code> | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| Linia 158: | Linia 163: | ||
| ===== DOMDocument, operacje na dokumencie===== | ===== DOMDocument, operacje na dokumencie===== | ||
| - | Gdy dokument zostanie sparsowany bez żadnych błędów możemy swobodnie zacząć na nim pracować wykorzystując zawarte w rekomendacjach metody. Poniżje znajduje się kod przykładowej aplikacji, która wczytuje plik XML, wpisuje jego zawartość na ekran, modyfikuje go, a następnie zapisuje zmiany do pliku.\\ \\ | + | Gdy dokument zostanie sparsowany bez żadnych błędów możemy swobodnie zacząć na nim pracować wykorzystując zawarte w rekomendacjach metody. Poniżej znajduje się kod przykładowej aplikacji, która wczytuje plik XML, wypisuje jego zawartość na ekran, modyfikuje go, a następnie zapisuje zmiany do pliku.\\ \\ |
| Plik XML - ''notes.xml'', który zostanie wczytany: | Plik XML - ''notes.xml'', który zostanie wczytany: | ||
| <code xml> | <code xml> | ||
| Linia 190: | Linia 195: | ||
| #include <string> | #include <string> | ||
| #include <iostream> | #include <iostream> | ||
| + | #include <stdexcept> | ||
| #include <xercesc/util/XMLString.hpp> | #include <xercesc/util/XMLString.hpp> | ||
| #include <xercesc/sax/HandlerBase.hpp> | #include <xercesc/sax/HandlerBase.hpp> | ||
| - | + | #include <xercesc/util/PlatformUtils.hpp> | |
| + | #include <xercesc/dom/DOM.hpp> | ||
| + | #include <xercesc/parsers/XercesDOMParser.hpp> | ||
| + | #include <xercesc/framework/LocalFileFormatTarget.hpp> | ||
| + | #include <xercesc/framework/StdOutFormatTarget.hpp> | ||
| //klasa pomocnicza ułatwiająca współpracę z XMLCh* | //klasa pomocnicza ułatwiająca współpracę z XMLCh* | ||
| class UniString { | class UniString { | ||
| + | private : | ||
| + | char* cString; | ||
| + | XMLCh* xmlString; | ||
| + | |||
| public : | public : | ||
| UniString(const XMLCh* const str) | UniString(const XMLCh* const str) | ||
| Linia 220: | Linia 235: | ||
| } | } | ||
| - | const char* toCString() { return cString; } | + | const char* toCString() const { return cString; } |
| - | const XMLCh* toXMLString() { return xmlString; } | + | const XMLCh* toXMLString() const { return xmlString; } |
| std::ostream& print(std::ostream& s) const | std::ostream& print(std::ostream& s) const | ||
| Linia 229: | Linia 244: | ||
| } | } | ||
| - | private : | + | |
| - | char* cString; | + | |
| - | XMLCh* xmlString; | + | |
| - | + | ||
| }; | }; | ||
| Linia 238: | Linia 250: | ||
| //klasa pomocnicza przechowująca nazwy tagów oraz atrybutów | //klasa pomocnicza przechowująca nazwy tagów oraz atrybutów | ||
| - | class docNames { | + | class DocNames { |
| public: | public: | ||
| const UniString TAG_NOTES; | const UniString TAG_NOTES; | ||
| Linia 249: | Linia 261: | ||
| const UniString ATTR_DATE; | const UniString ATTR_DATE; | ||
| - | docNames() | + | DocNames() |
| : | : | ||
| TAG_NOTES("notes"), | TAG_NOTES("notes"), | ||
| Linia 264: | Linia 276: | ||
| class myErrorHandler : xercesc::HandlerBase { | class myErrorHandler : xercesc::HandlerBase { | ||
| void warning( const xercesc::SAXParseException& e ) { | void warning( const xercesc::SAXParseException& e ) { | ||
| - | std::cout << "warning: " << UniString(e.getMessage()) | + | std::cerr << "warning: " << UniString(e.getMessage()) |
| << " | line: " << e.getLineNumber() << std::endl; | << " | line: " << e.getLineNumber() << std::endl; | ||
| } | } | ||
| void error( const xercesc::SAXParseException& e ) { | void error( const xercesc::SAXParseException& e ) { | ||
| - | std::cout << "error: " << UniString(e.getMessage()) | + | std::cerr << "error: " << UniString(e.getMessage()) |
| << " | line: " << e.getLineNumber() << std::endl; | << " | line: " << e.getLineNumber() << std::endl; | ||
| } | } | ||
| void fatalError( const xercesc::SAXParseException& e ) { | void fatalError( const xercesc::SAXParseException& e ) { | ||
| - | std::cout << "fatalError: " << UniString(e.getMessage()) | + | std::cerr << "fatalError: " << UniString(e.getMessage()) |
| << " | line: " <<e.getLineNumber() << std::endl; | << " | line: " <<e.getLineNumber() << std::endl; | ||
| } | } | ||
| Linia 278: | Linia 290: | ||
| }; | }; | ||
| </code> | </code> | ||
| - | ''parser.cpp'' | + | ''DOMtest.h'' - zawiera klasę DOMtest, prezentującą możliwości korzystania biblioteki DOM. |
| <code cpp> | <code cpp> | ||
| #include "support.h" | #include "support.h" | ||
| - | xercesc::DOMDocument* parseXML() { | + | class DOMtest { |
| - | xercesc::XercesDOMParser* parser = new xercesc::XercesDOMParser(); | + | private: |
| - | parser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto); | + | std::string filename; |
| - | parser->setDoNamespaces(true); | + | xercesc::XercesDOMParser parser; |
| - | + | DocNames names; | |
| - | xercesc::ErrorHandler* errHandler = (xercesc::ErrorHandler*) new myErrorHandler(); | + | bool loaded; |
| - | parser->setErrorHandler(errHandler); | + | |
| - | UniString src = UniString("dupa.xml"); | + | DOMtest(const DOMtest&); |
| - | try { | + | public: |
| - | parser->parse(src.toXMLString()); | + | DOMtest(std::string f) |
| + | : | ||
| + | filename(f), | ||
| + | parser(), | ||
| + | names(), | ||
| + | loaded(false) | ||
| + | { }; | ||
| + | |||
| + | void init() throw( std::runtime_error ) | ||
| + | { | ||
| + | parser.setValidationScheme(xercesc::XercesDOMParser::Val_Auto); | ||
| + | parser.setDoNamespaces(true); | ||
| + | |||
| + | xercesc::ErrorHandler* errHandler = (xercesc::ErrorHandler*) new myErrorHandler(); | ||
| + | parser.setErrorHandler(errHandler); | ||
| + | |||
| + | try { | ||
| + | parser.parse(filename.c_str()); | ||
| + | } catch(xercesc::XMLException& e){ | ||
| + | UniString eMsg(e.getMessage()); | ||
| + | throw(std::runtime_error(eMsg.toCString())); | ||
| + | }catch( const xercesc::DOMException& e ){ | ||
| + | UniString eMsg(e.getMessage()); | ||
| + | throw(std::runtime_error(eMsg.toCString())); | ||
| + | } | ||
| + | |||
| + | if(parser.getErrorCount()!=0) | ||
| + | throw(std::runtime_error("...")); | ||
| } | } | ||
| - | catch (...) { | + | |
| - | //... | + | //funkcja zawierający przykładowy sposób pobiernia |
| + | //informacji z dokumentu (bonus wyswietlanie ich) | ||
| + | std::ostream& print(std::ostream& s) throw(std::runtime_error) { | ||
| + | s << "MY NOTES: " << std::endl; | ||
| + | try { | ||
| + | //bierzmy sobie dokumenty | ||
| + | xercesc::DOMDocument* xmlDoc = parser.getDocument(); | ||
| + | |||
| + | //bierzemy sobie element główny | ||
| + | xercesc::DOMElement* root = xmlDoc->getDocumentElement(); | ||
| + | |||
| + | if(root == NULL) | ||
| + | throw(std::runtime_error("Empty Document")); | ||
| + | |||
| + | //pobieramy wartość atrybutu owner | ||
| + | //names.ATTR_OWNER.toXMLString() <- zwraca XMLCh* "owner"; -> support.h | ||
| + | UniString owner(root->getAttribute(names.ATTR_OWNER.toXMLString())); | ||
| + | s << "owner: " << owner << std::endl; | ||
| + | |||
| + | //pobieramy wszystkie elementy 'note' | ||
| + | xercesc::DOMNodeList* notesElements = root->getElementsByTagName(names.TAG_NOTE.toXMLString()); | ||
| + | |||
| + | for( XMLSize_t i = 0; i < notesElements->getLength(); ++i) { | ||
| + | s << "note no. " << i+1 << " "; | ||
| + | |||
| + | //bierzmy sobie node | ||
| + | xercesc::DOMNode* node = notesElements->item(i); | ||
| + | |||
| + | //konwersja na DOMElement, mogę sobie na to pozwolić gdyż znam, | ||
| + | //całą strukturę dokumentu, w przypadku nie znania wypadałoby sprawdzić | ||
| + | //aczkolwiek dynamic_cast rzuci wyjatke w razie problemów | ||
| + | xercesc::DOMElement* domElement = dynamic_cast<xercesc::DOMElement*>(node); | ||
| + | |||
| + | //pobieram datę | ||
| + | UniString date(domElement->getAttribute(names.ATTR_DATE.toXMLString())); | ||
| + | s << "date: " << date << std::endl; | ||
| + | |||
| + | //pobiorę sobie "bezposrednio" zawartość <form></form> | ||
| + | //nie jest to może tak "bezpośrednie" jak np. w Javascript ;) | ||
| + | UniString from(domElement->getElementsByTagName(names.TAG_FROM.toXMLString())->item(0)->getTextContent()); | ||
| + | s << " From: " << from << std::endl; | ||
| + | |||
| + | //teraz kolejne elementy | ||
| + | UniString heading(domElement->getElementsByTagName(names.TAG_HEADING.toXMLString())->item(0)->getTextContent()); | ||
| + | s << " Heading: " << heading << std::endl; | ||
| + | |||
| + | UniString body(domElement->getElementsByTagName(names.TAG_BODY.toXMLString())->item(0)->getTextContent()); | ||
| + | s << " Body: " << std::endl << " " << body << std::endl << std::endl; | ||
| + | } | ||
| + | |||
| + | } catch(xercesc::XMLException& e){ | ||
| + | UniString eMsg(e.getMessage()); | ||
| + | throw(std::runtime_error(eMsg.toCString())); | ||
| + | } catch( const xercesc::DOMException& e ){ | ||
| + | UniString eMsg(e.getMessage()); | ||
| + | throw(std::runtime_error(eMsg.toCString())); | ||
| + | } | ||
| + | return(s) ; | ||
| } | } | ||
| - | + | ||
| - | if(parser->getErrorCount()==0) { | + | //tworzymy nową notkę i dopinamy ją do drzewa dokumentu |
| - | return parser->getDocument(); | + | void modify() throw(std::runtime_error) |
| - | } else { | + | { |
| - | return NULL; | + | try { |
| + | //tresc notki | ||
| + | UniString date("16/04/2008"); | ||
| + | UniString from("Cassius"); | ||
| + | UniString heading("!!!"); | ||
| + | UniString body("Nice try, Zarflax!"); | ||
| + | |||
| + | //aby tworzyć nowe elemnty potrzebujemy DOMDocument | ||
| + | xercesc::DOMDocument* xmlDoc = parser.getDocument(); | ||
| + | |||
| + | //tworzymy nowy element <note></note> | ||
| + | xercesc::DOMElement* noteElement = xmlDoc->createElement(names.TAG_NOTE.toXMLString()); | ||
| + | |||
| + | //tworzymy atrybut date | ||
| + | xercesc::DOMAttr* noteElementDate = xmlDoc->createAttribute(names.ATTR_DATE.toXMLString()); | ||
| + | //ustawiamy wartosc atrybutu date | ||
| + | noteElementDate->setValue(date.toXMLString()); | ||
| + | //przypinamy atrybut date do elementu note | ||
| + | noteElement->setAttributeNode(noteElementDate); | ||
| + | |||
| + | //tworzymy kolejne elementy i przypominamy do notki | ||
| + | xercesc::DOMElement* noteFromElement = xmlDoc->createElement(names.TAG_FROM.toXMLString()); | ||
| + | //ustawiamy tresc elementu <from></from> | ||
| + | noteFromElement->setTextContent(from.toXMLString()); | ||
| + | noteElement->appendChild(noteFromElement); | ||
| + | |||
| + | xercesc::DOMElement* noteHeadingElement = xmlDoc->createElement(names.TAG_HEADING.toXMLString()); | ||
| + | noteHeadingElement->setTextContent(heading.toXMLString()); | ||
| + | noteElement->appendChild(noteHeadingElement); | ||
| + | |||
| + | xercesc::DOMElement* noteBodyElement = xmlDoc->createElement(names.TAG_BODY.toXMLString()); | ||
| + | noteBodyElement->setTextContent(body.toXMLString()); | ||
| + | noteElement->appendChild(noteBodyElement); | ||
| + | |||
| + | //dopinamy kompletną notkę elementu <notes></notes> | ||
| + | xmlDoc->getDocumentElement()->appendChild(noteElement); | ||
| + | |||
| + | } catch(xercesc::XMLException& e){ | ||
| + | UniString eMsg(e.getMessage()); | ||
| + | throw(std::runtime_error(eMsg.toCString())); | ||
| + | } catch( const xercesc::DOMException& e ){ | ||
| + | UniString eMsg(e.getMessage()); | ||
| + | throw(std::runtime_error(eMsg.toCString())); | ||
| + | } | ||
| } | } | ||
| - | } | + | |
| + | void write(std::string filename) throw(std::runtime_error) { | ||
| + | try { | ||
| + | //konieczne do wykorzystania przy zapisie pliku | ||
| + | xercesc::XMLFormatTarget* file = new xercesc::LocalFileFormatTarget(UniString(filename).toXMLString()); | ||
| + | |||
| + | //obiekt wykorzystywana do zapisu | ||
| + | xercesc::DOMWriter* domWriter = parser.getDocument()->getImplementation()->createDOMWriter(); | ||
| + | |||
| + | //jezeli mamy możliwość ustawiamy przyjazne dla człowieka formatowanie | ||
| + | if(domWriter->canSetFeature(xercesc::XMLUni::fgDOMWRTFormatPrettyPrint,true)){ | ||
| + | domWriter->setFeature(xercesc::XMLUni::fgDOMWRTFormatPrettyPrint,true); | ||
| + | } | ||
| + | |||
| + | //zapis | ||
| + | domWriter->writeNode(file,*parser.getDocument()); | ||
| + | |||
| + | delete(file); | ||
| + | } catch(xercesc::XMLException& e){ | ||
| + | UniString eMsg(e.getMessage()); | ||
| + | throw(std::runtime_error(eMsg.toCString())); | ||
| + | } catch( const xercesc::DOMException& e ){ | ||
| + | UniString eMsg(e.getMessage()); | ||
| + | throw(std::runtime_error(eMsg.toCString())); | ||
| + | } | ||
| + | } | ||
| + | }; | ||
| + | </code> | ||
| + | plik testujący ''main.cpp'' | ||
| + | <code cpp> | ||
| + | #include "DOMtest.h" | ||
| int main() { | int main() { | ||
| Linia 314: | Linia 482: | ||
| } | } | ||
| - | xercesc::DOMDocument* xmlDoc = parseXML(); | + | try { |
| - | if(xmlDoc == NULL) | + | DOMtest DOM("notes.xml"); |
| - | return -1; | + | //incjacja prasera itp. |
| + | DOM.init(); | ||
| + | //pobieranie wartości, wydruk na ekranie | ||
| + | DOM.print(std::cout); | ||
| + | //dodanie notki | ||
| + | DOM.modify(); | ||
| + | //zapisu do pliku | ||
| + | DOM.write("notes2.xml"); | ||
| - | + | } catch(std::runtime_error& e) { | |
| + | std::cerr << e.what() << std::endl; | ||
| + | std::cerr << "Exiting" << std::endl; | ||
| + | } | ||
| + | |||
| xercesc::XMLPlatformUtils::Terminate(); | xercesc::XMLPlatformUtils::Terminate(); | ||
| - | int a; | ||
| - | std::cin >> a; | ||
| return 0; | return 0; | ||
| } | } | ||
| - | </code> | ||
| - | <code cpp> | ||
| - | //... | ||
| - | |||
| - | xercesc::DOMDocument* XMLdoc = parser->getDocument(); | ||
| - | xercesc::DOMElement* root = XMLdoc->getDocumentElement(); | ||
| - | |||
| - | //pobieramy nazwę elementu głównego | ||
| - | char* rootName = XMLString::transcode(root->getLocalName()); | ||
| - | |||
| - | if(root->hasAttributes()) { | ||
| - | xercesc::DOMNamedNodeMap* attrMap = root->getAttributes(); | ||
| - | //iterujemy sobie po atrybutach | ||
| - | for( XMLSize_t i = 0 ; i < attrMap->getLength() ; ++i ) { | ||
| - | DOMAttr* attr = dynamic_cast<DOMAttr*>(attrMap->item(ix)); | ||
| - | //wykorzystujemy sobie atrybut | ||
| - | attr->getName(); //tutaj mamy nazwe | ||
| - | attr->getValue(); //wartosc | ||
| - | //... | ||
| - | } | ||
| - | } | ||
| - | |||
| - | |||
| - | |||
| - | |||
| </code> | </code> | ||