XMLManager.cpp 7.54 KB
#include "XMLManager.h"

#include <fstream> 

#include <libxml/xmlschemas.h>

#include "../Common/Toolbox.h"

using namespace TREPS::Common;

namespace TREPS
{
	namespace XMLManager
	{
		XMLManagerClass::XMLManagerClass(void) : doc(NULL), xpathCtx(NULL), rootNode(NULL)
		{
			#ifndef CSLIM_SERVER
			this->app = ApplicationClass::getInstance();
			#endif
		}
		
		XMLManagerClass::~XMLManagerClass(void)
		{
			this->close();
		}
		
		bool XMLManagerClass::loadFile(const char *file_path, bool initXPath)
		{
			#ifndef CSLIM_SERVER
			LOG4CXX_INFO(this->app->getLog()->getPtr(),"Try to load xml file: " << file_path);
			#endif

			if (this->isInUse())
			{
				#ifndef CSLIM_SERVER
				LOG4CXX_ERROR(this->app->getLog()->getPtr(), "A xml file already loaded. You need to close it before to load a new file : " << file_path);
				#endif
				return false;
			}

			//read file		
			this->doc = xmlReadFile(file_path, NULL, 0);
			
			if (this->doc == NULL)
			{
				#ifndef CSLIM_SERVER
				LOG4CXX_ERROR(this->app->getLog()->getPtr(),"Cannot load xml file: " << file_path);
				#endif
				return false;
			}

			//get root node
			this->rootNode = xmlDocGetRootElement(this->doc);
			
			#ifndef CSLIM_SERVER
			LOG4CXX_INFO(this->app->getLog()->getPtr(),"xml file loaded : " << file_path);
			#endif

			if (initXPath)
			{
				//init XPath if need
				this->xpathCtx = xmlXPathNewContext(this->doc);
			}

			return true;
		}
		
		bool XMLManagerClass::close()
		{

			if (this->isInUse())
			{
				#ifndef CSLIM_SERVER
				LOG4CXX_INFO(this->app->getLog()->getPtr(),"close xml file");
				#endif
				if (this->xpathCtx)
				{
					//delete XPath context if exist
					xmlXPathFreeContext(this->xpathCtx);
					this->xpathCtx = NULL;
				}
				//free xml document
				xmlFreeDoc(this->doc);
				this->doc = NULL;
				this->rootNode = NULL;
			}

			return (!this->isInUse());
		}
		
		bool XMLManagerClass::create(const char *root_name)
		{
			if (this->isInUse())
			{
				#ifndef CSLIM_SERVER
				LOG4CXX_ERROR(this->app->getLog()->getPtr(), "A xml file already loaded. You need to close it before to create a new xml doc");
				#endif
				return false;
			}

			//create new xml document
			this->doc = xmlNewDoc((const xmlChar*)"1.0");
			
			if (this->doc == NULL)
			{
				#ifndef CSLIM_SERVER
				LOG4CXX_ERROR(this->app->getLog()->getPtr(),"Cannot create xml doc");
				#endif
				return false;
			}

			//create root node
			this->rootNode = xmlNewNode(NULL, (const xmlChar*)root_name);
			
			if (this->rootNode == NULL)
			{
				#ifndef CSLIM_SERVER
				LOG4CXX_ERROR(this->app->getLog()->getPtr(),"Cannot create root node in xml doc");
				#endif
				this->close();
				return false;
			}
			
			//add root node
			xmlDocSetRootElement(this->doc, this->rootNode);
			
			return true;
		}
		
		bool XMLManagerClass::save(const char * file_path)
		{
			//save the current xml doc
			bool res = (xmlSaveFormatFileEnc(file_path,this->doc,NULL,1) > -1);
			
			#ifndef CSLIM_SERVER
			if (!res)
				LOG4CXX_ERROR(this->app->getLog()->getPtr(),"Cannot save file: " << file_path);
			#endif
		
			return res;
		}
		
		bool XMLManagerClass::isInUse()
		{
			return (this->doc != NULL);
		}

		#ifndef CSLIM_SERVER
		bool XMLManagerClass::isValid(const char *xsdName)
		{
			//check XML file validity with XSD file
			if (!this->isInUse())
			{
				LOG4CXX_ERROR(this->app->getLog()->getPtr(), "Cannot make the validation. No document opened!");
				return false;
			}

			string xsdPath = this->app->getConf()->getXSDDirPath();
			xsdPath += xsdName;
			
			xmlSchemaPtr schema = NULL;
			xmlSchemaParserCtxtPtr ctxt;
			xmlSchemaValidCtxtPtr validctxt;

			//parse xsd file
			ctxt = xmlSchemaNewParserCtxt(xsdPath.c_str());
			schema = xmlSchemaParse(ctxt);
			xmlSchemaFreeParserCtxt(ctxt);

			if (schema == NULL)
			{
				LOG4CXX_ERROR(this->app->getLog()->getPtr(), "Cannot parse xsd file " << xsdPath);
				return false;
			}

			validctxt = xmlSchemaNewValidCtxt(schema);

			//validation
			int res = xmlSchemaValidateDoc(validctxt, this->doc);

			//free
			xmlSchemaFreeValidCtxt(validctxt);
			xmlSchemaFree(schema);

			return (res == 0);
		}
		#endif
		
