Narzędzia użytkownika

Narzędzia witryny


xerces_dom

To jest stara wersja strony!


biblioteka dla XML: Xerces (DOM)

Autor: Krzysztof Mioduszewski 2008/04/14 23:59

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.

Biblioteka DOM jest implementacją następujących rekomendacji W3C:

Oraz zawiera częściową implementację (opartą o W3C Working Draft 09 April 2002) :


Więcej informacji na stronie projektu http://xerces.apache.org/xerces-c/. Na stronie znajdują się źródła, oraz skompilowane wersje biblioteki na różne platformy. Kompletna instrukcja instalacji na różnych platformach znajduje się tutaj.

Informacje wstępne

Nagłówki, które powinniśmy dołączyć w przypadku pisania typowych aplikacji korzystających z Xerces DOM znajdują się poniżej:

#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/dom/DOM.hpp> 
#include <xercesc/parsers/XercesDOMParser.hpp>

Xerces posiada własny typ znakowy XMLCh, który jest używany zamiast char i std::string. Do konwersji pomiędzy typami char* a XMLCh* (w obie strony) używana jest funkcja XMLString::transcode(). Pamięć zaalokowaną na łańcuchy należy zwalniać za pomocą funkcji XMLString::release().

Przed użyciem jakichkolwiek klas Xerces konieczne jest wywołanie metody XMLPlatformUtils::Initialize(). Po zakończeniu korzystania z Xerces powinno się wywołać XMLPlatformUtils::Terminate(). Poniżej znajduje się uproszczona struktura programu (warto zwrócić uwagę na uzycie transcode()).

#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/dom/DOM.hpp> 
#include <xercesc/parsers/XercesDOMParser.hpp>
// ...
#include <iostream>  
 
int main()
{
	try { 
		//incjalizacja Xerces-C++
		xercesc::XMLPlatformUtils::Initialize();
	}
	catch (const xercesc::XMLException& e) {
		//konwersja  z XMLCh* na char*
		char* msg = xercesc::XMLString::transcode(e.getMessage()) ;
 
		std::cerr << "Init Error: " << msg << std::endl;
		//zwolnienie pamieci
		xercesc::XMLString::release(&msg) ;
		return 1;
	}
 
	// Tutaj korzystamy z mozliwosci Xerces-C++ 
 
	xercesc::XMLPlatformUtils::Terminate();
 
	return 0;
}

XercesDOMParser

Jest to parser umożliwiający wczytanie do pamięci struktury pliku XML za pomocą metody parse(). Po czym uzyskujemy dostęp do obiektu DOMDocument, po którym możemy poruszać się wykorzystując zaimplementowane w zgodzie z rekomendacjami W3C metody.

Poniżej przykładowe fragmenty kodu dotyczącego inicjalizacji i korzystania z XercesDOMParser.

xercesc::XercesDOMParser* parser = new xercesc::XercesDOMParser();
parser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto);  //uruchamia walidację, jeżeli dostępne jest DTD (wewnętrzne/zewnętrzne)   
parser->setDoNamespaces(true);  
 
char* xmlFile = "file.xml";
 
try {
    parser->parse(xmlFile);
}
catch( const xercesc::XMLException& e ){
    //...			
}
catch( const xercesc::DOMException& e ){
    //...	
}
catch (...) {
    //...
}
 
//sprawdzamy czy nie wystąpiły błędy podczas parsowania
if(parser->getErrorCount()==0) {
    xercesc::DOMDocument* XMLdoc = parser->getDocument();
    //...
}

Dobrym pomysłem jest zastosowanie własnego ErrorHandler do wykrywania błędów składniowych w trakcie parsowania i wyświetlania o nich informacji (typ, miejsce wystąpienia). Najprostszy sposób to zaimplementowanie metod z interfejsu HandlerBase:

#include <xercesc/sax/HandlerBase.hpp>
 
class myErrorHandler : xercesc::HandlerBase {
	void warning( const xercesc::SAXParseException& e ) { 
		char *msg = xercesc::XMLString::transcode(e.getMessage()); 
		std::cout << "warning: " << msg 
		          << " | line: " << e.getLineNumber() << std::endl;
		xercesc::XMLString::release(&msg);
	}
	void error( const xercesc::SAXParseException& e ) {
               // analogicznie jak wyżej
	}
	void fatalError( const xercesc::SAXParseException& e ) {
	       // j.w.
	}
	void resetErrors() {}
};
 
//...
 
xercesc::XercesDOMParser* parser = new xercesc::XercesDOMParser();
parser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto);    
parser->setDoNamespaces(true);  
 
xercesc::ErrorHandler* errHandler = (xercesc::ErrorHandler*) new myErrorHandler();
parser->setErrorHandler(errHandler);

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.

Plik XML - notes.xml, który zostanie wczytany:

<?xml version="1.0"?>
<!DOCTYPE notes SYSTEM "note.dtd">
<notes owner="John Doe">
   <note date="21/02/2008">
      <from>Jani</from>
      <heading>Reminder</heading>
      <body>Don't forget me this weekend</body>
   </note>
   <note date="12/04/2008">
      <from>Jeff</from>
      <heading>Money</heading>
      <body>Gimme my money back!</body>
   </note>
</notes>

DTD - notes.dtd

 <!ELEMENT notes (note+) > 
 <!ATTLIST notes owner CDATA #REQUIRED>
  <!ELEMENT note (from,heading,body)>
  <!ATTLIST note date CDATA #REQUIRED>
  <!ELEMENT from    (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body    (#PCDATA)>

Klasy pomocnicze:

#include<string>
#include<xercesc/util/XMLString.hpp>
 
//klasa pomocnicza ułatwiająca współpracę z XMLCh*
class UniString {
public :
	UniString(const XMLCh* const str) 
	:
		cString(xercesc::XMLString::transcode(str)),
		xmlString(xercesc::XMLString::replicate(str))
	{}
 
	UniString(const char* const str)
	:
		cString(xercesc::XMLString::replicate(str)),
		xmlString(xercesc::XMLString::transcode(str))
	{}	
 
	UniString(const std::string& str)
	:
		cString(xercesc::XMLString::replicate(str.c_str())),
		xmlString(xercesc::XMLString::transcode(str.c_str()))
	{}
 
	~UniString() 
	{
		xercesc::XMLString::release(&cString);
		xercesc::XMLString::release(&xmlString);
	}
 
	const char* toCString() 	{ return cString; }
	const XMLCh* toXMLString() 	{ return xmlString; }
 
	std::ostream& print(std::ostream& s) const 
	{
		s << cString;
		return(s);
	}
 
private :
	char*   cString;
	XMLCh*  xmlString;
 
};
 
std::ostream& operator<<( std::ostream& s, const UniString& str ) { return s << str.print(); }
 
//klasa pomocnicza przechowująca nazwy tagów oraz atrybutów 
class docNames {
public:
	const UniString TAG_NOTES;
	const UniString TAG_NOTE;
	const UniString TAG_FROM;
	const UniString TAG_HEADING;
	const UniString TAG_BODY;
 
	const UniString ATTR_OWNER;
	const UniString ATTR_DATE;
 
	docNames()
		:
		TAG_NOTES("notes"),
		TAG_NOTE("note"),
		TAG_FROM("from"),
		TAG_HEADING("heading"),
		TAG_BODY("body"),
 
		ATTR_OWNER("owner"),
		ATTR_DATE("date")
	{}
};
//...
 
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
                //...
	}
}
xerces_dom.1208214384.txt.gz · ostatnio zmienione: 2008/04/15 01:06 przez kmioduszewski