MarlinMT  0.1.0
XMLConfigWriter.cc
Go to the documentation of this file.
1 
2 // -- marlinmt headers
5 #include <marlinmt/Utils.h>
6 
7 // -- std headers
8 #include <locale>
9 #include <sstream>
10 #include <unordered_map>
11 #include <iomanip>
12 #include <ctime>
13 
14 // -- tinyxml headers
15 #include <tinyxml.h>
16 
17 namespace marlinmt {
18 
23  class XMLConfigWriter : public ConfigWriter {
24  public:
25  using StringMap = std::vector<std::pair<std::string, std::string>> ;
26 
27  // from ConfigWriter
28  void init( const std::string &desc ) override ;
29  void write( const Configuration &cfg ) override ;
30 
40  TiXmlElement createParameterSection( const std::string &name, const ConfigSection &section, const StringMap &attrMapping = {} ) ;
41 
48  void appendDescription( TiXmlElement &element, const ConfigSection &section ) const ;
49 
50  // factory helper functions
51  TiXmlElement createElement( const std::string &name, const StringMap &attrs = {} ) const ;
52  TiXmlComment createComment( const std::string &comment ) const ;
53  TiXmlText createText( const std::string &text ) const ;
54  TiXmlElement createParameter( const std::string &name, const std::string &value ) const ;
55 
56  private:
58  std::string _fname {} ;
59  };
60 
61  //--------------------------------------------------------------------------
62  //--------------------------------------------------------------------------
63 
64  void XMLConfigWriter::init( const std::string &desc ) {
65  _fname = desc ;
66  }
67 
68  //--------------------------------------------------------------------------
69 
71  auto root = createElement( "marlinmt" ) ;
72  // write all standard sections (only)
73  auto procsConds = cfg.section("execute").parameters() ;
74  auto executeElement = createElement( "execute" ) ;
75  for( auto &pc : procsConds ) {
76  if( pc.second == "true" ) {
77  executeElement.InsertEndChild( createElement( "processor", {{"name", pc.first}} ) ) ;
78  }
79  else {
80  executeElement.InsertEndChild( createElement( "processor", {{"name", pc.first}, {"condition", pc.second}} ) ) ;
81  }
82  }
83  root.InsertEndChild( executeElement ) ;
84  if( cfg.hasSection( "global" ) ) {
85  appendDescription( root, cfg.section("global") ) ;
86  root.InsertEndChild( createParameterSection( "global", cfg.section("global") ) ) ;
87  }
88  if( cfg.hasSection( "logging" ) ) {
89  appendDescription( root, cfg.section("logging") ) ;
90  root.InsertEndChild( createParameterSection( "logging", cfg.section("logging") ) ) ;
91  }
92  if( cfg.hasSection( "scheduler" ) ) {
93  appendDescription( root, cfg.section("scheduler") ) ;
94  root.InsertEndChild( createParameterSection( "scheduler", cfg.section("scheduler") ) ) ;
95  }
96  if( cfg.hasSection( "datasource" ) ) {
97  appendDescription( root, cfg.section("datasource") ) ;
98  root.InsertEndChild( createParameterSection( "datasource", cfg.section("datasource"), {
99  {"DatasourceType", "type"}
100  } ) ) ;
101  }
102  if( cfg.hasSection( "geometry" ) ) {
103  appendDescription( root, cfg.section("geometry") ) ;
104  root.InsertEndChild( createParameterSection( "geometry", cfg.section("geometry"), {
105  {"GeometryType", "type"}
106  } ) ) ;
107  }
108  if( cfg.hasSection( "bookstore" ) ) {
109  appendDescription( root, cfg.section("bookstore") ) ;
110  root.InsertEndChild( createParameterSection( "bookstore", cfg.section("bookstore") ) ) ;
111  }
112  auto &procs = cfg.section( "processors" ) ;
113  auto processorNames = procs.subsectionNames() ;
114  for( auto &proc : processorNames ) {
115  auto &procSection = procs.section( proc ) ;
116  appendDescription( root, procSection ) ;
117  root.InsertEndChild( createParameterSection( "processor", procSection, {
118  {"ProcessorName", "name"},
119  {"ProcessorType", "type"},
120  {"ProcessorCritical", "critical"},
121  {"ProcessorClone", "clone"}
122  } ) ) ;
123  }
124 
125  // write out document
126  TiXmlDocument document ;
127  // XML declaration
128  TiXmlDeclaration declaration( "1.0", "utf8", "" ) ;
129  document.InsertEndChild( declaration ) ;
130  // A bit of info is nice
131  auto t = std::time(nullptr) ;
132  auto tm = *std::localtime(&t) ;
133  std::string indent = " " ;
134  std::stringstream dateStr ; dateStr << std::put_time(&tm, "Date: %d-%m-%Y %T") ;
135  std::stringstream header ;
136  header << "\n" <<
137  indent << "This an example steering file generated by MarlinMT\n" <<
138  indent << dateStr.str() << "\n" <<
139  indent << "MarlinMT version: " << MARLINMT_RELEASE << "\n" ;
140  std::cout << cfg << std::endl ;
141  if( cfg.hasSection( "CmdLine" ) ) {
142  auto &cmdline = cfg.section( "CmdLine" ) ;
143  header << indent << "Full command line: " << cmdline.parameter<std::string>("Arguments") << " \n" ;
144  }
145  document.InsertEndChild( createComment( header.str() ) ) ;
146  // Add root element and write
147  document.InsertEndChild( root ) ;
148  document.SaveFile( _fname ) ;
149  }
150 
151  //--------------------------------------------------------------------------
152 
153  void XMLConfigWriter::appendDescription( TiXmlElement &element, const ConfigSection &section ) const {
154  auto iter = section.metadata().find( "description" ) ;
155  if( section.metadata().end() != iter ) {
156  element.InsertEndChild( createComment( iter->second ) ) ;
157  }
158  }
159 
160  //--------------------------------------------------------------------------
161 
162  TiXmlElement XMLConfigWriter::createParameterSection( const std::string &name, const ConfigSection &section, const StringMap &attrMapping ) {
163  StringMap attributes {} ;
164  auto excludeParameters = details::keys( attrMapping ) ;
165  for( auto &attr : attrMapping ) {
166  attributes.push_back( { attr.second, section.parameter<std::string>( attr.first ) } ) ;
167  }
168  auto element = createElement( name, attributes ) ;
169  auto parameters = section.parameters() ;
170  for( auto &p : parameters ) {
171  if( excludeParameters.end() != std::find( excludeParameters.begin(), excludeParameters.end(), p.first ) ) {
172  continue ;
173  }
174  const auto &metadata = section.metadata( ) ;
175  auto desciter = metadata.find( p.first + ".description" ) ;
176  auto optiter = metadata.find( p.first + ".optional" ) ;
177  if( (metadata.end() != desciter) && (metadata.end() != optiter) ) {
178  std::stringstream comment ;
179  if( optiter->second == "true" ) {
180  comment << "[Optional] " ;
181  }
182  comment << desciter->second ;
183  element.InsertEndChild( createComment( comment.str() ) ) ;
184  }
185  element.InsertEndChild( createParameter( p.first, p.second ) ) ;
186  }
187  return element ;
188  }
189 
190  //--------------------------------------------------------------------------
191 
192  TiXmlElement XMLConfigWriter::createElement( const std::string &name, const StringMap &attrs ) const {
193  TiXmlElement element( name ) ;
194  for( auto &attr : attrs ) {
195  element.SetAttribute( attr.first, attr.second ) ;
196  }
197  return element ;
198  }
199 
200  //--------------------------------------------------------------------------
201 
202  TiXmlComment XMLConfigWriter::createComment( const std::string &comment ) const {
203  return TiXmlComment( comment.c_str() ) ;
204  }
205 
206  //--------------------------------------------------------------------------
207 
208  TiXmlText XMLConfigWriter::createText( const std::string &text ) const {
209  return TiXmlText( text ) ;
210  }
211 
212  //--------------------------------------------------------------------------
213 
214  TiXmlElement XMLConfigWriter::createParameter( const std::string &name, const std::string &value ) const {
215  auto parameter = createElement( "parameter", { {"name", name} } ) ;
216  parameter.InsertEndChild( createText( value ) ) ;
217  return parameter ;
218  }
219 
220  // plugin registration
222 
223 } // namespace marlinmt
const Metadata & metadata() const
Get the section metadata.
XMLConfigWriter plugin Write an XML file from the configuration sections and parameters.
T parameter(const std::string &n) const
Get a parameter value as type T.
void write(const Configuration &cfg) override
Write the configuration object.
std::vector< std::pair< std::string, std::string > > StringMap
#define MARLINMT_DECLARE_CONFIG_WRITER(Class)
Definition: PluginManager.h:52
constexpr unsigned long long value(const Flag_t &flag)
Definition: Flags.h:106
void appendDescription(TiXmlElement &element, const ConfigSection &section) const
Append the config section description in the element tree as comment.
TiXmlElement createParameter(const std::string &name, const std::string &value) const
std::string _fname
The output file name.
TiXmlElement createParameterSection(const std::string &name, const ConfigSection &section, const StringMap &attrMapping={})
Create an XML element containing all parameters from a section.
ConfigSection & section(const std::string &sn)
Get a section by name.
Configuration class.
ConfigWriter base class Interface for writing configuration.
void init(const std::string &desc) override
Initialize the parser.
std::vector< std::string > subsectionNames() const
Get the list of subsection names.
TiXmlElement createElement(const std::string &name, const StringMap &attrs={}) const
TiXmlText createText(const std::string &text) const
const ParameterMap & parameters() const
Get the raw parameter storage.
ConfigSection class Holds a set of parameters and subsection.
Definition: Configuration.h:20
TiXmlComment createComment(const std::string &comment) const
bool hasSection(const std::string &n) const
Whether the section exists.
#define MARLINMT_RELEASE
std::vector< K > keys(const std::map< K, V > &m)
Definition: Utils.h:539