Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Previous revision Next revision | Previous revision | ||
xerces_dom [2008/04/15 10:19] 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 160: | 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 192: | 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 { | ||
Linia 201: | Linia 210: | ||
XMLCh* xmlString; | XMLCh* xmlString; | ||
- | public : | + | public : |
- | UniString(const XMLCh* const str) | + | UniString(const XMLCh* const str) |
: | : | ||
cString(xercesc::XMLString::transcode(str)), | cString(xercesc::XMLString::transcode(str)), | ||
Linia 226: | 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 235: | Linia 244: | ||
} | } | ||
+ | |||
}; | }; | ||
Linia 240: | 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 251: | Linia 261: | ||
const UniString ATTR_DATE; | const UniString ATTR_DATE; | ||
- | docNames() | + | DocNames() |
: | : | ||
TAG_NOTES("notes"), | TAG_NOTES("notes"), | ||
Linia 266: | 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 280: | Linia 290: | ||
}; | }; | ||
</code> | </code> | ||
- | ''parser.cpp'' FIXME | + | ''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("file.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 316: | 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> |