		bool XMLManagerClass::isExist(const char *file_path)
		{
			return isFileExist(file_path);
		}

		Node *XMLManagerClass::getRootNode(void)
		{
			return this->rootNode;
		}
		
		NodeList XMLManagerClass::getChildrenFromNode(const char *tag_name, Node *node)
		{
			NodeList res;
	
			if ((node == NULL) || !this->isInUse())
				return res;

			Node *crt = node->xmlChildrenNode;
			while (crt != NULL)
			{
				if (!xmlStrcmp(crt->name, (const xmlChar *)tag_name))
				{
					res.push_back(crt);
				}
				crt = crt->next;
			}
			
			return res;
		}
		
		NodeList XMLManagerClass::getChildrenFromRoot(const char *tag_name)
		{
			return this->getChildrenFromNode(tag_name,this->rootNode);
		}
		
		Node *XMLManagerClass::getChildFromNode(const char *tag_name, Node *node)
		{
			//return first child
			NodeList l = this->getChildrenFromNode(tag_name, node);
			
			if (l.empty())
				return NULL;
			
			return l.front();
		}
		
		Node *XMLManagerClass::getChildFromRoot(const char *tag_name)
		{
			//return first child
			return this->getChildFromNode(tag_name,this->rootNode);
		}

		string XMLManagerClass::getAttributeFromNode(const char *att_name, Node *node)
		{
			if ((node == NULL)  || !this->isInUse())
				return "";
			xmlChar *att = xmlGetProp(node,(const xmlChar *)att_name);
			if (att == NULL)
				return "";
			string res = string(reinterpret_cast<const char*>(att));
			xmlFree(att);
			return res;
		}

		Node *XMLManagerClass::addChildToNode(const char *tag_name, Node *node)
		{
			if ((node == NULL)  || !this->isInUse())
				return NULL;
			
			return xmlNewChild(node, NULL, (const xmlChar*)tag_name, NULL);
		}
		
		Node *XMLManagerClass::addChildToRoot(const char *tag_name)
		{
			return this->addChildToNode(tag_name,this->rootNode);
		}
		
		bool XMLManagerClass::addAttributeToNode(const char *att_name, const char *att_value, Node *node)
		{
			//xmlEncodeEntitiesReentrant to replace special characters
			xmlChar* buf = xmlEncodeEntitiesReentrant(this->doc,(const xmlChar*) att_value);
			xmlSetProp(node, (const xmlChar*)att_name, buf);
			xmlFree(buf);
			return true;
		}
		
		bool XMLManagerClass::setNodeContent(const char *content, Node *node)
		{
			//xmlEncodeEntitiesReentrant to replace special characters
			xmlChar* buf = xmlEncodeEntitiesReentrant(this->doc,(const xmlChar*) content);
			xmlNodeSetContent(node, buf);
			xmlFree(buf);
			return true;
		}

		string XMLManagerClass::getNodeContent(Node *node)
		{
			xmlChar* nodeContent = xmlNodeGetContent(node);
			string res = (const char *)nodeContent;
			xmlFree(nodeContent);
			return res;
		}

		NodeList XMLManagerClass::evaluateXPathExpression(const char *xpathExpression)
		{
			//evaluate a XPath expression
			NodeList resNode;
			resNode.clear();

			if (!this->isInUse() || this->xpathCtx == NULL)
			{
				#ifndef CSLIM_SERVER
				LOG4CXX_ERROR(this->app->getLog()->getPtr(),"XPath context not initialized");
				#endif
				return resNode;
			}

			xmlXPathObject *xpathObj = xmlXPathEvalExpression((const xmlChar*)xpathExpression, this->xpathCtx);

			if(xpathObj == NULL)
			{
				#ifndef CSLIM_SERVER
				LOG4CXX_ERROR(this->app->getLog()->getPtr(),"Cannot evaluate xpath expression");
				#endif
				return resNode;
			}

			if (xpathObj->nodesetval != NULL)
			{
				for (int i = 0; i < xpathObj->nodesetval->nodeNr; ++i)
					if (xpathObj->nodesetval->nodeTab[i]->type == XML_ELEMENT_NODE)
						resNode.push_back(xpathObj->nodesetval->nodeTab[i]);
			}

			xmlXPathFreeObject(xpathObj);

			return resNode;
		}
	}
}