29 void init(
const std::string &desc )
override ;
42 void parseSection( TiXmlElement *parentElement,
const std::string &name,
Configuration &cfg,
bool addAttributes,
bool throwIfNotFound )
const ;
77 std::string
getAttribute(
const TiXmlElement* element,
const std::string& name )
const ;
150 void processConditions( TiXmlNode* current,
const std::string &aCondition )
const ;
158 void replaceGroups( TiXmlNode* processorsParent, TiXmlNode* section )
const ;
176 TiXmlNode *
findElement( TiXmlNode* node,
const std::string& tag,
const std::string& attribute,
const std::string&
value )
const ;
196 auto document = std::make_unique<TiXmlDocument>() ;
197 bool loadOkay = document->LoadFile(
_fname ) ;
199 std::stringstream str ;
200 str <<
"Parse error in file [" <<
_fname 201 <<
", row: " << document->ErrorRow() <<
", col: " << document->ErrorCol() <<
"] : " 202 << document->ErrorDesc() ;
206 auto rootElement = document->RootElement() ;
207 if(
nullptr == rootElement || rootElement->ValueStr() !=
"marlinmt" ) {
217 parseSection(rootElement,
"geometry", cfg,
true,
true) ;
219 parseSection(rootElement,
"bookstore", cfg,
true,
false) ;
221 parseSection(rootElement,
"scheduler", cfg,
true,
false) ;
223 parseSection(rootElement,
"datasource", cfg,
true,
true) ;
225 parseSection(rootElement,
"logging", cfg,
true,
false) ;
245 auto sectionElement = parentElement->FirstChildElement( name ) ;
246 if(
nullptr == sectionElement ) {
247 if( throwIfNotFound ) {
262 auto executeElement = parentElement->FirstChildElement(
"execute") ;
263 if(
nullptr == executeElement ) {
268 TiXmlNode* proc = 0 ;
269 std::set<std::string> processorDuplicates {} ;
270 std::vector<std::string> processorConditions {}, processorNames {} ;
273 while( ( proc = executeElement->IterateChildren(
"processor", proc ) ) != 0 ) {
274 std::string processorName(
getAttribute( proc->ToElement(),
"name") ) ;
276 auto inserted = processorDuplicates.insert( processorName ) ;
277 if( 1 != inserted.second ) {
278 MARLINMT_THROW_T( ParseException,
"Processor " + processorName +
" defined more than once in <execute> section" ) ;
280 processorNames.push_back( processorName ) ;
281 std::string condition ;
283 if( conditionReplace.has_value() ) {
284 condition = conditionReplace.value() ;
287 condition =
getAttribute( proc->ToElement(),
"condition") ;
290 if( condition.empty() ) {
293 processorConditions.push_back( condition ) ;
295 for( std::size_t i=0 ; i<processorNames.size() ; i++ ) {
296 executeSection.setParameter( processorNames[i], processorConditions[i] ) ;
307 TiXmlNode *section = nullptr ;
308 TiXmlNode* nextSection = rootElement->IterateChildren(
"group", section) ;
309 while((section = nextSection) != 0) {
310 nextSection = rootElement->IterateChildren(
"group", section);
311 std::vector<TiXmlNode*> groupParams ;
312 TiXmlNode* param = 0 ;
313 while( ( param = section->IterateChildren(
"parameter" , param ) ) != 0 ) {
314 groupParams.push_back( param->Clone() ) ;
316 TiXmlNode* proc = 0 ;
317 while( ( proc = section->IterateChildren(
"processor" , proc ) ) != 0 ) {
318 for( std::vector<TiXmlNode*>::iterator it = groupParams.begin() ; it != groupParams.end() ; it++){
319 proc->InsertEndChild( **it ) ;
321 std::shared_ptr<TiXmlNode> clone( proc->Clone() ) ;
322 rootElement->InsertBeforeChild( section , *clone ) ;
324 rootElement->RemoveChild( section ) ;
325 for( std::vector<TiXmlNode*>::iterator it = groupParams.begin() ; it != groupParams.end() ; it++) {
334 std::vector<std::string> availableProcs ;
335 TiXmlNode *section = nullptr ;
337 while( (section = parent->IterateChildren(
"processor", section ) ) != 0 ) {
339 std::string name =
getAttribute( section->ToElement(),
"name") ;
342 auto &procSection = parentSection.addSection( name ) ;
345 availableProcs.push_back( name ) ;
351 if( availableProcs.empty() ) {
352 MARLINMT_THROW_T( ParseException,
"No <processor> section found in root section <marlinmt>" ) ;
359 const char* attr = element->Attribute( name.c_str() ) ;
360 if(
nullptr == attr ) {
361 MARLINMT_THROW_T( ParseException,
"Missing attribute '" + name +
"' in element <" + element->ValueStr() +
"> in file " +
_fname ) ;
369 TiXmlElement *constantsElement = idoc->RootElement()->FirstChildElement(
"constants") ;
370 if(
nullptr == constantsElement ) {
373 TiXmlElement *previous(
nullptr), *child(
nullptr) ;
375 if(
nullptr == child ) {
376 child = constantsElement->FirstChildElement() ;
379 child = child->NextSiblingElement() ;
381 if(
nullptr == child ) {
384 if( child->ValueStr() ==
"constant" ) {
391 else if ( child->ValueStr() ==
"include" ) {
393 TiXmlDocument document ;
396 TiXmlNode *includeAfter( child ) ;
397 for( TiXmlElement *elt = document.FirstChildElement() ; elt ; elt = elt->NextSiblingElement() ) {
398 if ( elt->ValueStr() ==
"constant" ) {
399 includeAfter = constantsElement->InsertAfterChild( includeAfter, *elt ) ;
402 constantsElement->RemoveChild(child) ;
417 if( element->Attribute(
"value") ) {
418 value = element->Attribute(
"value") ;
421 if( element->FirstChild() ) {
422 value = element->FirstChild()->ValueStr() ;
427 if( replValue.has_value() ) {
429 value = replValue.value() ;
442 TiXmlElement* child = element->FirstChildElement() ;
444 if(
nullptr == child ) {
448 if( child->ValueStr() ==
"constants" ) {
449 child = child->NextSiblingElement() ;
453 if( child->ValueStr() !=
"include" ) {
455 child = child->NextSiblingElement() ;
459 TiXmlDocument document ;
462 TiXmlNode *includeAfter( child ) ;
463 for( TiXmlElement *includeElement = document.FirstChildElement() ; includeElement ; includeElement = includeElement->NextSiblingElement() ) {
464 includeAfter = element->InsertAfterChild( includeAfter, *includeElement ) ;
468 element->RemoveChild(child) ;
470 child = includeAfter->NextSiblingElement() ;
480 std::filesystem::path filepath = ref ;
481 if( not filepath.has_stem() || filepath.extension() !=
".xml" ) {
482 MARLINMT_THROW_T( ParseException,
"Invalid ref file name '" + ref +
"' in element <" + element->ValueStr() +
"/> in file " +
_fname ) ;
486 if( not filepath.is_absolute() ) {
487 auto idocdir = std::filesystem::path(
_fname).parent_path() ;
488 filepath = idocdir / filepath ;
491 bool loadOkay = document.LoadFile( filepath.string() ) ;
493 std::stringstream str ;
494 str <<
"Couldn't load include document. Error in file [" << filepath
495 <<
", row: " << document.ErrorRow() <<
", col: " << document.ErrorCol() <<
"] : " 496 << document.ErrorDesc() ;
509 for(
const TiXmlElement *child = node->FirstChildElement() ; child ; child = child->NextSiblingElement()) {
510 if( child->ValueStr() ==
"include" ) {
511 std::stringstream ss;
512 ss <<
"Nested includes are not allowed [in file: " << node->GetDocument()->ValueStr() <<
", line: " << child->Row() <<
"] !" ;
523 auto elementValue = element->ValueStr() ;
527 if( addAttributes ) {
528 elementValue[0] = std::toupper( elementValue[0], std::locale() ) ;
529 for(
const TiXmlAttribute *attr = element->FirstAttribute() ; attr != nullptr ; attr = attr->Next()) {
530 std::string attrName = attr->Name() ;
531 attrName[0] = std::toupper( attrName[0], std::locale() ) ;
532 std::string attrValue = attr->ValueStr() ;
533 if( not replacePrefix.empty() ) {
537 section.
setParameter( elementValue + attrName, attrValue ) ;
540 for(
const TiXmlElement *child = element->FirstChildElement(
"parameter") ; child ; child = child->NextSiblingElement(
"parameter")) {
542 std::string parameterValue ;
545 parameterValue =
getAttribute( child->ToElement() ,
"value" ) ;
547 catch( ParseException& ) {
548 if( child->FirstChild() ) {
549 parameterValue = child->FirstChild()->ValueStr() ;
552 if( not replacePrefix.empty() ) {
553 parameterValue =
getReplacementParameter( replacePrefix +
"." + parameterName, cfg ).value_or( parameterValue ) ;
569 std::string condition ;
571 if( aCondition.find(
'&') != std::string::npos || aCondition.find(
'|') != std::string::npos ) {
572 condition =
"(" + aCondition +
")" ;
575 condition = aCondition ;
578 TiXmlNode* child = 0 ;
579 while( ( child = current->IterateChildren(
"if" , child ) ) != 0 ) {
582 while( ( child = current->IterateChildren(
"processor" , child ) ) != 0 ) {
583 if( child->ToElement()->Attribute(
"condition" ) == 0 ) {
584 child->ToElement()->SetAttribute(
"condition", condition ) ;
587 std::string cond( child->ToElement()->Attribute(
"condition") ) ;
588 if( cond.size() > 0 && not condition.empty() ) {
592 child->ToElement()->SetAttribute(
"condition", cond ) ;
594 if( current->ValueStr() !=
"execute" ) {
596 TiXmlNode* parent = current->Parent() ;
597 std::shared_ptr<TiXmlNode> clone( child->Clone() ) ;
598 parent->InsertBeforeChild( current , *clone ) ;
602 if( current->ValueStr() !=
"execute" ) {
603 TiXmlNode* parent = current->Parent() ;
604 parent->RemoveChild( current ) ;
616 TiXmlNode* child = 0 ;
617 TiXmlNode* nextChild = section->IterateChildren( child ) ;
618 while((child = nextChild) != 0) {
619 nextChild = section->IterateChildren(child) ;
620 if( child->ValueStr() ==
"group" ) {
622 auto groupName =
getAttribute( child->ToElement(),
"name") ;
623 TiXmlNode* group =
findElement( processorsParent,
"group",
"name" , groupName ) ;
624 if(
nullptr == group ) {
628 while( ( sub = group->IterateChildren(
"processor" , sub ) ) != 0 ){
630 TiXmlElement item(
"processor" ) ;
631 item.SetAttribute(
"name",
getAttribute( sub->ToElement(),
"name") ) ;
632 section->InsertBeforeChild( child , item ) ;
634 section->RemoveChild( child ) ;
636 else if( child->ValueStr() ==
"if" ) {
649 TiXmlNode* child = 0 ;
650 while( (child = node->IterateChildren( type , child ) ) != 0 ) {
651 if( std::string( *child->ToElement()->Attribute( attribute ) ) == value ) {
662 auto &cmdline = config.
section(
"CmdLine") ;
663 if( cmdline.hasSection(
"AdditionalArgs") ) {
664 auto &addArgs = cmdline.
section(
"AdditionalArgs") ;
665 if( addArgs.hasParameter( arg ) ) {
666 return addArgs.
parameter<std::string>( arg ) ;
670 return std::nullopt ;
ConfigSection & section(const std::string &n)
Get a subsection by name.
T parameter(const std::string &n) const
Get a parameter value as type T.
void processConditions(TiXmlNode *current, const std::string &aCondition) const
Treat the conditions for a XML node.
#define MARLINMT_THROW_T(ExceptionType, message)
ConfigSection & createSection(const std::string &sn)
Create a new section by name.
TiXmlNode * findElement(TiXmlNode *node, const std::string &tag, const std::string &attribute, const std::string &value) const
Find a particular XML node by matching tag, and a specific attribute value.
void parseConstants(TiXmlDocument *idoc, Configuration &cfg) const
Parse the <constants> section.
void parseExecuteSection(TiXmlElement *parentElement, Configuration &cfg) const
Parse the <execute> section and populate the configuration object accordingly.
std::string _fname
The input/output file name.
constexpr unsigned long long value(const Flag_t &flag)
#define MARLINMT_RETHROW(orig, message)
#define MARLINMT_DECLARE_CONFIG_READER(Class)
Configuration & addConstant(const std::string &cn, const T &val)
Add a constant.
XMLConfigReader plugin Read an XML file and populate the configuration with sections and parameters...
ConfigReader base class Interface for reading configuration.
void resolveGroupSections(TiXmlElement *rootElement) const
Resolve the <group> sections.
void parseSection(TiXmlElement *parentElement, const std::string &name, Configuration &cfg, bool addAttributes, bool throwIfNotFound) const
Parse a configuration section from the parent XML element.
void parseConstant(TiXmlElement *element, Configuration &cfg) const
Parse a single <constant> element.
void checkForNestedIncludes(const TiXmlNode *node) const
Check recursively for XML element in the node.
ConfigSection & section(const std::string &sn)
Get a section by name.
std::string getAttribute(const TiXmlElement *element, const std::string &name) const
Helper method to get a XML element attribute as string.
std::optional< std::string > getReplacementParameter(const std::string &arg, const Configuration &config) const
void parametersFromXMLElement(const TiXmlElement *element, const Configuration &cfg, ConfigSection §ion, bool addAttributes, const std::string &replacePrefix="") const
Read the <parameter> XML elements form the parent XML element.
#define MARLINMT_RETHROW_T(ExceptionType, orig, message)
void parseProcessorParameters(TiXmlElement *parent, Configuration &cfg) const
Parse all the processor parameter sections in the parent XML element.
ConfigSection & setParameter(const std::string &n, const T &val)
Set a parameter value.
void processIncludeElements(TiXmlElement *element, const Configuration &cfg) const
Process all XML elements recursively.
void replaceConstants(std::string &str) const
Replace all occurences of ${constant_name} in the input string where "constant_name" must match a reg...
ConfigSection class Holds a set of parameters and subsection.
void init(const std::string &desc) override
Initialize the parser.
bool hasSection(const std::string &n) const
Whether the section exists.
void read(Configuration &cfg) override
Read the configuration and populate the configuration object.
void replaceGroups(TiXmlNode *processorsParent, TiXmlNode *section) const
Replace the <group> tags in the execute section by the corresponding processors.
void processIncludeElement(TiXmlElement *element, const Configuration &cfg, TiXmlDocument &document) const
Process a single XML element.