Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Previous revision Next revision | Previous revision | ||
xerces_dom [2008/04/15 00:57] 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 153: | 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 159: | Linia 169: | ||
<!DOCTYPE notes SYSTEM "note.dtd"> | <!DOCTYPE notes SYSTEM "note.dtd"> | ||
<notes owner="John Doe"> | <notes owner="John Doe"> | ||
- | |||
<note date="21/02/2008"> | <note date="21/02/2008"> | ||
<from>Jani</from> | <from>Jani</from> | ||
Linia 182: | Linia 191: | ||
<!ELEMENT body (#PCDATA)> | <!ELEMENT body (#PCDATA)> | ||
</code> | </code> | ||
- | Klasy pomocnicze: | + | Klasy pomocnicze ''support.h'': |
<code cpp> | <code cpp> | ||
- | #include<string> | + | #include <string> |
- | #include<xercesc/util/XMLString.hpp> | + | #include <iostream> |
+ | #include <stdexcept> | ||
+ | #include <xercesc/util/XMLString.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 195: | Linia 216: | ||
xmlString(xercesc::XMLString::replicate(str)) | xmlString(xercesc::XMLString::replicate(str)) | ||
{} | {} | ||
- | + | ||
UniString(const char* const str) | UniString(const char* const str) | ||
: | : | ||
Linia 201: | Linia 222: | ||
xmlString(xercesc::XMLString::transcode(str)) | xmlString(xercesc::XMLString::transcode(str)) | ||
{} | {} | ||
+ | |||
UniString(const std::string& str) | UniString(const std::string& str) | ||
: | : | ||
Linia 207: | Linia 228: | ||
xmlString(xercesc::XMLString::transcode(str.c_str())) | xmlString(xercesc::XMLString::transcode(str.c_str())) | ||
{} | {} | ||
- | + | ||
~UniString() | ~UniString() | ||
{ | { | ||
Linia 213: | Linia 234: | ||
xercesc::XMLString::release(&xmlString); | xercesc::XMLString::release(&xmlString); | ||
} | } | ||
- | + | ||
- | 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 222: | Linia 243: | ||
return(s); | return(s); | ||
} | } | ||
- | + | ||
- | private : | + | |
- | char* cString; | + | |
- | XMLCh* xmlString; | + | |
}; | }; | ||
- | + | ||
- | std::ostream& operator<<( std::ostream& s, const UniString& str ) { return s << str.print(); } | + | std::ostream& operator<<( std::ostream& s, const UniString& str ) { return str.print(s); } |
+ | |||
//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 243: | Linia 261: | ||
const UniString ATTR_DATE; | const UniString ATTR_DATE; | ||
- | TagNames() | + | DocNames() |
: | : | ||
TAG_NOTES("notes"), | TAG_NOTES("notes"), | ||
Linia 255: | Linia 273: | ||
{} | {} | ||
}; | }; | ||
- | </code> | ||
+ | class myErrorHandler : xercesc::HandlerBase { | ||
+ | void warning( const xercesc::SAXParseException& e ) { | ||
+ | std::cerr << "warning: " << UniString(e.getMessage()) | ||
+ | << " | line: " << e.getLineNumber() << std::endl; | ||
+ | } | ||
+ | void error( const xercesc::SAXParseException& e ) { | ||
+ | std::cerr << "error: " << UniString(e.getMessage()) | ||
+ | << " | line: " << e.getLineNumber() << std::endl; | ||
+ | } | ||
+ | void fatalError( const xercesc::SAXParseException& e ) { | ||
+ | std::cerr << "fatalError: " << UniString(e.getMessage()) | ||
+ | << " | line: " <<e.getLineNumber() << std::endl; | ||
+ | } | ||
+ | void resetErrors() {} | ||
+ | }; | ||
+ | </code> | ||
+ | ''DOMtest.h'' - zawiera klasę DOMtest, prezentującą możliwości korzystania biblioteki DOM. | ||
<code cpp> | <code cpp> | ||
- | //... | + | #include "support.h" |
- | xercesc::DOMDocument* XMLdoc = parser->getDocument(); | + | class DOMtest { |
- | xercesc::DOMElement* root = XMLdoc->getDocumentElement(); | + | private: |
+ | std::string filename; | ||
+ | xercesc::XercesDOMParser parser; | ||
+ | DocNames names; | ||
+ | bool loaded; | ||
- | //pobieramy nazwę elementu głównego | + | DOMtest(const DOMtest&); |
- | char* rootName = XMLString::transcode(root->getLocalName()); | + | public: |
+ | DOMtest(std::string f) | ||
+ | : | ||
+ | filename(f), | ||
+ | parser(), | ||
+ | names(), | ||
+ | loaded(false) | ||
+ | { }; | ||
- | if(root->hasAttributes()) { | + | void init() throw( std::runtime_error ) |
- | xercesc::DOMNamedNodeMap* attrMap = root->getAttributes(); | + | { |
- | //iterujemy sobie po atrybutach | + | parser.setValidationScheme(xercesc::XercesDOMParser::Val_Auto); |
- | for( XMLSize_t i = 0 ; i < attrMap->getLength() ; ++i ) { | + | parser.setDoNamespaces(true); |
- | DOMAttr* attr = dynamic_cast<DOMAttr*>(attrMap->item(ix)); | + | |
- | //wykorzystujemy sobie atrybut | + | xercesc::ErrorHandler* errHandler = (xercesc::ErrorHandler*) new myErrorHandler(); |
- | attr->getName(); //tutaj mamy nazwe | + | parser.setErrorHandler(errHandler); |
- | attr->getValue(); //wartosc | + | |
- | //... | + | 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("...")); | ||
} | } | ||
- | } | + | |
+ | //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) ; | ||
+ | } | ||
+ | |||
+ | //tworzymy nową notkę i dopinamy ją do drzewa dokumentu | ||
+ | void modify() throw(std::runtime_error) | ||
+ | { | ||
+ | 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() { | ||
+ | try { | ||
+ | xercesc::XMLPlatformUtils::Initialize(); | ||
+ | } | ||
+ | catch (const xercesc::XMLException& e) { | ||
+ | std::cerr << UniString(e.getMessage()) << std::endl; | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | try { | ||
+ | DOMtest DOM("notes.xml"); | ||
+ | //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(); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
</code> | </code> |