00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <pch.h>
00033 #include "Env/Param/ParamXMLTree.h"
00034 #include "Env/Param/ParamXMLPrinter.h"
00035
00036 using namespace std;
00037 using namespace boost;
00038 using namespace Onikiri;
00039
00040
00041 size_t ParamXMLTree::StringHash::operator()(const String& value) const
00042 {
00043 if( value.size() < 3 ){
00044 return 0;
00045 }
00046 else{
00047 return
00048 ((value.at(0) << 8) | value.at(1)) ^
00049 value.at(2);
00050 }
00051 }
00052
00053 ParamXMLTree::Node::Node()
00054 {
00055 status.stArray = false;
00056 status.stReadOnly = true;
00057 status.stRequireDefault = true;
00058 status.stDefault = true;
00059 status.stAttribute = false;
00060 inputIndex = -1;
00061 accessed = false;
00062 }
00063
00064 ParamXMLTree::ParamXMLTree()
00065 {
00066 m_root = NodePtr( new Node() );
00067
00068
00069 m_root->name = "root";
00070 }
00071
00072 ParamXMLTree::~ParamXMLTree()
00073 {
00074 }
00075
00076 ParamXMLTree::NodePtr ParamXMLTree::CreateNewNode( const String& name )
00077 {
00078 Node* node = new Node();
00079 node->name = name;
00080 return NodePtr( node );
00081 }
00082
00083
00084 void ParamXMLTree::CheckXMLParseError( TiXmlDocument& doc, const String& from )
00085 {
00086 if( doc.Error() ){
00087 String err;
00088 err.format(
00089 "Could not load from '%s'\n%s\nline:%d col:%d\n",
00090 from.c_str(),
00091 doc.ErrorDesc(),
00092 doc.ErrorRow(),
00093 doc.ErrorCol()
00094 );
00095 THROW_RUNTIME_ERROR( err.c_str() );
00096 }
00097 }
00098
00099
00100 void ParamXMLTree::CopyTree( NodePtr dst, NodePtr src )
00101 {
00102 dst->inputIndex = src->inputIndex;
00103 dst->status = src->status;
00104 dst->value = src->value;
00105 dst->name = src->name;
00106
00107
00108 for( AttributeMap::iterator i = src->attributes.begin();
00109 i != src->attributes.end();
00110 ++i
00111 ){
00112 NodePtr newNode( new Node );
00113 *newNode = *i->second;
00114 dst->attributes[ i->first ] = newNode;
00115 }
00116
00117
00118 for( ChildMap::iterator i = src->children.begin();
00119 i != src->children.end();
00120 ++i
00121 ){
00122 const String& name = i->first;
00123 NodeArray& children = i->second;
00124 for( size_t index = 0; index < children.size(); index++ ){
00125 NodePtr newNode( new Node );
00126 dst->children[ name ].push_back(newNode);
00127 CopyTree( newNode, children[ index ] );
00128 }
00129 }
00130
00131
00132 for( ArrayPlaceMap::iterator i = src->arrayPlace.begin();
00133 i != src->arrayPlace.end();
00134 ++i
00135 ){
00136 NodePtr newNode( new Node );
00137 CopyTree( newNode, i->second );
00138 dst->arrayPlace[ i->first ] = newNode;
00139 }
00140 }
00141
00142
00143
00144 void ParamXMLTree::ConvertXMLToMap(
00145 NodePtr mapParent, TiXmlNode* xmlParent, int inputIndex, bool stDefault )
00146 {
00147 map<String, size_t> nodeCount;
00148
00149 for( TiXmlElement* childElement = xmlParent->FirstChildElement();
00150 childElement != NULL;
00151 childElement = childElement->NextSiblingElement()
00152 ){
00153
00154 NodePtr childNode( new Node() );
00155
00156
00157 const char* childName = childElement->Value();
00158 childNode->name = childName;
00159 childNode->status = mapParent->status;
00160 childNode->status.stDefault = stDefault;
00161 childNode->inputIndex = inputIndex;
00162
00163
00164 const char* pdbArrayStr = childElement->Attribute( "PDB_Array" );
00165 bool arrayPlace = pdbArrayStr ? lexical_cast<bool>(pdbArrayStr) : false;
00166
00167
00168 bool arrayNode =
00169 mapParent->arrayPlace.find( childName ) != mapParent->arrayPlace.end();
00170
00171
00172 if( arrayPlace ){
00173
00174 mapParent->arrayPlace[ childName ] = childNode;
00175 }
00176 else if( arrayNode ){
00177
00178 CopyTree( childNode, mapParent->arrayPlace[ childName ] );
00179 mapParent->children[ childName ].push_back( childNode );
00180 childNode->status.stArray = true;
00181 }
00182 else{
00183
00184 size_t index = nodeCount[ childName ];
00185 NodeArray& list = mapParent->children[ childName ];
00186 if( index >= list.size() ){
00187
00188 list.resize( index + 1 );
00189 list[index] = childNode;
00190 }
00191 else{
00192
00193 NodeStatus newStatus = childNode->status;
00194
00195 if(list[index]->status.stDefault){
00196
00197
00198
00199 newStatus.stDefault = true;
00200 }
00201
00202 childNode = list[index];
00203 childNode->status = newStatus;
00204 }
00205
00206 nodeCount[ childName ]++;
00207 }
00208
00209
00210 for( TiXmlAttribute* attr = childElement->FirstAttribute();
00211 attr != NULL;
00212 attr = attr->Next()
00213 ){
00214 const String& name = attr->Name();
00215 const String& value = attr->Value();
00216 NodePtr attribute( new Node() );
00217 attribute->name = name;
00218 attribute->value = value;
00219 attribute->inputIndex = inputIndex;
00220 childNode->attributes[ name ] = attribute;
00221
00222
00223 if( name == "PDB_Array" ){
00224 arrayPlace = lexical_cast<bool>(value);
00225 childNode->status.stArray = arrayPlace;
00226 attribute->accessed = true;
00227 }
00228 else if( name == "PDB_ReadOnly" ){
00229 childNode->status.stReadOnly = lexical_cast<bool>(value);
00230 attribute->accessed = true;
00231 }
00232 else if( name == "PDB_RequireDefaultParam" ){
00233 childNode->status.stRequireDefault = lexical_cast<bool>(value);
00234 attribute->accessed = true;
00235 }
00236 }
00237
00238
00239 ConvertXMLToMap( childNode, childElement, inputIndex, stDefault );
00240 }
00241 }
00242
00243
00244 void ParamXMLTree::ConvertMapToXML( TiXmlNode* xmlParent, NodePtr mapParent )
00245 {
00246
00247 for( ChildMap::iterator children = mapParent->children.begin();
00248 children != mapParent->children.end();
00249 ++children
00250 ){
00251
00252
00253 NodeArray& siblingList = children->second;
00254 for( size_t index = 0; index < siblingList.size(); index++ ){
00255
00256 NodePtr sibling = siblingList[ index ];
00257
00258 TiXmlElement* node = new TiXmlElement( sibling->name );
00259 xmlParent->LinkEndChild( node );
00260
00261
00262 if( sibling->value != "" && sibling->children.size() == 0 ){
00263
00264
00265 String value = sibling->value;
00266 value.find_and_replace( "<", "<" );
00267
00268 TiXmlText* text = new TiXmlText( value );
00269 node->LinkEndChild( text );
00270 }
00271
00272
00273 AttributeMap &attr = sibling->attributes;
00274 for( AttributeMap::iterator i = attr.begin();
00275 i != attr.end();
00276 ++i
00277 ){
00278 node->SetAttribute( i->first, i->second->value );
00279 }
00280
00281 ConvertMapToXML( node, sibling );
00282 }
00283 }
00284
00285
00286 }
00287
00288
00289 void ParamXMLTree::LoadXMLFile( const String& fileName, bool stDefault )
00290 {
00291 TiXmlDocument doc;
00292 doc.LoadFile( fileName );
00293 CheckXMLParseError( doc, fileName );
00294
00295 int inputIndex = (int)m_inputList.size();
00296 ConvertXMLToMap( m_root, &doc, inputIndex, stDefault );
00297 InputInfo info;
00298 info.fileName = fileName;
00299 info.type = InputInfo::IT_FILE;
00300 m_inputList.push_back( info);
00301 }
00302
00303
00304 void ParamXMLTree::LoadString( const String& xmlString, bool stDefault, const String& signature )
00305 {
00306 TiXmlDocument doc;
00307 doc.Parse( xmlString );
00308 CheckXMLParseError( doc, signature );
00309
00310 int inputIndex = (int)m_inputList.size();
00311 InputInfo info;
00312 info.fileName = signature;
00313 info.type = InputInfo::IT_STRING;
00314 m_inputList.push_back( info);
00315 ConvertXMLToMap( m_root, &doc, inputIndex, stDefault );
00316 }
00317
00318
00319 void ParamXMLTree::LoadValue( const ParamXMLPath& path, const String& value )
00320 {
00321 int inputIndex = (int)m_inputList.size();
00322 InputInfo info;
00323 info.type = InputInfo::IT_CMD;
00324 m_inputList.push_back( info);
00325
00326 Set( path, value, true );
00327 GetNode( path )->inputIndex = inputIndex;
00328 }
00329
00330
00331 void ParamXMLTree::ToXMLDoc( TiXmlDocument& doc )
00332 {
00333 ConvertMapToXML( &doc, m_root );
00334 }
00335
00336
00337 String ParamXMLTree::ToXMLString()
00338 {
00339 TiXmlDocument dstDoc;
00340
00341 TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "UTF-8", "" );
00342 dstDoc.LinkEndChild( decl );
00343
00344 ConvertMapToXML( &dstDoc, m_root );
00345
00346
00347 ParamXMLPrinter printer;
00348 dstDoc.Accept( &printer );
00349 return String( printer.CStr() );
00350 }
00351
00352
00353 void ParamXMLTree::Set( const ParamXMLPath& path, const String& value, bool forceOverWrite )
00354 {
00355 NodePtr node = m_root;
00356 for( ParamXMLPath::const_iterator i = path.begin();
00357 i != path.end();
00358 ++i
00359 ){
00360 ParamXMLPath::NodePtr pathNode = *i;
00361 if( pathNode->type == ParamXMLPath::NT_ARRAY ){
00362
00363 ChildMap::iterator next = node->children.find( pathNode->str );
00364 if( next == node->children.end() ){
00365 node->children[ pathNode->str ] = NodeArray();
00366 next = node->children.find( pathNode->str );
00367 }
00368
00369 NodeArray& nodeList = next->second;
00370 size_t arrayIndex = pathNode->arrayIndex;
00371 for( size_t i = nodeList.size(); i < arrayIndex + 1; i++ ){
00372 NodePtr newNode = NodePtr( new Node() );
00373 newNode->status = node->status;
00374 newNode->name = pathNode->str;
00375 nodeList.push_back( newNode );
00376 }
00377 node = nodeList[ arrayIndex ];
00378
00379 }
00380 else if( pathNode->type == ParamXMLPath::NT_ATTRIBUTE ){
00381
00382 NodePtr newAttr( new Node() );
00383 newAttr->name = pathNode->str;
00384 newAttr->value = value;
00385 newAttr->accessed = true;
00386
00387 AttributeMap::iterator oldAttr =
00388 node->attributes.find( pathNode->str );
00389
00390 if( oldAttr == node->attributes.end() ){
00391 node->attributes[ pathNode->str ] = newAttr;
00392 }
00393 else{
00394 if( !forceOverWrite &&
00395 node->status.stReadOnly &&
00396 oldAttr->second->value != value
00397 ){
00398 THROW_RUNTIME_ERROR(
00399 "The path '%s' is read only. The value is changed from '%s' to '%s'",
00400 path.ToString().c_str(),
00401 oldAttr->second->value.c_str(),
00402 value.c_str()
00403 );
00404 }
00405
00406 oldAttr->second = newAttr;
00407 }
00408 return;
00409 }
00410 else if( pathNode->type == ParamXMLPath::NT_COUNT_FUNCTION ){
00411
00412
00413 RUNTIME_WARNING( "Count function?" );
00414 return;
00415 }
00416 else if( pathNode->type == ParamXMLPath::NT_TEXT ){
00417
00418
00419 node->accessed = true;
00420
00421
00422
00423
00424 if( !forceOverWrite &&
00425 node->status.stReadOnly &&
00426 node->value != value
00427 ){
00428 THROW_RUNTIME_ERROR(
00429 "The path '%s' is read only. The value is changed from '%s' to '%s'",
00430 path.ToString().c_str(),
00431 node->value.c_str(),
00432 value.c_str()
00433 );
00434 }
00435 node->value = value;
00436
00437 return;
00438 }
00439 else{
00440
00441 ChildMap::iterator next = node->children.find( pathNode->str );
00442 if( next == node->children.end() ){
00443 node->children[ pathNode->str ] = NodeArray();
00444 next = node->children.find( pathNode->str );
00445 }
00446
00447 NodeArray& nodeList = next->second;
00448 if( nodeList.size() < 1 ){
00449 NodePtr newNode = NodePtr( new Node() );
00450 newNode->status = node->status;
00451 newNode->name = pathNode->str;
00452 nodeList.push_back( newNode );
00453 }
00454 node = nodeList[0];
00455 }
00456 }
00457 }
00458
00459
00460 bool ParamXMLTree::Get( const ParamXMLPath& path, String* value, NodeStatus* status )
00461 {
00462 NodePtr node = m_root;
00463 for( ParamXMLPath::const_iterator i = path.begin();
00464 i != path.end();
00465 ++i
00466 ){
00467 ParamXMLPath::NodePtr pathNode = *i;
00468 if( pathNode->type == ParamXMLPath::NT_ARRAY ){
00469
00470 ChildMap::iterator next = node->children.find( pathNode->str );
00471 if( next != node->children.end() ){
00472 if( (size_t)pathNode->arrayIndex >= next->second.size() ){
00473 if(status)
00474 *status = node->status;
00475 return false;
00476 }
00477 node = next->second[pathNode->arrayIndex];
00478 }
00479 else{
00480 if(status)
00481 *status = node->status;
00482 return false;
00483 }
00484 }
00485 else if( pathNode->type == ParamXMLPath::NT_ATTRIBUTE ){
00486
00487 AttributeMap::iterator attribute =
00488 node->attributes.find( pathNode->str );
00489
00490 if( attribute != node->attributes.end() ){
00491 if(status)
00492 *status = attribute->second->status;
00493 *value = attribute->second->value;
00494 attribute->second->accessed = true;
00495 return true;
00496 }
00497 else{
00498 if(status)
00499 *status = node->status;
00500 return false;
00501 }
00502 }
00503 else if( pathNode->type == ParamXMLPath::NT_COUNT_FUNCTION ){
00504
00505 if(status)
00506 *status = node->status;
00507 ChildMap::iterator next = node->children.find( pathNode->str );
00508 if( next != node->children.end() ){
00509 *value = lexical_cast<String>( next->second.size() );
00510 return true;
00511 }
00512 else{
00513 return false;
00514 }
00515 }
00516 else if( pathNode->type == ParamXMLPath::NT_TEXT ){
00517
00518 if(status){
00519 *status = node->status;
00520 }
00521 *value = node->value;
00522 return true;
00523 }
00524 else{
00525
00526 ChildMap::iterator next = node->children.find( pathNode->str );
00527 if( next != node->children.end() ){
00528 if( next->second.size() == 0 ){
00529 THROW_RUNTIME_ERROR(
00530 "The node map is borken.\n"
00531 "'%s' has not child.\n"
00532 "path: %s",
00533 pathNode->str.c_str(),
00534 path.ToString().c_str()
00535 );
00536 }
00537 else if( next->second.size() != 1 ){
00538 THROW_RUNTIME_ERROR(
00539 "The specified path '%s' is array.\n"
00540 "path: %s",
00541 pathNode->str.c_str(),
00542 path.ToString().c_str()
00543 );
00544 }
00545
00546 node = next->second[0];
00547 }
00548 else{
00549 if(status)
00550 *status = node->status;
00551 return false;
00552 }
00553 }
00554 }
00555 if(status)
00556 *status = node->status;
00557 return false;
00558 }
00559
00560
00561 ParamXMLTree::NodePtr
00562 ParamXMLTree::GetNode( const ParamXMLPath& path, bool addNewNode )
00563 {
00564 NodePtr node = m_root;
00565 for( ParamXMLPath::const_iterator i = path.begin();
00566 i != path.end();
00567 ++i
00568 ){
00569 ParamXMLPath::NodePtr pathNode = *i;
00570 if( pathNode->type == ParamXMLPath::NT_ARRAY ){
00571
00572 ChildMap::iterator child = node->children.find( pathNode->str );
00573
00574 if( child == node->children.end() ){
00575 if( addNewNode ){
00576
00577 node->children[ pathNode->str ] = NodeArray();
00578 child = node->children.find( pathNode->str );
00579 }
00580 else{
00581
00582 return NodePtr();
00583 }
00584 }
00585
00586 NodeArray& childList = child->second;
00587 size_t arrayIndex = pathNode->arrayIndex;
00588
00589 if( childList.size() <= arrayIndex ){
00590 if( addNewNode ){
00591
00592 for( size_t i = childList.size(); i < arrayIndex + 1; i++ ){
00593 NodePtr newNode = NodePtr( new Node() );
00594 newNode->status = node->status;
00595 newNode->name = pathNode->str;
00596 childList.push_back( newNode );
00597 }
00598 }
00599 else{
00600
00601 return NodePtr();
00602 }
00603 }
00604
00605 node = childList[ arrayIndex ];
00606
00607 }
00608 else if( pathNode->type == ParamXMLPath::NT_ATTRIBUTE ){
00609
00610 AttributeMap::iterator attribute =
00611 node->attributes.find( pathNode->str );
00612
00613 if( attribute != node->attributes.end() ){
00614 return attribute->second;
00615 }
00616 else{
00617 if( addNewNode ){
00618 if( node->status.stReadOnly ){
00619 THROW_RUNTIME_ERROR(
00620 "The path '%s' is read only.",
00621 path.ToString().c_str()
00622 );
00623 }
00624
00625 NodePtr newAttribute( new Node() );
00626 newAttribute->name = pathNode->str;
00627 node->attributes[ pathNode->str ] = newAttribute;
00628 return newAttribute;
00629 }
00630 else{
00631 return NodePtr();
00632 }
00633 }
00634 }
00635 else if( pathNode->type == ParamXMLPath::NT_COUNT_FUNCTION ){
00636
00637 THROW_RUNTIME_ERROR( "Count function is not support." );
00638 return NodePtr();
00639 }
00640 else{
00641
00642 ChildMap::iterator child = node->children.find( pathNode->str );
00643 if( child == node->children.end() ){
00644 if( addNewNode ){
00645 node->children[ pathNode->str ] = NodeArray();
00646 child = node->children.find( pathNode->str );
00647 }
00648 else{
00649 return NodePtr();
00650 }
00651 }
00652
00653 NodeArray& nodeList = child->second;
00654 if( nodeList.size() < 1 ){
00655 if( addNewNode ){
00656 NodePtr newNode = NodePtr( new Node() );
00657 newNode->status = node->status;
00658 newNode->name = pathNode->str;
00659 nodeList.push_back( newNode );
00660 }
00661 else{
00662 return NodePtr();
00663 }
00664 }
00665 node = nodeList[0];
00666 }
00667 }
00668 return node;
00669 }
00670
00671 ParamXMLTree::NodeArray*
00672 ParamXMLTree::GetNodeArray( NodePtr parentNode, const String& childName, bool addNewNode )
00673 {
00674 ChildMap::iterator child =
00675 parentNode->children.find( childName );
00676 if( child != parentNode->children.end() )
00677 return &child->second;
00678
00679 if( addNewNode )
00680 return &parentNode->children[ childName ];
00681 else
00682 return NULL;
00683 }
00684
00685 ParamXMLTree::NodeArray*
00686 ParamXMLTree::GetNodeArray( const ParamXMLPath& orgPath, bool addNewNode )
00687 {
00688 ParamXMLPath path = orgPath;
00689 path.pop_back();
00690
00691 NodePtr node = GetNode( path, addNewNode );
00692 if( node == NULL ){
00693 return NULL;
00694 }
00695
00696 return GetNodeArray( node, orgPath.back()->str, addNewNode );
00697 }
00698
00699 ParamXMLTree::NodePtr
00700 ParamXMLTree::GetAttribute( NodePtr parentNode, const String& attributeName, bool addNewNode )
00701 {
00702 AttributeMap::iterator attribute =
00703 parentNode->attributes.find( attributeName );
00704 if( attribute != parentNode->attributes.end() )
00705 return attribute->second;
00706
00707 if( addNewNode )
00708 return parentNode->attributes[ attributeName ];
00709 else
00710 return NodePtr();
00711 }
00712
00713
00714
00715 const std::vector<ParamXMLTree::InputInfo>& ParamXMLTree::GetInputList()
00716 {
00717 return m_inputList;
00718 }
00719
00720 bool ParamXMLTree::GetSourceXMLFile( const ParamXMLPath& path, String& fileName )
00721 {
00722 NodePtr node = GetNode( path );
00723 if( node == NULL ){
00724 return false;
00725 }
00726
00727 if( node->inputIndex == -1 || node->inputIndex >= (int)m_inputList.size() ){
00728 return false;
00729 }
00730
00731 InputInfo& info = m_inputList[node->inputIndex];
00732 if( info.type != InputInfo::IT_FILE )
00733 return false;
00734
00735 fileName = info.fileName;
00736 return true;
00737 }