Back to index

nordugrid-arc-nox  1.1.0~rc6
xmlconfig.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #include <fstream>
00006 
00007 #include "configcore.h"
00008 #include "xmlconfig.h"
00009 
00010 #include <libxml/parser.h>
00011 #include <libxml/parserInternals.h>
00012 #include <libxml/tree.h>
00013 #include <libxml/xpath.h>
00014 
00015 namespace ARex {
00016 
00017 static void XmlErrorHandler(void*, const char*) {
00018        return;
00019 }
00020 
00021 
00022 void XMLConfig::FillTree(xmlNode* node, Config& config) {
00023 
00024        bool has_element = false;
00025 
00026        for (xmlNode* cur_node = node; cur_node; cur_node = cur_node->next) {
00027               if (cur_node->type == XML_ELEMENT_NODE)
00028                      has_element = true;
00029               if (cur_node->children)
00030                      FillTree(cur_node->children, config);
00031        }
00032 
00033        if (has_element)
00034               return;
00035 
00036        std::string key;
00037        std::string id;
00038        std::string attr;
00039        std::map<std::string,std::string> suboptions;
00040 
00041        static xmlNode* reg = NULL;
00042        bool newreg = false;
00043 
00044        for (xmlNode* cur_node = node; cur_node->parent->type != XML_DOCUMENT_NODE;
00045             cur_node = cur_node->parent) {
00046               if (cur_node->type == XML_ELEMENT_NODE) {
00047 
00048                      // hack for registrations that are not distinguished by id
00049                      if (strcmp((const char*) cur_node->name, "registration") == 0) {
00050                             if (reg != cur_node) {
00051                                    newreg = true;
00052                                    reg = cur_node;
00053                             }
00054                      }
00055 
00056                      for (xmlAttr *attribute = cur_node->properties; attribute;
00057                           attribute = attribute->next) {
00058                             if (strcmp((const char*) attribute->name, "id") == 0)
00059                                    id = (const char*) attribute->children->content;
00060                             else
00061                                    suboptions[(const char*) attribute->name] =
00062                                           (const char*) attribute->children->content;
00063                      }
00064                      if (attr.empty())
00065                             attr = (const char*) cur_node->name;
00066                      else if (key.empty())
00067                             key = (const char*) cur_node->name;
00068                      else
00069                             key = (const char*) cur_node->name + ('/' + key);
00070               }
00071        }
00072        Option opt(attr, (const char*) node->content, suboptions);
00073 
00074        try {
00075               if (newreg)
00076                      throw ConfigError("");
00077               const ConfGrp& grp = config.FindConfGrp(key,id);
00078               const_cast<ConfGrp&>(grp).AddOption(opt);
00079        }
00080        catch (ConfigError) {
00081               ConfGrp grp(key,id);
00082               grp.AddOption(opt);
00083               config.AddConfGrp(grp);
00084        }
00085 }
00086 
00087 
00088 Config XMLConfig::Read(std::istream& is) {
00089 
00090        Config config;
00091 
00092        // Create a parser context
00093        xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
00094        if (ctxt == NULL)
00095               throw ConfigError("Failed to create parser context");
00096 
00097        // Read stream content into buffer
00098        std::streamsize size = 4096;
00099        std::streamsize length = 0;
00100        char* buffer = (char*) malloc(sizeof(char) * (size + 1));
00101        if (!buffer)
00102               throw ConfigError("Failed to allocate memory for parser context");
00103        while(length < size) {
00104               is.read(buffer + length, size - length);
00105               length += is.gcount();
00106               if (length == size)
00107                      size += 4096;
00108               else
00109                      size = length;
00110               char* buffer_ = (char*) realloc(buffer, sizeof(char) * (size + 1));
00111               if (!buffer_) {
00112                      free(buffer);
00113                      throw ConfigError("Failed to allocate memory for parser context");
00114               }
00115               buffer = buffer_;
00116        }
00117        buffer[length] = '\0';
00118 
00119        // Set Error-handler
00120        xmlSetGenericErrorFunc(NULL, (xmlGenericErrorFunc)XmlErrorHandler);
00121 
00122        // Parse and validate buffer and fill the tree
00123        xmlDocPtr doc;
00124        doc = xmlParseMemory(buffer, length);
00125        free(buffer);
00126 
00127        // Reset Error-handler
00128        xmlSetGenericErrorFunc(NULL, NULL);
00129 
00130        // Check if parsing suceeded
00131        if (doc == NULL) {
00132               xmlFreeParserCtxt(ctxt);
00133               throw ConfigError("Failed xml parsing");
00134        }
00135        // Check if validation suceeded
00136        else if (ctxt->valid == 0) {
00137               xmlFreeParserCtxt(ctxt);
00138               xmlFreeDoc(doc);
00139               throw ConfigError("Failed to validate xml");
00140        }
00141 
00142        // Free up the parser context
00143        xmlFreeParserCtxt(ctxt);
00144 
00145        FillTree(xmlDocGetRootElement(doc), config);
00146 
00147        xmlFreeDoc(doc);
00148 
00149        return config;
00150 }
00151 
00152 
00153 void XMLConfig::Write(const Config& config, std::ostream& os) {
00154 
00155        xmlDocPtr doc = NULL;
00156        xmlDtdPtr dtd = NULL;
00157        xmlNodePtr root_node = NULL;
00158        xmlNodePtr node = NULL;
00159 
00160        std::string root_name = "arc";
00161 
00162        LIBXML_TEST_VERSION;
00163 
00164        // Create a new document, a node and set it as a root node
00165        doc = xmlNewDoc(BAD_CAST "1.0");
00166        root_node = xmlNewNode(NULL, BAD_CAST root_name.c_str());
00167        xmlDocSetRootElement(doc, root_node);
00168 
00169        // Create DTD declaration.
00170        dtd = xmlCreateIntSubset(doc,
00171                                 BAD_CAST root_name.c_str(),
00172                                 NULL,
00173                                 BAD_CAST "arc.dtd");
00174 
00175        // Create the content
00176        for (std::list<ConfGrp>::const_iterator it = config.GetConfigs().begin();
00177             it != config.GetConfigs().end(); it++) {
00178 
00179               node = root_node;
00180               std::string xpath = '/' + root_name;
00181 
00182               // id attribute goes to the second level for infosys options
00183               int idlevel = (it->GetSection().substr(0, 7) == "infosys") ? 1 : 0;
00184 
00185               std::string::size_type pos = 0;
00186               while (pos != std::string::npos) {
00187                      std::string::size_type pos2 = it->GetSection().find('/', pos);
00188                      std::string key;
00189                      if (pos2 == std::string::npos) {
00190                             key = it->GetSection().substr(pos);
00191                             pos = std::string::npos;
00192                      }
00193                      else {
00194                             key = it->GetSection().substr(pos, pos2 - pos);
00195                             pos = pos2 + 1;
00196                      }
00197 
00198                      xpath += '/' + key;
00199                      if (idlevel == 0) {
00200                             if (!it->GetID().empty())
00201                                    xpath += "[@id='" + it->GetID() + "']";
00202                             else
00203                                    xpath += "[not(@id)]";
00204                      }
00205 
00206                      xmlXPathContextPtr context = xmlXPathNewContext(doc);
00207                      xmlXPathObjectPtr result =
00208                             xmlXPathEvalExpression(BAD_CAST xpath.c_str(), context);
00209                      xmlXPathFreeContext(context);
00210 
00211                      // registration blocks are not distinguished by id
00212                      if (xmlXPathNodeSetIsEmpty(result->nodesetval) ||
00213                             key == "registration") {
00214                             node = xmlNewChild(node, NULL, BAD_CAST key.c_str(), NULL);
00215                             if (idlevel == 0 && !it->GetID().empty())
00216                                    xmlSetProp(node, BAD_CAST "id",
00217                                               BAD_CAST it->GetID().c_str());
00218                      }
00219                      else
00220                             node = result->nodesetval->nodeTab[0];
00221 
00222                      idlevel--;
00223               }
00224 
00225               for (std::list<Option>::const_iterator i1 = it->GetOptions().begin();
00226                    i1 != it->GetOptions().end(); i1++) {
00227                      xmlNodePtr optnode = xmlNewChild(node, NULL,
00228                                                       BAD_CAST i1->GetAttr().c_str(),
00229                                                       BAD_CAST i1->GetValue().c_str());
00230                      for (std::map<std::string, std::string>::const_iterator
00231                               i2 = i1->GetSubOptions().begin();
00232                           i2 != i1->GetSubOptions().end(); i2++) {
00233                             xmlSetProp(optnode,
00234                                        BAD_CAST i2->first.c_str(),
00235                                        BAD_CAST i2->second.c_str());
00236                      }
00237               }
00238        }
00239 
00240        xmlChar *xmlbuff;
00241        int buffersize;
00242        xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1);
00243 
00244        // Send the buffer to the stream
00245        os << xmlbuff;
00246 
00247        // Free the buffer
00248        xmlFree(xmlbuff);
00249 
00250        // Free the document
00251        xmlFreeDoc(doc);
00252 
00253        // Free variables allocated by parser
00254        xmlCleanupParser();
00255 }
00256 
00257 }