Marlin  01.17.01
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
XMLParser.cc
Go to the documentation of this file.
1 
2 #include "marlin/XMLParser.h"
3 #include "marlin/Exceptions.h"
4 #include "marlin/tinyxml.h"
5 
6 #include <algorithm>
7 
8 #include <sstream>
9 #include <set>
10 
11 
12 #include <memory>
13 
14 namespace marlin{
15 
16  // open steering file with processor names
17  XMLParser::XMLParser( const std::string& fileName, bool forCCheck ) :
18  _current(NULL) , _fileName( fileName ), _forCCheck( forCCheck ) {
19  }
20 
22  }
23 
25 
26 
28  bool loadOkay = _doc->LoadFile(_fileName ) ;
29 
30  if( !loadOkay ) {
31 
32  std::stringstream str ;
33 
34  str << "XMLParser::parse error in file [" << _fileName
35  << ", row: " << _doc->ErrorRow() << ", col: " << _doc->ErrorCol() << "] : "
36  << _doc->ErrorDesc() ;
37 
38  throw ParseException( str.str() ) ;
39  }
40 
41  // TiXmlHandle docHandle( _doc );
42 
43  TiXmlElement* root = _doc->RootElement();
44  if( root==0 || strcmp(root->Value(),"marlin") != 0 ){
45 
46  throw ParseException(std::string( "XMLParser::parse : no root tag <marlin>...</marlin> found in ")
47  + _fileName ) ;
48  }
49 
50  TiXmlNode* section = 0 ;
51 
52  section = root->FirstChild("constants") ;
54 
55  if( section != 0 ) {
56  processConstants( section , constants ) ;
57  } else {
58  std::cout << "XMLParser::parse : no <constants/> section found in " << _fileName << std::endl ;
59  }
60 
61  processIncludeElements( root , constants ) ;
62 
63  _map[ "Global" ] = std::make_shared<StringParameters>();
64  StringParameters* globalParameters = _map[ "Global" ].get();
65 
66  section = root->FirstChild("global") ;
67 
68  if( section != 0 ){
69  _current = _map[ "Global" ].get() ;
70  parametersFromNode( section , constants ) ;
71 
72  } else {
73 
74  throw ParseException(std::string( "XMLParser::parse : no <global/> section found in ")
75  + _fileName ) ;
76  }
77 
78  for( TiXmlElement *p = section->FirstChildElement( "parameter" ) ; p ; p = p->NextSiblingElement( "parameter" ) ) {
79 
80  const char* attr = p->Attribute( "name" );
81 
82  if( attr != 0 && std::string( attr ) == "OutputSteeringFile" ) {
83  // in case the file name is not in the attribute
84  // "value" but in the element text
85  // The clear method clears only the child elements, not the element itself
86  p->Clear() ;
87  // Overwrite this value to make sure we don't re-generate
88  // inifinitely steering files
89  p->SetAttribute( "value" , "" );
90 
91  break;
92  }
93  }
94 
95  // create global parameter ActiveProcessors from <execute> section
96  // TiXmlElement activeProcessorItem( "parameter" );
97  // activeProcessorItem.SetAttribute( "name", "ActiveProcessors" );
98 
99  std::vector<std::string> activeProcs ;
100  activeProcs.push_back("ActiveProcessors") ;
101 
102  std::vector<std::string> procConds ;
103  procConds.push_back("ProcessorConditions") ;
104 
105  // variable used to check for duplicate processor entries in the execute section
106  std::set<std::string> procList ;
107 
108  section = root->FirstChild("execute") ;
109  if( section != 0 ){
110 
111  // preprocess groups: replace with <processor/> tags
112  replacegroups( section ) ;
113 
114  // process processor conditions:
115  processconditions( section , "" ) ;
116 
117  // std::cout << " execute after group replacement : " << *section << std::
118 
119  TiXmlNode* proc = 0 ;
120  while( ( proc = section->IterateChildren( "processor", proc ) ) != 0 ){
121 
122  std::string procName( getAttribute( proc, "name") );
123  performConstantReplacement( procName, constants ) ;
124 
125  //std::cout << "looping over processor " + procName << std::endl;
126 
127  // exit if processor defined more than once in the execute section
128  if( procList.find( procName ) != procList.end() ){
129  throw ParseException(std::string( "XMLParser::parse : "+ procName +" defined more than once in <execute> section ") );
130  }
131  procList.insert( procName ) ;
132 
133  activeProcs.push_back( procName ) ;
134 
135  std::string condition( getAttribute( proc,"condition") ) ;
136 
137  performConstantReplacement( condition, constants ) ;
138 
139  if( condition.size() == 0 )
140  condition += "true" ;
141 
142  procConds.push_back( condition ) ;
143 
144  }
145 
146  } else {
147 
148  throw ParseException(std::string( "XMLParser::parse : no <execute/> section found in ")
149  + _fileName ) ;
150  }
151 
152  _current->add( activeProcs ) ;
153  _current->add( procConds ) ;
154 
155 
156 
157  // preprocess groups: ---------------------------------------------------------------------------------
158  // simply copy all group parameters to the processors
159  // and then copy the processors to the root node <Marlin>
160  // 'section' comes from above as first execute child, get the next section so we
161  // do not cleanup the execute section in loop body below, only the groups
162  TiXmlNode* nextSection = root->IterateChildren("group", section);
163  while((section = nextSection) != 0){
164  nextSection = root->IterateChildren("group", section);
165 
166  std::vector<TiXmlNode*> groupParams ;
167 
168  TiXmlNode* param = 0 ;
169  while( ( param = section->IterateChildren( "parameter" , param ) ) != 0 ){
170  groupParams.push_back( param->Clone() ) ;
171  }
172 
173  TiXmlNode* proc = 0 ;
174  while( ( proc = section->IterateChildren( "processor" , proc ) ) != 0 ){
175 
176  for( std::vector<TiXmlNode*>::iterator it = groupParams.begin() ; it != groupParams.end() ; it++){
177  proc->InsertEndChild( **it ) ;
178  }
179  std::shared_ptr<TiXmlNode> clone( proc->Clone() ) ;
180  root->InsertBeforeChild( section , *clone ) ; // FIXME: memory mngmt. ?
181  }
182 
183  root->RemoveChild( section ) ;
184 
185  for( std::vector<TiXmlNode*>::iterator it = groupParams.begin() ; it != groupParams.end() ; it++){
186  delete *it ;
187  }
188  }
189 
190 
191  // process processor sections -------------------------------------------------------------------------
192  std::vector<std::string> availableProcs ;
193  availableProcs.push_back("AvailableProcessors") ;
194 
195  // count processors with collection type information in order to generate warning
196  // about old files or missing type info
197  std::pair<unsigned,unsigned> typeCount ;
198  unsigned procCount(0) ;
199  unsigned typedProcCount(0) ;
200 
201  // use this variable to check for duplicate processor definitions
202  procList.clear();
203 
204  while( (section = root->IterateChildren("processor", section ) ) != 0 ){
205 
206  // std::cout << " processor found: " << section->Value() << std::endl ;
207 
208  std::string name( getAttribute( section, "name") ) ;
209  _map[ name ] = std::make_shared<StringParameters>();
210  _current = _map[ name ].get();
211 
212  // exit if processor defined more than once in the execute section
213  if( procList.find( name ) != procList.end() ){
214  throw ParseException(std::string( "XMLParser::parse : "+ name +" defined more than once in the steering file ") );
215  }
216  procList.insert( name ) ;
217 
218 
219  // std::cout << " processor found: " << name << std::endl ;
220 
221  availableProcs.push_back( name ) ;
222 
223  // add ProcessorType to processor parameters
224  std::vector<std::string> procType(2) ;
225  procType[0] = "ProcessorType" ;
226  procType[1] = getAttribute( section, "type") ;
227  _current->add( procType ) ;
228 
229 
230 
231  std::pair<unsigned,unsigned> currentCount( typeCount ) ;
232 
233  parametersFromNode( section , constants, &typeCount ) ;
234 
235  if( typeCount.first > currentCount.first || typeCount.second > currentCount.second ){
236  ++typedProcCount ; // at least one type info attribute found in processor
237  }
238  // else {
239  // std::cout << " -- processor w/o type info : " << name << std::endl ;
240  // }
241 
242  ++procCount ;
243  }
244 
245  globalParameters->add( availableProcs ) ;
246 
247  // DEBUG:
248  //_doc->SaveFile( "debug.xml" ) ;
249 
250 
251  if( _forCCheck && typeCount.first==0 && typeCount.second ==0){
252  std::cout << "---------------------------------------------------------------------" << std::endl
253  << " WARNING XMLParser : none of the available processors have input or " << std::endl
254  << " or output collection information assigned. You won't be able to " << std::endl
255  << " check the steering file for consistency with 'Marlin -c steer.xml'" << std::endl
256  << " Please use Processor::registerInputCollection() and " << std::endl
257  << " Processor::registerOutputCollection() in you Marlin processors " << std::endl
258  << " and create a new steering file with 'Marlin -x > newsteer.xml' " << std::endl
259  << " or add the appropriate information to your existing steering files " << std::endl
260  << "---------------------------------------------------------------------" << std::endl ;
261  }
262 
263  // fg --- this is not really a warning as there are a number of processors w/o any input or output collections
264  //
265  // else if( procCount > typedProcCount ){
266  // std::cout << "---------------------------------------------------------------------" << std::endl
267  // << " WARNING XMLParser : some of the available processors don't have " << std::endl
268  // << " input or output collection information assigned. This is " << std::endl
269  // << " needed to check the steering file for consistency with 'Marlin -c'." << std::endl
270  // << " Please use Processor::registerInputCollection() and " << std::endl
271  // << " Processor::registerOutputCollection() in you Marlin processors " << std::endl
272  // << " and create a new steering file with 'Marlin -x > newsteer.xml' " << std::endl
273  // << " or add the appropriate information to your existing steering files " << std::endl
274  // << "---------------------------------------------------------------------" << std::endl ;
275  // }
276 
277 
278  // ====== check if we have unused cmd line parameter overwrites
279  if( _cmdlineparams.size() > 0 ) {
280 
281  std::stringstream str ;
282  str << "Unknwon command line parameter overwrite ( spelling !?) : \n " ;
283 
284  typedef CommandLineParametersMap::iterator IT ;
285 
286  for( IT itP=_cmdlineparams.begin() ; itP != _cmdlineparams.end() ; ++itP ){
287 
288  std::string index1 = itP->first ;
289 
290  typedef CommandLineParametersMap::mapped_type ValMap ;
291 
292  ValMap* clp_map = &itP->second ;
293 
294  for( ValMap::iterator it = clp_map->begin() , end = clp_map->end() ; it!=end ; ++it ) {
295  str << " " << index1 << "." << it->first << " : " << it->second << "\n" ;
296  }
297  }
298 
299  str << " Note: only parameters that are present in the Marlin steering file can be overwritten !!! " << "\n" ;
300 
301  throw ParseException( str.str() ) ;
302  }
303  //===================================================================
304  }
305 
306  void XMLParser::write(const std::string &filen) const{
307 
308  if( ! _doc ){
309  throw ParseException( "XMLParser::write: file not opened. Couldn't write to disk !" );
310  }
311 
312  _doc->SaveFile(filen);
313  }
314 
315  const char* XMLParser::getAttribute( TiXmlNode* node , const std::string& name ){
316 
317  TiXmlElement* el = node->ToElement() ;
318  if( el == 0 )
319  throw ParseException("XMLParser::getAttribute not an XMLElement " ) ;
320 
321  const char* at = el->Attribute( name.c_str() ) ;
322 
323  if( at == 0 ){
324 
325  std::stringstream str ;
326  str << "XMLParser::getAttribute missing attribute \"" << name
327  << "\" in element <" << el->Value() << "/> in file " << _fileName ;
328  throw ParseException( str.str() ) ;
329  }
330 
331  return at ;
332 
333  }
334 
335 
337 
338  TiXmlNode* par = 0 ;
339 
340  //_cmdlineparams["global"]["LCIOInputFiles"]="myfile.slcio" ;
341  //_cmdlineparams["MyAIDAProcessor"]["FileName"]="myfile.root" ;
342 
343  std::string index1, index2, cmdlinevalues ;
344 
345  // std::cout << " ******************************* " <<std::endl ;
346 
347  index1 = section->Value() ;
348  if( index1.compare( "processor" ) == 0 ){
349  index1 = getAttribute( section, "name") ;
350  }
351 
352  // try and get a map of overwritten cmd line parameters for this processor
353  typedef CommandLineParametersMap::mapped_type ValMap ;
354  ValMap* clp_map = 0 ;
355  CommandLineParametersMap::iterator clp_it = _cmdlineparams.find( index1 ) ;
356  if( clp_it != _cmdlineparams.end() ){ // found some command line parameters for this section
357  clp_map = &( clp_it->second ) ;
358  }
359  // CommandLineParametersMap::mapped_type clp_map = _cmdlineparams[ index1 ] ;
360 
361 
362  while( ( par = section->IterateChildren( "parameter", par ) ) != 0 ){
363 
364  index2 = par->ToElement()->Attribute("name") ;
365 
366  // // case insensitive command line options
367  // std::transform(index1.begin(), index1.end(), index1.begin(), ::toupper);
368  // std::transform(index2.begin(), index2.end(), index2.begin(), ::toupper);
369 
370  //std::cout << " ******** parameter found : " << par->ToElement()->Attribute("name") << std::endl ;
371  //std::cout << " ***** xml parameter: " << index1 << ": " << index2 << std::endl ;
372 
373  std::vector<std::string> tokens ;
374 
375  std::string name( getAttribute( par, "name" ) ) ;
376 
377  tokens.push_back( name ) ; // first token is parameter name
378 
379  LCTokenizer t( tokens ,' ') ;
380 
381  std::string inputLine("") ;
382 
383 
384  try{ inputLine = getAttribute( par , "value" ) ;
385  }
386  catch( ParseException ) {
387 
388  if( par->FirstChild() )
389  inputLine = par->FirstChild()->Value() ;
390  }
391 
392 
393 
394 
395 
396  // if( par->ToElement()->Attribute("value") != 0 ) {
397  // inputLine = par->ToElement()->Attribute("value") ;
398  // }
399  // else if( par->FirstChild() ) {
400  // inputLine = par->FirstChild()->Value() ;
401  // }
402 
403 
404 
405  // cmdlinevalues = _cmdlineparams[ index1 ][ index2 ] ;
406  // if( cmdlinevalues.compare( "" ) != 0 ){
407  // inputLine = cmdlinevalues ; // overwrite steering file parameters with command line ones
408  // }
409 
410  // ---- check we have a cmd line param overwrite
411  if( clp_map != 0 ) {
412 
413  ValMap::iterator vm_it = clp_map->find( index2 ) ;
414 
415  if( vm_it != clp_map->end() ) {
416 
417  cmdlinevalues = vm_it->second ;
418 
419  if( cmdlinevalues.compare( "" ) != 0 ){
420 
421  inputLine = cmdlinevalues ; // overwrite steering file parameters with command line ones
422 
423  // std::cout << " ############### will replace " << index1 << "." << index2 << " with : " << cmdlinevalues << std::endl ;
424 
425  clp_map->erase( vm_it ) ;
426  }
427  }
428  }
429 
430  // replace the pre-processed parameter value in the xml tree
431  try{
432  getAttribute( par , "value" ) ;
433  if( par->ToElement() )
434  par->ToElement()->SetAttribute( "value", inputLine );
435  }
436  catch( ParseException ) {
437 
438  if( par->FirstChild() )
439  par->FirstChild()->SetValue( inputLine ) ;
440  }
441 
442  // evaluate constant value
443  try {
444  performConstantReplacement( inputLine , constants );
445  }
446  catch(ParseException &e) {
447  std::cout << "XMLParser::parse : Couldn't parse parameter \"" << name << "\"" << std::endl ;
448  throw e ;
449  }
450 
451  // std::cout << " values : " << inputLine << std::endl ;
452 
453  std::for_each( inputLine.begin(),inputLine.end(), t ) ;
454 
455  // for( StringVec::iterator it = tokens.begin() ; it != tokens.end() ; it++ ){
456  // std::cout << " " << *it ;
457  // }
458  // std::cout << std::endl ;
459 
460  _current->add( tokens ) ;
461 
462 
463 
464  //--------------- check for lcio input/output type attributes -----------
465 
466  std::vector<std::string> lcioInTypes ;
467  std::vector<std::string> lcioOutTypes ;
468 
469  lcioInTypes.push_back( "_marlin.lcioInType" ) ;
470  lcioOutTypes.push_back( "_marlin.lcioOutType" ) ;
471 
472  std::string colType("") ;
473 
474  try{
475 
476  colType = getAttribute( par , "lcioInType" ) ;
477  ++typeCount->first ; // count type description to identify old files w/o type description
478  lcioInTypes.push_back( name ) ;
479  lcioInTypes.push_back( colType ) ;
480 
481  }
482  catch( ParseException ) { }
483 
484  try{
485 
486  colType = getAttribute( par , "lcioOutType" ) ;
487  ++typeCount->second ; // count type description to identify old files w/o type description
488  lcioOutTypes.push_back( name ) ;
489  lcioOutTypes.push_back( colType ) ;
490 
491  }
492  catch( ParseException ) { }
493 
494 
495 
496  _current->add( lcioInTypes ) ;
497  _current->add( lcioOutTypes ) ;
498  }
499 
500 
501  // if we did have cmd line parameters and have used all of them, we delete the corresponding submap ...
502  if( clp_map != 0 && clp_map->size() == 0 ) {
503  _cmdlineparams.erase( clp_it ) ;
504  }
505 
506  }
507 
508  // TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).Element();
509  // if ( child2 ){}
510 
512 
513  // for( StringParametersMap::iterator iter = _map.begin() ; iter != _map.end() ; iter++){
514  // // std::cout << " parameter section " << iter->first
515  // // << std::endl
516  // // << *iter->second
517  // // << std::endl ;
518  // }
519 
520  return _map[ sectionName ] ;
521  }
522 
523 
524  void XMLParser::processconditions( TiXmlNode* current , const std::string& aCondition ) {
525 
526  std::string condition ;
527  // put parentheses around compound expressions
528  if( aCondition.find('&') != std::string::npos || aCondition.find('|') != std::string::npos )
529  condition = "(" + aCondition + ")" ;
530  else
531  condition = aCondition ;
532 
533  TiXmlNode* child = 0 ;
534  TiXmlNode* nextChild = current->IterateChildren("if" , child);
535  while((child = nextChild) != 0){
536  nextChild = current->IterateChildren("if" , child);
537  processconditions( child , getAttribute( child, "condition") ) ; // might clean child
538  }
539 
540  while( ( child = current->IterateChildren( "processor" , child ) ) != 0 ) {
541 
542 
543  if( child->ToElement()->Attribute("condition") == 0 ) {
544 
545  child->ToElement()->SetAttribute("condition" , condition ) ;
546 
547  } else {
548 
549  std::string cond( child->ToElement()->Attribute("condition") ) ;
550 
551  if( cond.size() > 0 && condition.size() )
552  cond += " && " ;
553 
554  cond += condition ;
555 
556  child->ToElement()->SetAttribute("condition" , cond ) ;
557 
558  }
559 
560 
561  if( std::string( current->Value() ) != "execute" ) {
562 
563  // unless we are already in the top node (<execute/>) we have to move all processors up
564 
565  TiXmlNode* parent = current->Parent() ;
566 
567  std::shared_ptr<TiXmlNode> clone( child->Clone() ) ;
568 
569  parent->InsertBeforeChild( current , *clone ) ;
570 
571  }
572 
573  }
574  // remove the current <if/> node
575  if( std::string( current->Value() ) != "execute" ) {
576  TiXmlNode* parent = current->Parent() ;
577  parent->RemoveChild( current ) ;
578  }
579 
580  }
581 
582 
584  {
585  TiXmlElement* child = element->FirstChildElement() ;
586 
587  while( 1 )
588  {
589  if( ! child )
590  break ;
591 
592  if( child->Value() == std::string("constants") ) {
593 
594  child = child->NextSiblingElement() ;
595  continue ;
596  }
597 
598  if( child->Value() != std::string("include") ) {
599 
600  processIncludeElements( child , constants ) ;
601  child = child->NextSiblingElement() ;
602  continue ;
603  }
604 
605  // process the include and returns the first and last elements found in the include
606  TiXmlDocument document ;
607  processIncludeElement( child , constants , document ) ;
608 
609  // add them to the xml tree
610  TiXmlNode *includeAfter( child ) ;
611 
612  for( TiXmlElement *includeElement = document.FirstChildElement() ; includeElement ; includeElement = includeElement->NextSiblingElement() ) {
613 
614  includeAfter = element->InsertAfterChild( includeAfter, *includeElement ) ;
615  }
616 
617  // tricky lines :
618  // 1) Remove the include element
619  element->RemoveChild(child) ;
620  // 2) Go to the next sibling element of the last included element to skip nested <include> elements
621  child = includeAfter->NextSiblingElement() ;
622  }
623  }
624 
625 
627 
628  std::pair<TiXmlElement*, TiXmlElement*> firstAndLastElements(nullptr, nullptr) ;
629 
630  if( ! element->Attribute("ref") ) {
631 
632  std::stringstream str ;
633  str << "XMLParser::processIncludeElement missing attribute \"" << "ref"
634  << "\" in element <" << element->Value() << "/> in file " << _fileName ;
635  throw ParseException( str.str() ) ;
636  }
637 
638  std::string ref ( element->Attribute("ref") ) ;
639 
640  try { performConstantReplacement( ref, constants ) ;
641  }
642  catch( ParseException & e ) {
643  std::cout << "XMLParser::processIncludeElement : Couldn't parse include ref \"" << ref << "\"" << std::endl ;
644  throw e ;
645  }
646 
647  if( ref.size() < 5 || ref.substr( ref.size() - 4 ) != ".xml" ) {
648 
649  std::stringstream str ;
650  str << "XMLParser::processIncludeElement invalid ref file name \"" << ref
651  << "\" in element <" << element->Value() << "/> in file " << _fileName ;
652  throw ParseException( str.str() ) ;
653  }
654 
655  std::string refFileName ;
656 
657  if( ref.at(0) != '/' ) {
658 
659  // relative path case
660  // prepend with current file path
661  size_t idx = _fileName.find_last_of("/") ;
662  std::string baseFileName ;
663 
664  if( idx != std::string::npos )
665  {
666  baseFileName = _fileName.substr( 0 , idx ) + "/" ;
667  }
668 
669  refFileName = baseFileName + ref ;
670  }
671  else {
672  refFileName = ref ;
673  }
674 
675  bool loadOkay = document.LoadFile( refFileName ) ;
676 
677  if( !loadOkay ) {
678 
679  std::stringstream str ;
680  str << "XMLParser::processIncludeElement error in file [" << refFileName
681  << ", row: " << document.ErrorRow() << ", col: " << document.ErrorCol() << "] : "
682  << document.ErrorDesc() ;
683  throw ParseException( str.str() ) ;
684 
685  }
686 
687  checkForNestedIncludes( &document ) ;
688 
689  }
690 
691 
693 
694  for(const TiXmlElement *child = node->FirstChildElement() ; child ; child = child->NextSiblingElement()){
695 
696  if( child->Value() == std::string("include") ) {
698  ss << "Nested includes are not allowed [in file: " << node->GetDocument()->Value() << ", line: " << child->Row() << "] !" ;
699  throw ParseException( ss.str() ) ;
700  }
701 
702  checkForNestedIncludes( child ) ;
703 
704  }
705 
706  }
707 
708 
710 
711  TiXmlElement *previous(nullptr);
712  TiXmlElement *child(nullptr);
713 
714  while(1) {
715 
716  if( ! child )
717  child = node->FirstChildElement();
718  else
719  child = child->NextSiblingElement();
720 
721  if( ! child )
722  break;
723 
724  if( std::string( child->Value() ) == "constant" ) {
725 
726  // process single constant
727  processConstant( child , constants ) ;
728  }
729  // need to process includes in constants section since some
730  // constants may be defined in includes and could then be
731  // used in next constant values
732  else if ( std::string( child->Value() ) == "include" ) {
733 
734  // process the include and returns the first and last elements found in the include
735  TiXmlDocument document ;
736  processIncludeElement( child , constants , document ) ;
737 
738  // add them to the xml tree
739  TiXmlNode *includeAfter( child ) ;
740 
741  for( TiXmlElement *elt = document.FirstChildElement() ; elt ; elt = elt->NextSiblingElement() ) {
742 
743  if ( elt->Value() == std::string( "constant" ) ) {
744  // processConstant( elt , constants ) ;
745  includeAfter = node->InsertAfterChild( includeAfter, *elt ) ;
746  }
747  }
748 
749  node->RemoveChild(child);
750  child = previous;
751  }
752 
753  previous = child;
754  }
755 
756  // check the cmd line constant map. It should be empty now ...
757  typedef CommandLineParametersMap::mapped_type ValMap ;
758  ValMap* clp_map = 0 ;
759  CommandLineParametersMap::iterator clp_it = _cmdlineparams.find( "constant" ) ;
760 
761  if( clp_it != _cmdlineparams.end() ){ // found some command line parameters for the constants section
762  clp_map = &( clp_it->second ) ;
763  }
764 
765  // if we did have cmd line parameters and have used all of them, we delete the corresponding submap ...
766  if( clp_map != 0 && clp_map->size() == 0 ) {
767  _cmdlineparams.erase( clp_it ) ;
768  }
769 
770  }
771 
772 
773 
775 
776  // try and get a map of overwritten cmd line parameters for this constant
777  typedef CommandLineParametersMap::mapped_type ValMap ;
778  ValMap* clp_map = 0 ;
779  CommandLineParametersMap::iterator clp_it = _cmdlineparams.find( "constant" ) ;
780 
781  if( clp_it != _cmdlineparams.end() ){ // found some command line parameters for the constants section
782  clp_map = &( clp_it->second ) ;
783  }
784 
785  if( ! element->Attribute("name") ) {
786 
787  throw ParseException( "XMLParser::processConstant : constant element without name. Skipping ..." ) ;
788  }
789 
790  const std::string name( element->Attribute("name") ) ;
791 
792  if( name.empty() ) {
793 
794  throw ParseException( "XMLParser::processConstant : parsed empty constant name !" ) ;
795  }
796 
797  // std::cout << "Found constant with name : " << name << std::endl;
798 
799  if( constants.end() != constants.find( name ) ) {
800  std::stringstream str ;
801  str << "XMLParser::processConstant : constant \"" << name << "\" defined twice !" << std::endl ;
802  throw ParseException( str.str() ) ;
803  }
804 
805  std::string value ;
806 
807  if( element->Attribute("value") ) {
808 
809  value = element->Attribute("value") ;
810  }
811  else {
812 
813  if( element->FirstChild() )
814  value = element->FirstChild()->Value() ;
815  }
816 
817  // ---- check we have a cmd line constant overwrite
818  if( clp_map != 0 ) {
819 
820  ValMap::iterator vm_it = clp_map->find( name ) ;
821 
822  if( vm_it != clp_map->end() ) {
823 
824  std::string cmdlinevalues = vm_it->second ;
825 
826  if( cmdlinevalues.compare( "" ) != 0 ){
827 
828  value = cmdlinevalues ; // overwrite steering file constant with command line ones
829  clp_map->erase( vm_it ) ;
830  }
831  }
832  }
833 
834  // replace the pre-processed constant in the XML element
835  if( element->Attribute("value") ) {
836 
837  element->SetAttribute("value", value) ;
838  }
839  else {
840 
841  if( element->FirstChild() )
842  element->FirstChild()->SetValue(value) ;
843  }
844 
845  // evaluate constant value
846  try { performConstantReplacement( value, constants ) ;
847  }
848  catch( ParseException & e ) {
849  std::cout << "XMLParser::processConstant : Couldn't parse constant \"" << name << "\"" << std::endl ;
850  throw e ;
851  }
852 
853  if( ! constants.insert( std::map<std::string, std::string>::value_type( name , value ) ).second ) {
854  std::stringstream str ;
855  str << "XMLParser::processConstant : couldn't add constant \"" << name << "\" to constant map !" << std::endl ;
856  throw ParseException( str.str() ) ;
857  }
858 
859  std::cout << "Read constant \"" << name << "\" , value = \"" << value << "\"" << std::endl ;
860  }
861 
862 
863 
865 
866  size_t pos = value.find("${") ;
867  std::string original(value);
868 
869  while( pos != std::string::npos ) {
870 
871  size_t pos2 = value.find_first_of( "}", pos+2 ) ;
872 
873  if( pos2 == std::string::npos ) {
874 
875  throw ParseException( "XMLParser::performConstantReplacement : couldn't parse constant value !" ) ;
876  }
877 
878  const std::string key( value.substr( pos+2 , pos2-pos-2 )) ;
879  auto findConstant = constants.find( key ) ;
880  const std::string replacementValue( findConstant != constants.end() ? findConstant->second : "" ) ;
881 
882  if( replacementValue.empty() ) {
883 
884  std::stringstream str ;
885  str << "XMLParser::performConstantReplacement : constant \"" << key << "\" not found in available constants !" ;
886  throw ParseException( str.str() ) ;
887  }
888 
889  value.replace( pos , (pos2+1-pos) , replacementValue ) ;
890  pos2 = pos + replacementValue.size() ; // new end position after replace
891 
892  pos = value.find("${", pos2) ; // find next possible key to replace
893  }
894 
895  return value ;
896  }
897 
898 
900 
901  TiXmlElement* root = _doc->RootElement() ;
902  if( root==0 ){
903  std::cout << "XMLParser::parse : no root tag <marlin>...</marlin> found ! " << std::endl ;
904  return ;
905  }
906 
907  TiXmlNode* child = 0 ;
908  TiXmlNode* nextChild = section->IterateChildren( child );
909  while((child = nextChild) != 0){
910  nextChild = section->IterateChildren(child);
911  if( std::string( child->Value() ) == "group" ) {
912 
913  // find group definition in root node
914  TiXmlNode* group = findElement( root, "group", "name" , getAttribute( child, "name") ) ;
915 
916  if( group != 0 ) {
917 
918  TiXmlNode* sub = 0 ;
919  while( ( sub = group->IterateChildren( "processor" , sub ) ) != 0 ){
920 
921  // insert <processor/> tag
922  TiXmlElement item( "processor" );
923  item.SetAttribute( "name", getAttribute( sub, "name") ) ;
924 
925  section->InsertBeforeChild( child , item ) ;
926 
927  // std::cout << " inserting processor tag for group : " << item.Value() << ", "
928  // << item.Attribute("name") << std::endl ;
929  }
930 
931  section->RemoveChild( child ) ;
932 
933  } else
934 
935  std::cout << " XMLParser::parse - group not found : " << child->ToElement()->Attribute("name") << std::endl ;
936 
937  } else if( std::string( child->Value() ) == "if" ) { // other element, e.g. <if></if>
938 
939  replacegroups( child ) ;
940 
941  }
942  }
943  }
944 
945 
947  const std::string& attribute, const std::string& value ) {
948 
949  TiXmlNode* child = 0 ;
950  bool elementFound = false ;
951 
952  while( (child = node->IterateChildren( type , child ) ) != 0 ){
953 
954  if( std::string( *child->ToElement()->Attribute( attribute ) ) == value ) {
955  elementFound = true ;
956  break ;
957  }
958  }
959  if( ! elementFound )
960  child = 0 ;
961 
962  return child ;
963  }
964 
965 } // namespace marlin
966 
967 
StringParametersMap _map
Definition: XMLParser.h:204
const TiXmlElement * RootElement() const
Get the root element – the only top level element – of the document.
Definition: tinyxml.h:1429
void write(const std::string &filen) const
Write the parsed XML tree in an other file.
Definition: XMLParser.cc:306
ParseException used for parse errors, e.g.
Definition: Exceptions.h:16
void processIncludeElements(TiXmlElement *element, const std::map< std::string, std::string > &constants)
Helper method - recursively replace all with the corresponding file content.
Definition: XMLParser.cc:583
StringParameters * _current
Definition: XMLParser.h:205
T endl(T...args)
const char * getAttribute(TiXmlNode *node, const std::string &name)
Return named attribute - throws ParseException if attribute doesn&#39;t exist.
Definition: XMLParser.cc:315
void processconditions(TiXmlNode *current, const std::string &conditions)
Helper method - recursively moves processors from &lt;if&gt; tags to top level (&lt;execute&gt;) and adds corresp...
Definition: XMLParser.cc:524
T end(T...args)
void add(const std::string &key, const std::vector< std::string > &values)
bool LoadFile(TiXmlEncoding encoding=TIXML_DEFAULT_ENCODING)
Load a file using the current document value.
Definition: tinyxml.cc:915
void SetValue(const char *_value)
Changes the value of the node.
Definition: tinyxml.h:508
int ErrorCol() const
The column where the error occured. See ErrorRow()
Definition: tinyxml.h:1455
TiXmlNode * InsertEndChild(const TiXmlNode &addThis)
Add a new node related to this.
Definition: tinyxml.cc:202
TiXmlNode * InsertBeforeChild(TiXmlNode *beforeThis, const TiXmlNode &addThis)
Add a new node related to this.
Definition: tinyxml.cc:217
Helper class for XMLParser.
Definition: XMLParser.h:114
STL class.
T find_last_of(T...args)
T push_back(T...args)
int ErrorRow() const
Returns the location (if known) of the error.
Definition: tinyxml.h:1454
T replace(T...args)
const TiXmlNode * FirstChild() const
The first child of this node. Will be null if there are no children.
Definition: tinyxml.h:522
const char * ErrorDesc() const
Contains a textual (english) description of the error if one occurs.
Definition: tinyxml.h:1440
void SetAttribute(const char *name, const char *_value)
Sets an attribute of name to a given value.
Definition: tinyxml.cc:708
std::shared_ptr< StringParameters > getParameters(const std::string &sectionName) const
Return the StringParameters for the section as read from the xml file.
Definition: XMLParser.cc:511
T erase(T...args)
bool SaveFile() const
Save a file using the current document value. Returns true if successful.
Definition: tinyxml.cc:924
virtual ~XMLParser()
Definition: XMLParser.cc:21
std::string & performConstantReplacement(std::string &value, const std::map< std::string, std::string > &constants)
Definition: XMLParser.cc:864
Always the top level node.
Definition: tinyxml.h:1366
const TiXmlElement * FirstChildElement() const
Convenience function to get through elements.
Definition: tinyxml.cc:422
T find_first_of(T...args)
T str(T...args)
CommandLineParametersMap _cmdlineparams
Definition: XMLParser.h:216
T clear(T...args)
TiXmlNode * InsertAfterChild(TiXmlNode *afterThis, const TiXmlNode &addThis)
Add a new node related to this.
Definition: tinyxml.cc:249
virtual const TiXmlElement * ToElement() const
Cast to a more defined type. Will return null if not of the requested type.
Definition: tinyxml.h:698
const TiXmlDocument * GetDocument() const
Return a pointer to the Document this node lives in.
Definition: tinyxml.cc:482
T insert(T...args)
T find(T...args)
T size(T...args)
TiXmlNode * findElement(TiXmlNode *node, const std::string &type, const std::string &attribute, const std::string &value)
Helper method - finds child element of node with given type and attribute value.
Definition: XMLParser.cc:946
const TiXmlElement * NextSiblingElement() const
Convenience function to get through elements.
Definition: tinyxml.cc:452
TiXmlNode * Parent()
One step up the DOM.
Definition: tinyxml.h:519
void parse()
Parse the input file.
Definition: XMLParser.cc:24
T begin(T...args)
The parent class for everything in the Document Object Model.
Definition: tinyxml.h:425
T c_str(T...args)
void processConstant(TiXmlElement *element, std::map< std::string, std::string > &constants)
Definition: XMLParser.cc:774
T substr(T...args)
std::unique_ptr< TiXmlDocument > _doc
Definition: XMLParser.h:206
const TiXmlNode * IterateChildren(const TiXmlNode *previous) const
An alternate way to walk the children of a node.
Definition: tinyxml.cc:355
const char * Value() const
The meaning of &#39;value&#39; changes for the specific type of TiXmlNode.
Definition: tinyxml.h:489
bool RemoveChild(TiXmlNode *removeThis)
Delete a child of this node.
Definition: tinyxml.cc:309
T for_each(T...args)
void processConstants(TiXmlNode *node, std::map< std::string, std::string > &constants)
Definition: XMLParser.cc:709
void checkForNestedIncludes(const TiXmlNode *node)
Definition: XMLParser.cc:692
void replacegroups(TiXmlNode *section)
Helper method - replaces all &lt;group&gt; tag with corresponding &lt;processor&gt; tags.
Definition: XMLParser.cc:899
std::string _fileName
Definition: XMLParser.h:208
const char * Attribute(const char *name) const
Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists.
Definition: tinyxml.cc:546
Simple parameters class for Marlin.
virtual TiXmlNode * Clone() const =0
Create an exact duplicate of this node and return it.
void parametersFromNode(TiXmlNode *section, std::map< std::string, std::string > &constants, std::pair< unsigned, unsigned > *typeCount=0)
Extracts all parameters from the given node and adss them to the current StringParameters object...
Definition: XMLParser.cc:336
void processIncludeElement(TiXmlElement *element, const std::map< std::string, std::string > &constants, TiXmlDocument &document)
Definition: XMLParser.cc:626
T compare(T...args)
The element is a container class.
Definition: tinyxml.h:943