Back to index

nordugrid-arc-nox  1.1.0~rc6
XMLNode.cpp
Go to the documentation of this file.
00001 // -*- indent-tabs-mode: nil -*-
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006 
00007 #include <iostream>
00008 #include <fstream>
00009 #include <cstring>
00010 
00011 #include "XMLNode.h"
00012 #include <libxml/xmlschemas.h>
00013 
00014 namespace Arc {
00015 
00016   static xmlNsPtr GetNamespace(xmlNodePtr node) {
00017     xmlNsPtr ns_ = NULL;
00018     if (node->type == XML_ELEMENT_NODE)
00019       ns_ = node->ns;
00020     else if (node->type == XML_ATTRIBUTE_NODE)
00021       ns_ = ((xmlAttrPtr)node)->ns;
00022     ;
00023     if (ns_)
00024       return ns_;
00025     if (node->parent)
00026       return GetNamespace(node->parent);
00027     return NULL;
00028   }
00029 
00030   static bool MatchXMLName(xmlNodePtr node1, xmlNodePtr node2) {
00031     if (strcmp((char*)(node1->name), (char*)(node2->name)) != 0)
00032       return false;
00033     if (node1->type != node2->type)
00034       return false;
00035     if ((node1->type != XML_ELEMENT_NODE) && (node1->type != XML_ATTRIBUTE_NODE))
00036       return true;
00037     xmlNsPtr ns1 = GetNamespace(node1);
00038     xmlNsPtr ns2 = GetNamespace(node2);
00039     if (ns1 != ns2)
00040       return false;
00041     return true;
00042   }
00043 
00044   static bool MatchXMLName(xmlNodePtr node, const char *name) {
00045     if (name == NULL)
00046       return false;
00047     const char *name_ = strchr(name, ':');
00048     if (name_ == NULL)
00049       name_ = name;
00050     else
00051       ++name_;
00052     if (strcmp(name_, (char*)(node->name)) != 0)
00053       return false;
00054     if (name_ == name)
00055       return true;
00056     xmlNsPtr ns_ = GetNamespace(node);
00057     std::string ns(name, name_ - name - 1);
00058     if ((ns_ == NULL) || (ns_->prefix == NULL))
00059       return ns.empty();
00060     return (ns == (const char*)(ns_->prefix));
00061   }
00062 
00063   static bool MatchXMLNamespace(xmlNodePtr node1, xmlNodePtr node2) {
00064     if (node1->type != node2->type)
00065       return false;
00066     if ((node1->type != XML_ELEMENT_NODE) && (node1->type != XML_ATTRIBUTE_NODE))
00067       return false;
00068     xmlNsPtr ns1 = GetNamespace(node1);
00069     xmlNsPtr ns2 = GetNamespace(node2);
00070     return (ns1 == ns2);
00071   }
00072 
00073   static bool MatchXMLNamespace(xmlNodePtr node, const char *uri) {
00074     if (uri == NULL)
00075       return false;
00076     xmlNsPtr ns_ = GetNamespace(node);
00077     if ((ns_ == NULL) || (ns_->href == NULL))
00078       return false;
00079     return (strcmp(uri, (const char*)(ns_->href)) == 0);
00080   }
00081 
00082   bool MatchXMLName(const XMLNode& node1, const XMLNode& node2) {
00083     return MatchXMLName(node1.node_, node2.node_);
00084   }
00085 
00086   bool MatchXMLName(const XMLNode& node, const char *name) {
00087     return MatchXMLName(node.node_, name);
00088   }
00089 
00090   bool MatchXMLName(const XMLNode& node, const std::string& name) {
00091     return MatchXMLName(node.node_, name.c_str());
00092   }
00093 
00094   bool MatchXMLNamespace(const XMLNode& node1, const XMLNode& node2) {
00095     return MatchXMLNamespace(node1.node_, node2.node_);
00096   }
00097 
00098   bool MatchXMLNamespace(const XMLNode& node, const char *uri) {
00099     return MatchXMLNamespace(node.node_, uri);
00100   }
00101 
00102   bool MatchXMLNamespace(const XMLNode& node, const std::string& uri) {
00103     return MatchXMLNamespace(node.node_, uri.c_str());
00104   }
00105 
00106   static void ReplaceNamespace(xmlNsPtr ns, xmlNodePtr node, xmlNsPtr new_ns) {
00107     if (node->type == XML_ELEMENT_NODE) {
00108       if (node->ns == ns)
00109         node->ns = new_ns;
00110       for (xmlAttrPtr node_ = node->properties; node_; node_ = node_->next)
00111         ReplaceNamespace(ns, (xmlNodePtr)node_, new_ns);
00112       for (xmlNodePtr node_ = node->children; node_; node_ = node_->next)
00113         ReplaceNamespace(ns, node_, new_ns);
00114     }
00115     else if (node->type == XML_ATTRIBUTE_NODE) {
00116       if (((xmlAttrPtr)node)->ns == ns)
00117         ((xmlAttrPtr)node)->ns = new_ns;
00118     }
00119     else
00120       return;
00121   }
00122 
00123   static void ReassignNamespace(xmlNsPtr ns, xmlNodePtr node,bool keep = false,int recursion = -1) {
00124     if(recursion >= 0) keep = true;
00125     xmlNsPtr ns_cur = node->nsDef;
00126     xmlNsPtr ns_prev = NULL;
00127     for (; ns_cur;) {
00128       if (ns == ns_cur) {
00129         ns_prev = ns_cur;
00130         ns_cur = ns_cur->next;
00131         continue;
00132       }
00133       if (ns->href && ns_cur->href && (xmlStrcmp(ns->href, ns_cur->href) == 0)) {
00134         ReplaceNamespace(ns_cur, node, ns);
00135         if(!keep) {
00136           // Unlinking namespace from tree
00137           if (ns_prev)
00138             ns_prev->next = ns_cur->next;
00139           else
00140             node->nsDef = ns_cur->next;
00141           xmlNsPtr ns_tmp = ns_cur;
00142           ns_cur = ns_cur->next;
00143           xmlFreeNs(ns_tmp);
00144         } else {
00145           ns_cur = ns_cur->next;
00146         }
00147         continue;
00148       }
00149       ns_prev = ns_cur;
00150       ns_cur = ns_cur->next;
00151     }
00152     if(recursion == 0) return;
00153     if(recursion > 0) --recursion;
00154     for (xmlNodePtr node_ = node->children; node_; node_ = node_->next)
00155       ReassignNamespace(ns, node_, keep, recursion);
00156   }
00157 
00158   // Adds new 'namespaces' to namespace definitions of 'node_'.
00159   // The 'node_' and its children are converted to new prefixes.
00160   // If keep == false all existing namespaces with same href
00161   // defined in 'node_' or children are removed.
00162   // 'recursion' limits how deep to follow children nodes. 0 for
00163   // 'node_' only. -1 for unlimited depth. If 'recursion' is set
00164   //  to >=0 then existing namespaces always kept disregarding
00165   //  value of 'keep'. Otherwise some XML node would be left
00166   //  without valid namespaces.
00167   static void SetNamespaces(const NS& namespaces, xmlNodePtr node_,bool keep = false,int recursion = -1) {
00168     for (NS::const_iterator ns = namespaces.begin();
00169          ns != namespaces.end(); ++ns) {
00170       // First check maybe this namespace is already defined
00171       xmlNsPtr ns_ = xmlSearchNsByHref(node_->doc, node_, (const xmlChar*)(ns->second.c_str()));
00172       if (ns_) {
00173         const char *prefix = (const char*)(ns_->prefix);
00174         if (!prefix) prefix = "";
00175         if (ns->first == prefix) {
00176           // Same namespace with same prefix - doing nothing
00177         }
00178         else {
00179           // Change to new prefix
00180           ns_ = NULL;
00181         }
00182       }
00183       if (!ns_) {
00184         // New namespace needed
00185         // If the namespace's name is defined then pass it to the libxml function else set the value as default namespace
00186         ns_ = xmlNewNs(node_, (const xmlChar*)(ns->second.c_str()), ns->first.empty() ? NULL : (const xmlChar*)(ns->first.c_str()));
00187         if (ns_ == NULL)
00188           // There is already namespace with same prefix (or some other error)
00189           // TODO: optional change of prefix
00190           return;
00191       }
00192       // Go through all children removing same namespaces and reassigning elements to this one.
00193       ReassignNamespace(ns_, node_, keep, recursion);
00194     }
00195   }
00196 
00197   static void GetNamespaces(NS& namespaces, xmlNodePtr node_) {
00198     if (node_ == NULL)
00199       return;
00200     if (node_->type != XML_ELEMENT_NODE)
00201       return;
00202     // TODO: Check for duplicate prefixes
00203     xmlNsPtr ns = node_->nsDef;
00204     for (; ns; ns = ns->next) {
00205       std::string prefix = ns->prefix ? (char*)(ns->prefix) : "";
00206       if (ns->href)
00207         if (namespaces[prefix].empty())
00208           namespaces[prefix] = (char*)(ns->href);
00209     }
00210     GetNamespaces(namespaces, node_->parent);
00211   }
00212 
00213   XMLNode::XMLNode(const std::string& xml)
00214     : node_(NULL),
00215       is_owner_(false),
00216       is_temporary_(false) {
00217     xmlDocPtr doc = xmlParseMemory((char*)(xml.c_str()), xml.length());
00218     if (!doc)
00219       return;
00220     xmlNodePtr p = doc->children;
00221     for (; p; p = p->next)
00222       if (p->type == XML_ELEMENT_NODE) break;
00223     if (!p) {
00224       xmlFreeDoc(doc);
00225       return;
00226     }
00227     node_ = p;
00228     is_owner_ = true;
00229   }
00230 
00231   XMLNode::XMLNode(const char *xml, int len)
00232     : node_(NULL),
00233       is_owner_(false),
00234       is_temporary_(false) {
00235     if (!xml)
00236       return;
00237     if (len == -1)
00238       len = strlen(xml);
00239     xmlDocPtr doc = xmlParseMemory((char*)xml, len);
00240     if (!doc)
00241       return;
00242     xmlNodePtr p = doc->children;
00243     for (; p; p = p->next)
00244       if (p->type == XML_ELEMENT_NODE) break;
00245     if (!p) {
00246       xmlFreeDoc(doc);
00247       return;
00248     }
00249     node_ = p;
00250     is_owner_ = true;
00251   }
00252 
00253   XMLNode::XMLNode(long ptr_addr)
00254     : node_(NULL),
00255       is_owner_(false),
00256       is_temporary_(false) {
00257     XMLNode *other = (XMLNode *)ptr_addr;
00258     (*other).New((*this));
00259   }
00260 
00261   XMLNode::XMLNode(const NS& ns, const char *name)
00262     : node_(NULL),
00263       is_owner_(false),
00264       is_temporary_(false) {
00265     xmlDocPtr doc = xmlNewDoc((const xmlChar*)"1.0");
00266     if (!doc)
00267       return;
00268     if (name == NULL)
00269       name = "";
00270     const char *name_ = strchr(name, ':');
00271     std::string node_ns_;
00272     if (name_ != NULL) {
00273       node_ns_.assign(name, name_ - name);
00274       ++name_;
00275     }
00276     else
00277       name_ = name;
00278     xmlNodePtr new_node = xmlNewNode(NULL, (const xmlChar*)name_);
00279     if (new_node == NULL) {
00280       xmlFreeDoc(doc);
00281       return;
00282     }
00283     xmlDocSetRootElement(doc, new_node);
00284     node_ = new_node;
00285     is_owner_ = true;
00286     SetNamespaces(ns, node_);
00287     node_->ns = xmlSearchNs(node_->doc, node_, (const xmlChar*)(node_ns_.c_str()));
00288   }
00289 
00290   XMLNode::~XMLNode(void) {
00291     if (is_owner_ && node_)
00292       xmlFreeDoc(node_->doc);
00293   }
00294 
00295   XMLNode XMLNode::operator[](int n) const {
00296     if (!node_)
00297       return XMLNode();
00298     xmlNodePtr p = n < 0 ? NULL : node_;
00299     for (; p; p = p->next) {
00300       if ((p->type != XML_ELEMENT_NODE) &&
00301           (p->type != XML_ATTRIBUTE_NODE))
00302         continue;
00303       if (node_->name) {
00304         if (!(p->name))
00305           continue;
00306         if (!MatchXMLName(node_, p))
00307           continue;
00308       }
00309       if ((--n) < 0)
00310         break;
00311     }
00312     return XMLNode(p);
00313   }
00314 
00315   XMLNode XMLNode::operator[](const char *name) const {
00316     if (!node_)
00317       return XMLNode();
00318     if ((node_->type != XML_ELEMENT_NODE) &&
00319         (node_->type != XML_ATTRIBUTE_NODE))
00320       return XMLNode();
00321     xmlNodePtr p = node_->children;
00322     for (; p; p = p->next) {
00323       if ((p->type != XML_ELEMENT_NODE) &&
00324           (p->type != XML_ATTRIBUTE_NODE))
00325         continue;
00326       if (MatchXMLName(p, name))
00327         break;
00328     }
00329     return XMLNode(p);
00330   }
00331 
00332   void XMLNode::operator++(void) {
00333     if (!node_)
00334       return;
00335     if (is_owner_) { // top node has no siblings
00336       xmlFreeDoc(node_->doc);
00337       node_ = NULL;
00338       is_owner_ = false;
00339       return;
00340     }
00341     xmlNodePtr p = node_->next;
00342     for (; p; p = p->next) {
00343       if (node_->type != p->type)
00344         continue;
00345       if (node_->name) {
00346         if (!(p->name))
00347           continue;
00348         if (!MatchXMLName(node_, p))
00349           continue;
00350       }
00351       break;
00352     }
00353     node_ = p;
00354   }
00355 
00356   void XMLNode::operator--(void) {
00357     if (!node_)
00358       return;
00359     if (is_owner_) { // top node has no siblings
00360       xmlFreeDoc(node_->doc);
00361       node_ = NULL;
00362       is_owner_ = false;
00363       return;
00364     }
00365     xmlNodePtr p = node_->prev;
00366     for (; p; p = p->prev) {
00367       if (node_->type != p->type)
00368         continue;
00369       if (node_->name) {
00370         if (!(p->name))
00371           continue;
00372         if (!MatchXMLName(node_, p))
00373           continue;
00374       }
00375       break;
00376     }
00377     node_ = p;
00378   }
00379 
00380   int XMLNode::Size(void) const {
00381     if (!node_)
00382       return 0;
00383     int n = 0;
00384     xmlNodePtr p = node_->children;
00385     for (; p; p = p->next) {
00386       if (p->type != XML_ELEMENT_NODE)
00387         continue;
00388       ++n;
00389     }
00390     return n;
00391   }
00392 
00393   std::string XMLNode::Name(void) const {
00394     const char *name = (node_) ? ((node_->name) ? (char*)(node_->name) : "") : "";
00395     return std::string(name);
00396   }
00397 
00398   int XMLNode::AttributesSize(void) const {
00399     if (!node_)
00400       return 0;
00401     if (node_->type != XML_ELEMENT_NODE)
00402       return 0;
00403     int n = 0;
00404     xmlAttrPtr p = node_->properties;
00405     for (; p; p = p->next) {
00406       if (p->type != XML_ATTRIBUTE_NODE)
00407         continue;
00408       ++n;
00409     }
00410     return n;
00411   }
00412 
00413   XMLNode XMLNode::Attribute(int n) {
00414     if (!node_)
00415       return XMLNode();
00416     if (node_->type != XML_ELEMENT_NODE)
00417       return XMLNode();
00418     xmlAttrPtr p = n < 0 ? NULL : node_->properties;
00419     for (; p; p = p->next) {
00420       if (p->type != XML_ATTRIBUTE_NODE)
00421         continue;
00422       if ((--n) < 0)
00423         break;
00424     }
00425     return XMLNode((xmlNodePtr)p);
00426   }
00427 
00428   XMLNode XMLNode::Attribute(const char *name) {
00429     if (!node_)
00430       return XMLNode();
00431     if (node_->type != XML_ELEMENT_NODE)
00432       return XMLNode();
00433     xmlNodePtr p = (xmlNodePtr)(node_->properties);
00434     for (; p; p = p->next) {
00435       if (p->type != XML_ATTRIBUTE_NODE)
00436         continue;
00437       if (MatchXMLName(p, name))
00438         break;
00439     }
00440     if (p)
00441       return XMLNode(p);
00442     // New temporary node
00443     return XMLNode(p);
00444   }
00445 
00446   XMLNode XMLNode::NewAttribute(const char *name) {
00447     if (!node_)
00448       return XMLNode();
00449     if (node_->type != XML_ELEMENT_NODE)
00450       return XMLNode();
00451     const char *name_ = strchr(name, ':');
00452     xmlNsPtr ns = NULL;
00453     if (name_ != NULL) {
00454       std::string ns_(name, name_ - name);
00455       ns = xmlSearchNs(node_->doc, node_, (const xmlChar*)(ns_.c_str()));
00456       ++name_;
00457     }
00458     else
00459       name_ = name;
00460     return XMLNode((xmlNodePtr)xmlNewNsProp(node_, ns, (const xmlChar*)name_, NULL));
00461   }
00462 
00463   std::string XMLNode::Prefix(void) const {
00464     if (!node_)
00465       return "";
00466     xmlNsPtr ns = GetNamespace(node_);
00467     if (!ns)
00468       return "";
00469     if (!(ns->prefix))
00470       return "";
00471     return (const char*)(ns->prefix);
00472   }
00473 
00474   std::string XMLNode::Namespace(void) const {
00475     if (!node_)
00476       return "";
00477     xmlNsPtr ns = GetNamespace(node_);
00478     if (!ns)
00479       return "";
00480     if (!(ns->href))
00481       return "";
00482     return (const char*)(ns->href);
00483   }
00484 
00485   void XMLNode::Name(const char *name) {
00486     if (!node_)
00487       return;
00488     const char *name_ = strchr(name, ':');
00489     xmlNsPtr ns = NULL;
00490     if (name_ != NULL) {
00491       std::string ns_(name, name_ - name);
00492       // ns element is located at same place in Node and Attr elements
00493       ns = xmlSearchNs(node_->doc, node_, (const xmlChar*)(ns_.c_str()));
00494       ++name_;
00495     }
00496     else
00497       name_ = name;
00498     xmlNodeSetName(node_, (const xmlChar*)name_);
00499     if (ns)
00500       node_->ns = ns;
00501   }
00502 
00503   XMLNode XMLNode::Child(int n) {
00504     if (!node_)
00505       return XMLNode();
00506     if (node_->type != XML_ELEMENT_NODE)
00507       return XMLNode();
00508     xmlNodePtr p = n < 0 ? NULL : node_->children;
00509     for (; p; p = p->next) {
00510       if (p->type != XML_ELEMENT_NODE)
00511         continue;
00512       if ((--n) < 0)
00513         break;
00514     }
00515     return XMLNode(p);
00516   }
00517 
00518   XMLNode::operator std::string(void) const {
00519     std::string content;
00520     if (!node_)
00521       return content;
00522     for (xmlNodePtr p = node_->children; p; p = p->next) {
00523       if (p->type != XML_TEXT_NODE)
00524         continue;
00525       xmlChar *buf = xmlNodeGetContent(p);
00526       if (!buf)
00527         continue;
00528       content += (char*)buf;
00529       xmlFree(buf);
00530     }
00531     return content;
00532   }
00533 
00534   XMLNode& XMLNode::operator=(const char *content) {
00535     if (!node_)
00536       return *this;
00537     if (!content)
00538       content = "";
00539     xmlChar *encode = xmlEncodeSpecialChars(node_->doc, (xmlChar*)content);
00540     if (!encode)
00541       encode = (xmlChar*)"";
00542     xmlNodeSetContent(node_, encode);
00543     xmlFree(encode);
00544     return *this;
00545   }
00546 
00547 
00548   XMLNode XMLNode::NewChild(const char *name, const NS& namespaces, int n, bool global_order) {
00549     XMLNode x = NewChild("", n, global_order); // placeholder
00550     x.Namespaces(namespaces);
00551     x.Name(name);
00552     return x;
00553   }
00554 
00555   XMLNode XMLNode::NewChild(const char *name, int n, bool global_order) {
00556     if (node_ == NULL)
00557       return XMLNode();
00558     if (node_->type != XML_ELEMENT_NODE)
00559       return XMLNode();
00560     const char *name_ = strchr(name, ':');
00561     xmlNsPtr ns = NULL;
00562     if (name_ != NULL) {
00563       std::string ns_(name, name_ - name);
00564       ns = xmlSearchNs(node_->doc, node_, (const xmlChar*)(ns_.c_str()));
00565       ++name_;
00566     }
00567     else
00568       name_ = name;
00569     xmlNodePtr new_node = xmlNewNode(ns, (const xmlChar*)name_);
00570     if (new_node == NULL)
00571       return XMLNode();
00572     if (n < 0)
00573       return XMLNode(xmlAddChild(node_, new_node));
00574     XMLNode old_node = global_order ? Child(n) : operator[](name)[n];
00575     if (!old_node)
00576       // TODO: find last old_node
00577       return XMLNode(xmlAddChild(node_, new_node));
00578     if (old_node)
00579       return XMLNode(xmlAddPrevSibling(old_node.node_, new_node));
00580     return XMLNode(xmlAddChild(node_, new_node));
00581   }
00582 
00583   XMLNode XMLNode::NewChild(const XMLNode& node, int n, bool global_order) {
00584     if (node_ == NULL)
00585       return XMLNode();
00586     if (node.node_ == NULL)
00587       return XMLNode();
00588     if (node_->type != XML_ELEMENT_NODE)
00589       return XMLNode();
00590     // TODO: Add new attribute if 'node' is attribute
00591     if (node.node_->type != XML_ELEMENT_NODE)
00592       return XMLNode();
00593     xmlNodePtr new_node = xmlDocCopyNode(node.node_, node_->doc, 1);
00594     if (new_node == NULL)
00595       return XMLNode();
00596     if (n < 0)
00597       return XMLNode(xmlAddChild(node_, new_node));
00598     std::string name;
00599     xmlNsPtr ns = GetNamespace(new_node);
00600     if (ns != NULL) {
00601       if (ns->prefix != NULL)
00602         name = (char*)ns->prefix;
00603       name += ":";
00604     }
00605     if (new_node->name)
00606       name += (char*)(new_node->name);
00607     XMLNode old_node = global_order ? Child(n) : operator[](name)[n];
00608     if (!old_node)
00609       // TODO: find last old_node
00610       return XMLNode(xmlAddChild(node_, new_node));
00611     if (old_node)
00612       return XMLNode(xmlAddPrevSibling(old_node.node_, new_node));
00613     return XMLNode(xmlAddChild(node_, new_node));
00614   }
00615 
00616   void XMLNode::Replace(const XMLNode& node) {
00617     if (node_ == NULL)
00618       return;
00619     if (node.node_ == NULL)
00620       return;
00621     if (node_->type != XML_ELEMENT_NODE)
00622       return;
00623     if (node.node_->type != XML_ELEMENT_NODE)
00624       return;
00625     xmlNodePtr new_node = xmlDocCopyNode(node.node_, node_->doc, 1);
00626     if (new_node == NULL)
00627       return;
00628     xmlReplaceNode(node_, new_node);
00629     xmlFreeNode(node_);
00630     node_ = new_node;
00631     return;
00632   }
00633 
00634   void XMLNode::New(XMLNode& new_node) const {
00635     if (new_node.is_owner_ && new_node.node_)
00636       xmlFreeDoc(new_node.node_->doc);
00637     new_node.is_owner_ = false;
00638     new_node.node_ = NULL;
00639     if (node_ == NULL)
00640       return;
00641     // TODO: Copy attribute node too
00642     if (node_->type != XML_ELEMENT_NODE)
00643       return;
00644     xmlDocPtr doc = xmlNewDoc((const xmlChar*)"1.0");
00645     if (doc == NULL)
00646       return;
00647     new_node.node_ = xmlDocCopyNode(node_, doc, 1);
00648     if (new_node.node_ == NULL)
00649       return;
00650     xmlDocSetRootElement(doc, new_node.node_);
00651     new_node.is_owner_ = true;
00652     return;
00653   }
00654 
00655   void XMLNode::Move(XMLNode& node) {
00656     if (node.is_owner_ && node.node_)
00657       xmlFreeDoc(node.node_->doc);
00658     node.is_owner_ = false;
00659     node.node_ = NULL;
00660     if (node_ == NULL)
00661       return;
00662     // TODO: Copy attribute node too
00663     if (node_->type != XML_ELEMENT_NODE) {
00664       return;
00665     }
00666     if(is_owner_) {
00667       // Owner also means top level. So just copy and clean.
00668       node.node_=node_;
00669       node.is_owner_=true;
00670       node_=NULL; is_owner_=false;
00671       return;
00672     }
00673     // Otherwise unlink this node and make a new document of it
00674     // New(node); Destroy();
00675     xmlDocPtr doc = xmlNewDoc((const xmlChar*)"1.0");
00676     if (doc == NULL) return;
00677     xmlUnlinkNode(node_);
00678     node.node_ = node_; node_ = NULL;
00679     xmlDocSetRootElement(doc, node.node_);
00680     node.is_owner_ = true;
00681     return;
00682   }
00683 
00684   void XMLNode::Swap(XMLNode& node) {
00685     xmlNodePtr tmp_node_ = node.node_;
00686     bool tmp_is_owner_ = node.is_owner_;
00687     node.node_ = node_;
00688     node.is_owner_ = is_owner_;
00689     node_ = tmp_node_;
00690     is_owner_ = tmp_is_owner_;
00691   }
00692 
00693   void XMLNode::Exchange(XMLNode& node) {
00694     if(((node_ == NULL) || is_owner_) &&
00695        ((node.node_ == NULL) || node.is_owner_)) {
00696       Swap(node); // ?
00697       return;
00698     }
00699     xmlNodePtr node1 = node_;
00700     xmlNodePtr node2 = node.node_;
00701     if(node1 && (node1->type != XML_ELEMENT_NODE)) return;
00702     if(node2 && (node2->type != XML_ELEMENT_NODE)) return;
00703     node_ = NULL; node.node_ = NULL;
00704     xmlNodePtr neighb1 = node1?(node1->next):NULL;
00705     xmlNodePtr neighb2 = node2?(node2->next):NULL;
00706     xmlNodePtr parent1 = node1?(node1->parent):NULL;
00707     xmlNodePtr parent2 = node2?(node2->parent):NULL;
00708     xmlDocPtr doc1 = node1?(node1->doc):NULL;
00709     xmlDocPtr doc2 = node2?(node2->doc):NULL;
00710     // In current implementation it is dangerous to move
00711     // top level element if node is not owning document
00712     if((parent1 == NULL) && (!is_owner_)) return;
00713     if((parent2 == NULL) && (!node.is_owner_)) return;
00714     xmlUnlinkNode(node1);
00715     xmlUnlinkNode(node2);
00716     if(parent1) {
00717       if(neighb1) {
00718         xmlAddPrevSibling(neighb1,node2);
00719       } else {
00720         xmlAddChild(parent1,node2);
00721       }
00722     } else if(doc1) {
00723       xmlDocSetRootElement(doc1,node2);
00724     } else {
00725       // Should not happen
00726       xmlFreeNode(node2); node2 = NULL;
00727     }
00728     if(parent2) {
00729       if(neighb2) {
00730         xmlAddPrevSibling(neighb2,node1);
00731       } else {
00732         xmlAddChild(parent2,node1);
00733       }
00734     } else if(doc2) {
00735       xmlDocSetRootElement(doc2,node1);
00736     } else {
00737       // Should not happen
00738       xmlFreeNode(node1); node1 = NULL;
00739     }
00740     node_ = node2;
00741     node.node_ = node1;
00742   }
00743 
00744   void XMLNode::Namespaces(const NS& namespaces, bool keep, int recursion) {
00745     if (node_ == NULL)
00746       return;
00747     if (node_->type != XML_ELEMENT_NODE)
00748       return;
00749     SetNamespaces(namespaces, node_, keep, recursion);
00750   }
00751 
00752   NS XMLNode::Namespaces(void) {
00753     NS namespaces;
00754     if (node_ == NULL)
00755       return namespaces;
00756     if (node_->type != XML_ELEMENT_NODE)
00757       return namespaces;
00758     GetNamespaces(namespaces, node_);
00759     return namespaces;
00760   }
00761 
00762   std::string XMLNode::NamespacePrefix(const char *urn) {
00763     if (node_ == NULL)
00764       return "";
00765     xmlNsPtr ns_ = xmlSearchNsByHref(node_->doc, node_, (const xmlChar*)urn);
00766     if (!ns_)
00767       return "";
00768     return (char*)(ns_->prefix);
00769   }
00770 
00771   void XMLNode::Destroy(void) {
00772     if (node_ == NULL)
00773       return;
00774     if (is_owner_) {
00775       xmlFreeDoc(node_->doc);
00776       node_ = NULL;
00777       is_owner_ = false;
00778       return;
00779     }
00780     if (node_->type == XML_ELEMENT_NODE) {
00781       xmlUnlinkNode(node_);
00782       xmlFreeNode(node_);
00783       node_ = NULL;
00784       return;
00785     }
00786     if (node_->type == XML_ATTRIBUTE_NODE) {
00787       xmlRemoveProp((xmlAttrPtr)node_);
00788       node_ = NULL;
00789       return;
00790     }
00791   }
00792 
00793   XMLNodeList XMLNode::Path(const std::string& path) {
00794     XMLNodeList res;
00795     std::string::size_type name_s = 0;
00796     std::string::size_type name_e = path.find('/', name_s);
00797     if (name_e == std::string::npos)
00798       name_e = path.length();
00799     res.push_back(*this);
00800     for (;;) {
00801       if (res.size() <= 0)
00802         return res;
00803       XMLNodeList::iterator node = res.begin();
00804       std::string node_name = path.substr(name_s, name_e - name_s);
00805       int nodes_num = res.size();
00806       for (int n = 0; n < nodes_num; ++n) {
00807         for (int cn = 0;; ++cn) {
00808           XMLNode cnode = (*node).Child(cn);
00809           if (!cnode)
00810             break;
00811           if (MatchXMLName(cnode, node_name))
00812             res.push_back(cnode);
00813         }
00814         ++node;
00815       }
00816       res.erase(res.begin(), node);
00817       if (name_e >= path.length())
00818         break;
00819       name_s = name_e + 1;
00820       name_e = path.find('/', name_s);
00821       if (name_e == std::string::npos)
00822         name_e = path.length();
00823     }
00824     return res;
00825   }
00826 
00827   XMLNodeList XMLNode::XPathLookup(const std::string& xpathExpr, const NS& nsList) {
00828     std::list<XMLNode> retlist;
00829     if (node_ == NULL)
00830       return retlist;
00831     if (node_->type != XML_ELEMENT_NODE)
00832       return retlist;
00833     xmlDocPtr doc = node_->doc;
00834     if (doc == NULL)
00835       return retlist;
00836     xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
00837 
00838     for (NS::const_iterator ns = nsList.begin(); ns != nsList.end(); ++ns)
00839       xmlXPathRegisterNs(xpathCtx, (xmlChar*)ns->first.c_str(), (xmlChar*)ns->second.c_str());
00840 
00841     xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar*)(xpathExpr.c_str()), xpathCtx);
00842 
00843     if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr) {
00844       xmlNodeSetPtr nodes = xpathObj->nodesetval;
00845       int size = nodes->nodeNr;
00846       for (int i = 0; i < size; ++i)
00847         if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
00848           xmlNodePtr cur = nodes->nodeTab[i];
00849           xmlNodePtr parent = cur;
00850           for (; parent; parent = parent->parent)
00851             if (parent == node_)
00852               break;
00853           if (parent)
00854             retlist.push_back(XMLNode(cur));
00855         }
00856     }
00857 
00858     xmlXPathFreeObject(xpathObj);
00859     xmlXPathFreeContext(xpathCtx);
00860 
00861     return retlist;
00862   }
00863 
00864   XMLNode XMLNode::GetRoot(void) {
00865     if (node_ == NULL)
00866       return XMLNode();
00867     xmlDocPtr doc = node_->doc;
00868     if (doc == NULL)
00869       return XMLNode();
00870     return XMLNode(doc->children);
00871   }
00872 
00873   XMLNode XMLNode::Parent(void) {
00874     if (node_ == NULL)
00875       return XMLNode();
00876     if (node_->type == XML_ELEMENT_NODE)
00877       return XMLNode(node_->parent);
00878     if (node_->type == XML_ATTRIBUTE_NODE)
00879       return XMLNode(((xmlAttrPtr)node_)->parent);
00880     return XMLNode();
00881   }
00882 
00883   XMLNode& XMLNode::operator=(const XMLNode& node) {
00884     if (is_owner_ && node_) {
00885       xmlDocPtr doc = node_->doc;
00886       if (doc != NULL)
00887         xmlFreeDoc(doc);
00888     }
00889     node_ = node.node_;
00890     is_owner_ = false;
00891     is_temporary_ = node.is_temporary_;
00892     return *this;
00893   }
00894 
00895   static int write_to_string(void* context,const char* buffer,int len) {
00896     if(!context) return -1;
00897     std::string* str = (std::string*)context;
00898     if(len <= 0) return 0;
00899     if(!buffer) return -1;
00900     str->append(buffer,len);
00901     return len;
00902   }
00903 
00904   static int close_string(void* context) {
00905     if(!context) return -1;
00906     return 0;
00907   }
00908 
00909   void XMLNode::GetDoc(std::string& out_xml_str, bool user_friendly) const {
00910     out_xml_str.resize(0);
00911     if (!node_)
00912       return;
00913     xmlDocPtr doc = node_->doc;
00914     if (doc == NULL)
00915       return;
00916     xmlOutputBufferPtr buf =
00917      xmlOutputBufferCreateIO(&write_to_string,&close_string,&out_xml_str,NULL);
00918     if(buf == NULL)
00919       return;
00920 /*
00921     xmlChar *buf = NULL;
00922     int bufsize = 0;
00923     if (user_friendly)
00924       xmlDocDumpFormatMemory(doc, &buf, &bufsize, 1);
00925     else
00926       xmlDocDumpMemory(doc, &buf, &bufsize);
00927     if (buf) {
00928       out_xml_str = (char*)buf;
00929       xmlFree(buf);
00930     }
00931 */
00932     // Note xmlSaveFormatFileTo/xmlSaveFileTo call xmlOutputBufferClose
00933     if (user_friendly)
00934       xmlSaveFormatFileTo(buf, doc, (const char*)(doc->encoding), 1);
00935     else
00936       xmlSaveFileTo(buf, doc, (const char*)(doc->encoding));
00937   }
00938 
00939   void XMLNode::GetXML(std::string& out_xml_str, bool user_friendly) const {
00940     out_xml_str.resize(0);
00941     if (!node_)
00942       return;
00943     if (node_->type != XML_ELEMENT_NODE)
00944       return;
00945     xmlDocPtr doc = node_->doc;
00946     if (doc == NULL)
00947       return;
00948 /*
00949     xmlBufferPtr buf = xmlBufferCreate();
00950     xmlNodeDump(buf, doc, node_, 0, user_friendly ? 1 : 0);
00951     out_xml_str = (char*)(buf->content);
00952     xmlBufferFree(buf);
00953 */
00954     xmlOutputBufferPtr buf =
00955      xmlOutputBufferCreateIO(&write_to_string,&close_string,&out_xml_str,NULL);
00956     if(buf == NULL)
00957       return;
00958     xmlNodeDumpOutput(buf, doc, node_, 0, user_friendly ? 1 : 0, (const char*)(doc->encoding));
00959     xmlOutputBufferClose(buf);
00960   }
00961 
00962   void XMLNode::GetXML(std::string& out_xml_str, const std::string& encoding, bool user_friendly) const {
00963     out_xml_str.resize(0);
00964     if (!node_)
00965       return;
00966     if (node_->type != XML_ELEMENT_NODE)
00967       return;
00968     xmlDocPtr doc = node_->doc;
00969     if (doc == NULL)
00970       return;
00971     xmlCharEncodingHandlerPtr handler = NULL;
00972     handler = xmlFindCharEncodingHandler(encoding.c_str());
00973     if (handler == NULL)
00974       return;
00975     //xmlOutputBufferPtr buf = xmlAllocOutputBuffer(handler);
00976     xmlOutputBufferPtr buf =
00977      xmlOutputBufferCreateIO(&write_to_string,&close_string,&out_xml_str,NULL);
00978     if(buf == NULL)
00979       return;
00980     xmlNodeDumpOutput(buf, doc, node_, 0, user_friendly ? 1 : 0, encoding.c_str());
00981     xmlOutputBufferFlush(buf);
00982     //out_xml_str = (char*)(buf->conv ? buf->conv->content : buf->buffer->content);
00983     xmlOutputBufferClose(buf);
00984   }
00985 
00986   bool XMLNode::SaveToStream(std::ostream& out) const {
00987     std::string s;
00988     GetXML(s);
00989     out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl;
00990     out << s;
00991     return (bool)out;
00992   }
00993 
00994   bool XMLNode::SaveToFile(const std::string& file_name) const {
00995     std::ofstream out(file_name.c_str(), std::ios::out);
00996     if (!out)
00997       return false;
00998     bool r = SaveToStream(out);
00999     out.close();
01000     return r;
01001   }
01002 
01003   std::ostream& operator<<(std::ostream& out, const XMLNode& node) {
01004     node.SaveToStream(out);
01005     return out;
01006   }
01007 
01008   bool XMLNode::ReadFromStream(std::istream& in) {
01009     std::string s;
01010     std::getline<char>(in, s, 0);
01011     if (!in)
01012       return false;
01013     xmlDocPtr doc = xmlParseMemory((char*)(s.c_str()), s.length());
01014     if (doc == NULL)
01015       return false;
01016     xmlNodePtr p = doc->children;
01017     for (; p; p = p->next)
01018       if (p->type == XML_ELEMENT_NODE) break;
01019     if (!p) {
01020       xmlFreeDoc(doc);
01021       return false;
01022     }
01023     if (node_ != NULL)
01024       if (is_owner_) {
01025         xmlFreeDoc(node_->doc);
01026         node_ = NULL;
01027         is_owner_ = false;
01028       }
01029     node_ = p;
01030     if (node_)
01031       is_owner_ = true;
01032     return true;
01033   }
01034 
01035   bool XMLNode::ReadFromFile(const std::string& file_name) {
01036     std::ifstream in(file_name.c_str(), std::ios::in);
01037     if (!in)
01038       return false;
01039     bool r = ReadFromStream(in);
01040     in.close();
01041     return r;
01042   }
01043 
01044   std::istream& operator>>(std::istream& in, XMLNode& node) {
01045     node.ReadFromStream(in);
01046     return in;
01047   }
01048 
01049   bool XMLNode::Validate(const std::string &schema_file_name, std::string &err_msg) {
01050     // create parser ctxt for schema accessible on schemaPath
01051     xmlSchemaParserCtxtPtr schemaParser = xmlSchemaNewParserCtxt(schema_file_name.c_str());
01052     if (!schemaParser) {
01053         err_msg = "Cannot load schema";
01054         return false;
01055     }
01056     // parse schema
01057     xmlSchemaPtr schema = xmlSchemaParse(schemaParser);
01058     if (!schema) {
01059         xmlSchemaFreeParserCtxt(schemaParser);
01060         err_msg = "Cannot parse schmea";
01061         return false;
01062     }
01063     xmlSchemaFreeParserCtxt(schemaParser);
01064 
01065     // create schema validation context
01066     xmlSchemaValidCtxtPtr validityCtx = xmlSchemaNewValidCtxt(schema);
01067     if (!validityCtx) {
01068         xmlSchemaFree(schema);
01069         err_msg = "Cannot create validation context";
01070         return false;
01071     }
01072 
01073     // Set contect collectoors
01074     xmlSchemaSetValidErrors(validityCtx,
01075                             (xmlSchemaValidityErrorFunc) fprintf,
01076                             (xmlSchemaValidityWarningFunc) fprintf,
01077                             stderr);
01078     // validate against schema
01079     bool result = (xmlSchemaValidateDoc(validityCtx, node_->doc) == 0);
01080 
01081     // free resources and return result
01082     xmlSchemaFreeValidCtxt(validityCtx);
01083     xmlSchemaFree(schema);
01084 
01085     return result;
01086   }
01087 
01088   XMLNodeContainer::XMLNodeContainer(void) {}
01089 
01090   XMLNodeContainer::XMLNodeContainer(const XMLNodeContainer& container) {
01091     operator=(container);
01092   }
01093 
01094   XMLNodeContainer::~XMLNodeContainer(void) {
01095     for (std::vector<XMLNode*>::iterator n = nodes_.begin();
01096          n != nodes_.end(); ++n)
01097       delete *n;
01098   }
01099 
01100   XMLNodeContainer& XMLNodeContainer::operator=(const XMLNodeContainer& container) {
01101     for (std::vector<XMLNode*>::iterator n = nodes_.begin();
01102          n != nodes_.end(); ++n)
01103       delete *n;
01104     for (std::vector<XMLNode*>::const_iterator n = container.nodes_.begin();
01105          n != container.nodes_.end(); ++n) {
01106       if ((*n)->is_owner_)
01107         AddNew(*(*n));
01108       else
01109         Add(*(*n));
01110     }
01111     return *this;
01112   }
01113 
01114   void XMLNodeContainer::Add(const XMLNode& node) {
01115     XMLNode *new_node = new XMLNode(node);
01116     nodes_.push_back(new_node);
01117   }
01118 
01119   void XMLNodeContainer::Add(const std::list<XMLNode>& nodes) {
01120     for (std::list<XMLNode>::const_iterator n = nodes.begin();
01121          n != nodes.end(); ++n)
01122       Add(*n);
01123   }
01124 
01125   void XMLNodeContainer::AddNew(const XMLNode& node) {
01126     XMLNode *new_node = new XMLNode();
01127     node.New(*new_node);
01128     nodes_.push_back(new_node);
01129   }
01130 
01131   void XMLNodeContainer::AddNew(const std::list<XMLNode>& nodes) {
01132     for (std::list<XMLNode>::const_iterator n = nodes.begin();
01133          n != nodes.end(); ++n)
01134       AddNew(*n);
01135   }
01136 
01137   int XMLNodeContainer::Size(void) const {
01138     return nodes_.size();
01139   }
01140 
01141   XMLNode XMLNodeContainer::operator[](int n) {
01142     if (n < 0)
01143       return XMLNode();
01144     if (n >= nodes_.size())
01145       return XMLNode();
01146     return *nodes_[n];
01147   }
01148 
01149   std::list<XMLNode> XMLNodeContainer::Nodes(void) {
01150     std::list<XMLNode> r;
01151     for (std::vector<XMLNode*>::iterator n = nodes_.begin();
01152          n != nodes_.end(); ++n)
01153       r.push_back(**n);
01154     return r;
01155   }
01156 
01157 } // namespace Arc