XML.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                               SOFA :: Modules                               *
00020 *                                                                             *
00021 * Authors: The SOFA Team and external contributors (see Authors.txt)          *
00022 *                                                                             *
00023 * Contact information: contact@sofa-framework.org                             *
00024 ******************************************************************************/
00025 #include <string>
00026 #include <typeinfo>
00027 #include <stdlib.h>
00028 #include <libxml/tree.h>
00029 #include <sofa/simulation/tree/xml/XML.h>
00030 #include <sofa/helper/system/FileRepository.h>
00031 #include <sofa/helper/system/SetDirectory.h>
00032 #include <string.h>
00033 /* For loading the scene */
00034 
00035 
00036 namespace sofa
00037 {
00038 
00039 namespace simulation
00040 {
00041 
00042 namespace tree
00043 {
00044 
00045 namespace xml
00046 {
00047 
00048 using std::cout;
00049 using std::endl;
00050 
00051 
00052 #define is(n1, n2) (! xmlStrcmp((const xmlChar*)n1,(const xmlChar*)n2)) 
00053 #define getProp(n) ( xmlGetProp(cur, (const xmlChar*)n) )
00054 
00055 void recReplaceAttribute(BaseElement* node, const char* attr, const char* value, const char* nodename=NULL)
00056 {
00057     if (nodename)
00058     {
00059         if (node->getName() == nodename)
00060         {
00061 //             std::cout << "XML: Replacing attribute " << attr << " in " << node->getName() << " by " << value << std::endl;
00062             node->setAttribute(attr, value);
00063         }
00064     }
00065     else
00066     {
00067         if (node->getAttribute( attr ))
00068         {
00069 //             std::cout << "XML: Replacing attribute " << attr << " in " << node->getName() << " by " << value << std::endl;
00070             node->setAttribute(attr, value);
00071         }
00072     }
00073     BaseElement::child_iterator<> it = node->begin();
00074     BaseElement::child_iterator<> end = node->end();
00075     while (it != end)
00076     {
00077         recReplaceAttribute( it, attr, value, nodename );
00078         ++it;
00079     }
00080 }
00081 
00082 
00083 BaseElement* includeNode  (xmlNodePtr root,const char *basefilename);
00084 BaseElement* attributeNode(xmlNodePtr root,const char *basefilename);
00085 
00086 
00087 int numDefault=0;
00088 
00089 BaseElement* createNode(xmlNodePtr root, const char *basefilename, bool isRoot = false)
00090 {
00091     //if (!xmlStrcmp(root->name,(const xmlChar*)"text")) return NULL;
00092     if (root->type != XML_ELEMENT_NODE) return NULL;
00093     
00094     // handle special 'preprocessor' tags
00095     
00096     if (!xmlStrcmp(root->name,(const xmlChar*)"include"))
00097     {
00098             return includeNode(root, basefilename);     
00099     }
00100 
00101     std::string name, type;
00102     
00103     xmlChar *pname = xmlGetProp(root, (const xmlChar*) "name");
00104     xmlChar *ptype = xmlGetProp(root, (const xmlChar*) "type");
00105     
00106     if (pname != NULL)
00107     {
00108         name = (const char*)pname;
00109         xmlFree(pname);
00110     }
00111     else
00112     {
00113         name = "default";
00114 //      static int num = 0;
00115         char buf[16];
00116         sprintf(buf, "%d", numDefault);
00117         ++numDefault;
00118         name += buf;
00119     }
00120     if (ptype != NULL)
00121     {
00122         type = (const char*)ptype;
00123         xmlFree(ptype);
00124     }
00125     else
00126     {
00127         type = "default";
00128     }
00129     
00130     BaseElement* node = BaseElement::Create((const char*)root->name,name,type);
00131     
00132     if (node == NULL)
00133     {
00134         std::cerr << "Node "<<root->name<<" name "<<name<<" type "<<type<<" creation failed.\n";
00135         return NULL;
00136     }
00137     
00138     if (isRoot)
00139         node->setBaseFile( basefilename );
00140     
00141     //std::cout << "Node "<<root->name<<" name "<<name<<" type "<<type<<" created.\n";
00142     
00143     // List attributes
00144     for (xmlAttrPtr attr = root->properties; attr!=NULL; attr = attr->next)
00145     {
00146         if (attr->children==NULL) continue;
00147         if (!xmlStrcmp(attr->name,(const xmlChar*)"name")) continue;
00148         if (!xmlStrcmp(attr->name,(const xmlChar*)"type")) continue;
00149         //std::cout << attr->name << " = " << attr->children->content << std::endl;
00150         node->setAttribute((const char*)attr->name, (const char*)attr->children->content);
00151     }
00152     
00153     for (xmlNodePtr child = root->xmlChildrenNode; child != NULL; child = child->next)
00154     {
00155         BaseElement* childnode = createNode(child, basefilename);
00156         if (childnode != NULL)
00157         { 
00158                     //  if the current node is an included node, with the special name Group, we only add the objects.
00159                     if (childnode->isGroupType())
00160                     {
00161                      BaseElement::child_iterator<> it(childnode->begin());
00162                      for(;it!=childnode->end();++it) {node->addChild(it); childnode->removeChild(it);}                     
00163                     }
00164                     else
00165                     {                                                               
00166             if (!node->addChild(childnode))
00167             {
00168                 std::cerr << "Node "<<childnode->getClass()<<" name "<<childnode->getName()<<" type "<<childnode->getType()
00169                     <<" cannot be a child of node "<<node->getClass()<<" name "<<node->getName()<<" type "<<node->getType()<<std::endl;
00170                 delete childnode;
00171             }
00172                     }                     
00173         }
00174     }
00175     return node;
00176 }
00177 
00178 static void dumpNode(BaseElement* node, std::string prefix0="==", std::string prefix="  ")
00179 {
00180     std::cout << prefix0;
00181     std::cout << node->getClass()<<" name "<<node->getName()<<" type "<<node->getType()<<std::endl;
00182     BaseElement::child_iterator<> it = node->begin();
00183     BaseElement::child_iterator<> end = node->end();
00184     while (it != end)
00185     {
00186         BaseElement::child_iterator<> next = it;
00187         ++next;
00188         if (next==end) dumpNode(it, prefix+"\\-", prefix+"  ");
00189         else           dumpNode(it, prefix+"+-", prefix+"| ");
00190         it = next;
00191     }
00192 }
00193 
00194 BaseElement* processXMLLoading(const char *filename, const xmlDocPtr &doc)
00195 {
00196     xmlNodePtr root;
00197     
00198     if (doc == NULL) {
00199             std::cerr << "Failed to open " << filename << std::endl;
00200             return NULL;
00201     }
00202     
00203     root = xmlDocGetRootElement(doc);
00204     
00205     if (root == NULL) {
00206         std::cerr << "empty document" << std::endl;
00207         xmlFreeDoc(doc);
00208         return NULL;
00209     }
00210 
00211     //std::cout << "Creating XML graph"<<std::endl;
00212     std::string basefilename = 
00213         sofa::helper::system::SetDirectory::GetRelativeFromDir(filename,sofa::helper::system::SetDirectory::GetCurrentDir().c_str());
00214     BaseElement* graph = createNode(root, basefilename.c_str(), true);
00215     //std::cout << "XML Graph created"<<std::endl;
00216     xmlFreeDoc(doc);
00217     xmlCleanupParser();
00218     xmlMemoryDump();
00219     
00220     if (graph == NULL)
00221     {
00222         std::cerr << "XML Graph creation failed."<<std::endl;
00223         return NULL;
00224     }
00225     
00226     //print the graph scene
00227         //dumpNode(graph);
00228 
00229     return graph;
00230 }
00231 
00232 BaseElement* loadFromMemory(const char *filename, const char *data, unsigned int size )
00233 {
00234     //
00235     // this initialize the library and check potential ABI mismatches
00236     // between the version it was compiled for and the actual shared
00237     // library used.
00238     //
00239    LIBXML_TEST_VERSION
00240    
00241     xmlDocPtr doc; // the resulting document tree 
00242     
00243    xmlSubstituteEntitiesDefault(1);
00244    
00245    doc = xmlParseMemory(data,size);
00246    
00247    return processXMLLoading(filename, doc);
00248 }
00249 
00250 BaseElement* loadFromFile(const char *filename)
00251 {
00252      //
00253      // this initialize the library and check potential ABI mismatches
00254      // between the version it was compiled for and the actual shared
00255      // library used.
00256      //
00257     LIBXML_TEST_VERSION
00258 
00259     xmlDocPtr doc; // the resulting document tree 
00260 
00261     xmlSubstituteEntitiesDefault(1);
00262 
00263     doc = xmlParseFile(filename);
00264     
00265     return processXMLLoading(filename, doc);
00266     
00267 }
00268 
00269 
00270 BaseElement* includeNode(xmlNodePtr root,const char *basefilename)
00271 {
00272   std::string filename;
00273   xmlChar *pfilename = xmlGetProp(root, (const xmlChar*) "href");
00274   if (pfilename)
00275   {
00276     filename = (const char*)pfilename;
00277     xmlFree(pfilename);
00278   }
00279   if (filename.empty())
00280   {
00281     std::cerr << "ERROR: xml include tag requires non empty filename or href attribute." << std::endl;
00282     return NULL;
00283   }
00284 /*  std::cout << "XML: Including external file " << filename << " from " << basefilename << std::endl;*/
00285   sofa::helper::system::DataRepository.findFileFromFile(filename, basefilename);
00286   xmlDocPtr doc; // the resulting document tree
00287   doc = xmlParseFile(filename.c_str());
00288   if (doc == NULL)
00289   {
00290     std::cerr << "ERROR: Failed to parse " << filename << std::endl;
00291     return NULL;
00292   }
00293 
00294   xmlNodePtr newroot = xmlDocGetRootElement(doc);
00295   if (newroot == NULL)
00296   {
00297     std::cerr << "ERROR: empty document in " << filename << std::endl;
00298     xmlFreeDoc(doc);
00299     return NULL;
00300   }
00301   BaseElement* result = createNode(newroot, filename.c_str(), true);
00302   if (result)
00303   {    
00304     
00305     if (result->getName() == "Group") result->setGroupType(true);   
00306             // Copy attributes
00307     for (xmlAttrPtr attr = root->properties; attr!=NULL; attr = attr->next)
00308     {
00309       if (attr->children==NULL) continue;
00310       if (!xmlStrcmp(attr->name,(const xmlChar*)"href")) continue;
00311       if (!xmlStrcmp(attr->name,(const xmlChar*)"name"))
00312       { 
00313         if(!xmlStrcmp(attr->children->content,(const xmlChar*)"Group")) result->setGroupType(true);
00314         else  result->setGroupType(false);
00315         
00316         if (!result->isGroupType()) result->setName((const char*)attr->children->content);   
00317       }
00318       else
00319       {    
00320     const char* attrname = (const char*)attr->name;
00321  
00322     const char* value = (const char*)attr->children->content;
00323     if (const char* sep = strstr(attrname,"__"))
00324     { // replace attribute in nodes with a given name
00325       std::string nodename(attrname, sep);
00326       recReplaceAttribute(result, sep+2, value, nodename.c_str());
00327     }
00328     else
00329     { // replace attribute in all nodes already containing it
00330       recReplaceAttribute(result, attrname, value);
00331     }
00332       }
00333     }
00334   }
00335   xmlFreeDoc(doc);
00336   return result;
00337 }
00338 
00339 
00340 } // namespace xml
00341 
00342 } // namespace tree
00343 
00344 } // namespace simulation
00345 
00346 } // namespace sofa
00347 

Generated on Sun Nov 23 04:05:48 2008 for Sofa by  doxygen 1.5.7.1