Go to the documentation of this file.00001
00002
00003
00004 #include <threemxl/platform/io/configuration/XMLConfiguration.h>
00005 #include <string.h>
00006 #include <threemxl/platform/io/logging/Log2.h>
00007
00008 #ifdef _MSC_VER
00009 #define CONST_PATH_SEPARATOR '\\'
00010 #else
00011 #define CONST_PATH_SEPARATOR '/'
00012 #endif
00013
00014 #define CONST_XML_PATH_SEPARATOR '/' // Separator for paths defined inside XML files: <path>node/subnode/subsubnode</path>
00015
00016
00017
00018
00019
00020
00021
00022 CLog2 gXmlLog("xml");
00023
00024
00025
00026
00027
00028
00029 IXMLConfigSection::IXMLConfigSection(TiXmlElement* pElement)
00030 {
00031 mPElement = pElement;
00032 }
00033
00034 IXMLConfigSection::~IXMLConfigSection()
00035 {
00036
00037 }
00038
00039 bool IXMLConfigSection::isSection(TiXmlElement* pElement) const
00040 {
00041
00042 return pElement->FirstChildElement() != NULL;
00043 }
00044
00045 bool IXMLConfigSection::isProperty(TiXmlElement* pElement) const
00046 {
00047 TiXmlNode *firstChild = pElement->FirstChild();
00048 if (firstChild != NULL)
00049 return pElement->FirstChild()->ToText() != NULL;
00050 else
00051 return false;
00052 }
00053
00054 std::string IXMLConfigSection::name() const
00055 {
00056 return mPElement->Value();
00057 }
00058
00059 bool IXMLConfigSection::hasSection(const std::string& section) const
00060 {
00061 return mPElement->FirstChildElement(section.c_str()) != NULL;
00062 }
00063
00064 IConfigSection* IXMLConfigSection::parent()
00065 {
00066 if (mPElement->Parent() != NULL)
00067 {
00068 if (mPElement->Parent()->Type() == TiXmlElement::TINYXML_ELEMENT)
00069 return (IXMLConfigSection*)registerPendingInterface(new IXMLConfigSection((TiXmlElement*)mPElement->Parent()));
00070 else
00071 return NULL;
00072 }
00073 else
00074 return NULL;
00075 }
00076
00077 IConfigSection* IXMLConfigSection::section(const std::string& section)
00078 {
00079 TiXmlElement* foundElement = mPElement->FirstChildElement(section.c_str());
00080 if (foundElement)
00081 return (IXMLConfigSection*)registerPendingInterface(new IXMLConfigSection(foundElement));
00082 else
00083 return NULL;
00084 }
00085
00086 IConfigSection* IXMLConfigSection::firstSection()
00087 {
00088
00089 TiXmlElement* foundSection = NULL;
00090 TiXmlElement* iElement = mPElement->FirstChildElement();
00091 while (iElement != NULL)
00092 {
00093 if (isSection(iElement))
00094 {
00095 foundSection = iElement;
00096 break;
00097 }
00098 iElement = iElement->NextSiblingElement();
00099 }
00100
00101 if (foundSection)
00102 return (IXMLConfigSection*)registerPendingInterface(new IXMLConfigSection(foundSection));
00103 else
00104 return NULL;
00105 }
00106
00107 IConfigSection* IXMLConfigSection::nextSection()
00108 {
00109 TiXmlElement* foundSection = NULL;
00110 TiXmlElement* iElement = mPElement->NextSiblingElement();
00111 while (iElement != NULL)
00112 {
00113 if (isSection(iElement))
00114 {
00115 foundSection = iElement;
00116 break;
00117 }
00118 iElement = iElement->NextSiblingElement();
00119 }
00120
00121 if (foundSection)
00122 return (IXMLConfigSection*)registerPendingInterface(new IXMLConfigSection(foundSection));
00123 else
00124 return NULL;
00125 }
00126
00127 IConfigSection* IXMLConfigSection::nextSimilarSection()
00128 {
00129 TiXmlElement* foundElement = mPElement->NextSiblingElement(mPElement->Value());
00130 if (foundElement)
00131 return (IXMLConfigSection*)registerPendingInterface(new IXMLConfigSection(foundElement));
00132 else
00133 return NULL;
00134 }
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 bool IXMLConfigSection::has(const std::string& property) const
00288 {
00289 return mPElement->FirstChildElement(property.c_str()) != NULL;
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299 IConfigProperty* IXMLConfigSection::get(const std::string& property)
00300 {
00301 TiXmlElement* foundElement = mPElement->FirstChildElement(property.c_str());
00302
00303 if (foundElement)
00304 return (IXMLConfigProperty*)registerPendingInterface(new IXMLConfigProperty(foundElement));
00305 else
00306 return NULL;
00307 }
00308
00309 IConfigProperty* IXMLConfigSection::firstProperty()
00310 {
00311
00312 TiXmlElement* foundProperty = NULL;
00313 TiXmlElement* iElement = mPElement->FirstChildElement();
00314 while (iElement != NULL)
00315 {
00316 if (isProperty(iElement))
00317 {
00318 foundProperty = iElement;
00319 break;
00320 }
00321 iElement = iElement->NextSiblingElement();
00322 }
00323
00324 if (foundProperty)
00325 return (IXMLConfigProperty*)registerPendingInterface(new IXMLConfigProperty(foundProperty));
00326 else
00327 return NULL;
00328 }
00329
00330
00331
00332
00333
00334
00335 IXMLConfigProperty::IXMLConfigProperty(TiXmlElement* pElement)
00336 {
00337 mPElement = pElement;
00338 }
00339
00340 IXMLConfigProperty::~IXMLConfigProperty()
00341 {
00342
00343 }
00344
00345 bool IXMLConfigProperty::isProperty(TiXmlElement* pElement) const
00346 {
00347 if (pElement->FirstChild() != NULL)
00348 return pElement->FirstChild()->ToText() != NULL;
00349 else
00350
00351 return false;
00352 }
00353
00354 std::string IXMLConfigProperty::name() const
00355 {
00356 return mPElement->Value();
00357 }
00358
00359 std::string IXMLConfigProperty::toString() const
00360 {
00361 const char* result = mPElement->GetText();
00362 if (result)
00363 return result;
00364 else
00365 return "";
00366 }
00367
00368 void IXMLConfigProperty::set(const std::string& value)
00369 {
00370 TiXmlText* text = mPElement->FirstChild()->ToText();
00371 if (text != NULL)
00372 text->SetValue(value.c_str());
00373 }
00374
00375 IConfigProperty* IXMLConfigProperty::nextProperty()
00376 {
00377
00378 TiXmlElement* foundProperty = NULL;
00379 TiXmlElement* iElement = mPElement->NextSiblingElement();
00380 while (iElement != NULL)
00381 {
00382 if (isProperty(iElement))
00383 {
00384 foundProperty = iElement;
00385 break;
00386 }
00387 iElement = iElement->NextSiblingElement();
00388 }
00389
00390 if (foundProperty)
00391 return (IXMLConfigProperty*)registerPendingInterface(new IXMLConfigProperty(foundProperty));
00392 else
00393 return NULL;
00394 }
00395
00396 bool IXMLConfigProperty::isVerbose() const
00397 {
00398 const char* verboseStr = mPElement->Attribute("verbose");
00399 if (verboseStr != NULL)
00400 {
00401
00402 if ((strcasecmp(verboseStr, "false") == 0) || (strcasecmp(verboseStr, "0") == 0))
00403 return false;
00404 else
00405 return true;
00406 }
00407 else
00408 return false;
00409 }
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422 CXMLConfiguration::CXMLConfiguration():
00423 mFilename("")
00424 {
00425 mPRootConfigSection = NULL;
00426 }
00427
00428 CXMLConfiguration::~CXMLConfiguration()
00429 {
00430 if (mPRootConfigSection != NULL)
00431 delete mPRootConfigSection;
00432 }
00433
00434
00435 bool CXMLConfiguration::findXmlNode(TiXmlElement* rootElement, const std::string& nodePath, TiXmlElementList* resultList)
00436 {
00437 std::string::size_type searchPos = nodePath.find(CONST_XML_PATH_SEPARATOR, 0);
00438 std::string::size_type prevSearchPos = searchPos;
00439 std::string::size_type firstNodeLength = (searchPos==std::string::npos)?nodePath.length():searchPos;
00440 std::string nodeName = nodePath.substr(0, firstNodeLength);
00441 TiXmlElement *e = rootElement;
00442
00443 while ((searchPos != std::string::npos))
00444 {
00445
00446 if (!nodeName.empty())
00447 e = e->FirstChildElement(nodeName.c_str());
00448
00449 if (e == NULL)
00450 return false;
00451
00452
00453 searchPos = nodePath.find(CONST_XML_PATH_SEPARATOR, searchPos+1);
00454 if (searchPos != std::string::npos)
00455
00456 nodeName = nodePath.substr(prevSearchPos+1, searchPos-prevSearchPos-1);
00457 else
00458
00459 nodeName = nodePath.substr(prevSearchPos+1, nodePath.length()-prevSearchPos-1);
00460
00461 prevSearchPos = searchPos;
00462 }
00463
00464 if (!nodeName.empty())
00465 {
00466
00467 e = e->FirstChildElement(nodeName.c_str());
00468 if (e == NULL)
00469 return false;
00470 else
00471 resultList->push_back(e);
00472 }
00473 else
00474 {
00475
00476 for (TiXmlElement *child = e->FirstChildElement(); child; child = child->NextSiblingElement())
00477 resultList->push_back(child);
00478 }
00479
00480
00481 return true;
00482
00483 }
00484
00485 bool CXMLConfiguration::loadFile(const std::string& filename)
00486 {
00487 mFilename = filename;
00488 bool result = mXMLDocument.LoadFile(filename.c_str());
00489 if (mPRootConfigSection != NULL)
00490 delete mPRootConfigSection;
00491 TiXmlElement *rootElement = mXMLDocument.FirstChildElement(CONST_ConfRootSectionName);
00492 if (rootElement != NULL)
00493 {
00494 mPRootConfigSection = new IXMLConfigSection(rootElement);
00495
00496
00497 #ifdef XMLCONF_INCLUDETAG_DEBUG_OUTPUT
00498 mXMLDocument.SaveFile("XmlDEBUG_BeforeIncludes.xml");
00499 #endif
00500
00501 std::string filePath = mFilename.substr( 0, mFilename.rfind(CONST_PATH_SEPARATOR)+1);
00502 processIncludes(rootElement, rootElement, filePath);
00503
00504 #ifdef XMLCONF_INCLUDETAG_DEBUG_OUTPUT
00505 mXMLDocument.SaveFile("XmlDEBUG_AfterIncludes.xml");
00506 #endif
00507
00508 return result;
00509 }
00510 else
00511 return false;
00512 }
00513
00514
00515 void CXMLConfiguration::processIncludes(TiXmlElement* rootNode, TiXmlElement* node, const std::string& filePath)
00516 {
00517
00518 TiXmlElement* nextChild;
00519 for(TiXmlElement* child = node->FirstChildElement(); child; child = nextChild)
00520 {
00521 nextChild = child->NextSiblingElement();
00522 if (child->Value() == std::string("include"))
00523 {
00524
00525 TiXmlElement* filenameNode = child->FirstChildElement("filename");
00526 if (filenameNode != NULL)
00527 {
00528 std::string filename = filenameNode->GetText();
00529
00530 if (filename[1] != ':' && filename[0] != '/')
00531 {
00532
00533 filename = filePath + filename;
00534 }
00535 mLogDebugLn("Processing XML include file " << filename << " ...");
00536 TiXmlDocument includeDoc;
00537 if (includeDoc.LoadFile(filename.c_str()))
00538 {
00539
00540 TiXmlElement *includeRootNode = includeDoc.FirstChildElement(CONST_ConfRootSectionName);
00541 if (includeRootNode != NULL)
00542 {
00543
00544
00545
00546 std::string includeFilePath = filename.substr( 0, filename.rfind(CONST_PATH_SEPARATOR)+1);
00547 processIncludes(includeRootNode, includeRootNode, includeFilePath);
00548
00549 TiXmlNode *insertAfter = child;
00550 for (TiXmlElement *pathNode = child->FirstChildElement("path"); pathNode; pathNode = pathNode->NextSiblingElement("path"))
00551 {
00552 TiXmlElementList resultNodes;
00553 bool searchResult = findXmlNode(includeRootNode, pathNode->GetText(), &resultNodes);
00554 if (searchResult)
00555 {
00556 for (unsigned int iResNode=0; iResNode<resultNodes.size(); iResNode++)
00557 {
00558
00559 if ((resultNodes[iResNode] != includeRootNode->FirstChildElement(CONST_ConfConstantsSectionName))
00560 && (resultNodes[iResNode] != includeRootNode->FirstChildElement(CONST_ConfStringsSectionName)))
00561 insertAfter = node->InsertAfterChild(insertAfter, *(resultNodes[iResNode]));
00562 }
00563 }
00564 else
00565 mLogErrorLn("Could not find path \"" << pathNode->GetText() << "\" in XML file \"" << filename << "\"!");
00566 }
00567
00568 node->RemoveChild(child);
00569
00570
00571
00572
00573
00574
00575 TiXmlElement *includeConstantsSection = includeRootNode->FirstChildElement(CONST_ConfConstantsSectionName);
00576 if (includeConstantsSection != NULL)
00577 {
00578 TiXmlElement *rootConstantsSection = rootNode->FirstChildElement(CONST_ConfConstantsSectionName);
00579 if (rootConstantsSection == NULL)
00580
00581 rootNode->InsertEndChild(*includeConstantsSection);
00582 else
00583 {
00584 for (TiXmlElement *constElement = includeConstantsSection->FirstChildElement(); constElement; constElement = constElement->NextSiblingElement())
00585 rootConstantsSection->InsertEndChild(*constElement);
00586 }
00587 }
00588
00589 TiXmlElement *includeStringsSection = includeRootNode->FirstChildElement(CONST_ConfStringsSectionName);
00590 if (includeStringsSection != NULL)
00591 {
00592 TiXmlElement *rootStringsSection = rootNode->FirstChildElement(CONST_ConfStringsSectionName);
00593 if (rootStringsSection == NULL)
00594
00595 rootNode->InsertEndChild(*includeStringsSection);
00596 else
00597 {
00598 for (TiXmlElement *stringElement = includeStringsSection->FirstChildElement(); stringElement; stringElement = stringElement->NextSiblingElement())
00599 rootStringsSection->InsertEndChild(*stringElement);
00600 }
00601 }
00602 }
00603 else
00604 mLogErrorLn("Could not find root node \"" << CONST_ConfRootSectionName << "\" in XML file \"" << filename << "\"! Include paths are always relative to this root node.");
00605 }
00606 else
00607 mLogErrorLn("[ERROR] Could not load input XML file \"" << filename << "\"! Error: " << includeDoc.ErrorDesc());
00608 }
00609 }
00610 else
00611
00612 processIncludes(rootNode, child, filePath);
00613 }
00614
00615 }
00616
00617 bool CXMLConfiguration::saveFile(const std::string& filename)
00618 {
00619 if (filename == "")
00620 {
00621
00622 if (mFilename == "")
00623
00624 return false;
00625 else
00626 return mXMLDocument.SaveFile(mFilename.c_str());
00627 }
00628 else
00629
00630 return mXMLDocument.SaveFile(filename.c_str());
00631 }
00632
00633 bool CXMLConfiguration::reload()
00634 {
00635 if (mFilename == "")
00636 return false;
00637 else
00638 return mXMLDocument.LoadFile(mFilename.c_str());
00639 }
00640
00641 std::string CXMLConfiguration::errorStr()
00642 {
00643 std::string errStr(mXMLDocument.ErrorDesc());
00644 char errStr2[100];
00645 sprintf(errStr2, " at row %d, col %d", mXMLDocument.ErrorRow(), mXMLDocument.ErrorCol());
00646 return errStr + errStr2;
00647 }
00648
00649 void CXMLConfiguration::clear()
00650 {
00651 mXMLDocument.Clear();
00652 }
00653
00654
00655 CConfigSection CXMLConfiguration::root()
00656 {
00657 return CConfigSection(mPRootConfigSection);
00658 }
00659
00660 void CXMLConfiguration::print()
00661 {
00662 mXMLDocument.Print();
00663 }