選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

XMLReader.hpp 48KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. // XMLReader.hpp
  2. //
  3. // (C) 2006 - 2009 MicroNeil Research Corporation.
  4. // See http://www.codedweller.com for details.
  5. //
  6. // This program is free software; you can redistribute it and/or modify it
  7. // under the terms of the GNU General Public License as published by the
  8. // Free Software Foundation; either version 2 of the License, or (at your
  9. // option) any later version.
  10. //
  11. // This program is distributed in the hope that it will be useful, but WITHOUT
  12. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14. // more details.
  15. //
  16. // You should have received a copy of the GNU General Public License along with
  17. // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  18. // Place, Suite 330, Boston, MA 02111-1307 USA
  19. //
  20. // What about this =============================================================
  21. // The XMLReader module provides a platform for reading configuration files
  22. // (or string data) containing well-formed xml and mapping that data to program
  23. // variables.
  24. // The idea is to provide the ability for an object or application to provide
  25. // a modular "XMLReader" object that models a hierarchical collection of
  26. // "settings" that can be represented easily in code and in xml.
  27. //
  28. // The following is an example model of a XMLReader in code and that same
  29. // XMLReader fully populated in xml.
  30. //
  31. // The code might look like this...
  32. //
  33. // int IntValue, DefaultInt = 3;
  34. // double DblValue, DefaultDbl = 3.14159;
  35. // bool BooleanValue, DefaultBool = false;
  36. // string StringValue, DefaultString = "NoStringHere";
  37. //
  38. // SpecialConfigurator : public XMLReaderHandler { // Create a special handler to build a list
  39. // ...
  40. // public:
  41. //
  42. // XMLReaderHandler& Startup(XMLReaderElement& E) { // This function returns a handy handler to
  43. // return MyStartupXMLReaderHandler; // (re) initialize this handler ;-)
  44. // }
  45. //
  46. // void Operator()() { // Each time the configurator is called
  47. // ...
  48. // }
  49. //
  50. // int Attribute1; // these items are interpreted and added
  51. // double Attribute2; // to the list. A XMLReaderHandler COULD
  52. // string Attribute3; // do something entirely different though ;-)
  53. // string Contents;
  54. // ...
  55. // } Special;
  56. //
  57. // XMLReaderElement SampleConfig("SampleConfiguration"); // Define a sample config (doc element)
  58. // SampleConfig // Populate the SampleConfig
  59. // .atStartCall(Special.Startup())
  60. // .Element("Integer", IntValue, DefaultInt).End() // Link an element to an int w/ default.
  61. // .Element("Double", DblValue, DefaultDbl).End("Double") // Link an element to a dbl w/ default.
  62. // .Element("String", StringValue, DefaultString).End("String") // Link an element to a string w/ default.
  63. // .Element("ComplexElements") // Create a sub element.
  64. // .Element("Complex1") // Sub element Complex1 has attributes.
  65. // .Attribute("IntAtt", IntValue, DefaultInt) // Complex1 has an integer attribute.
  66. // .Attribute("DblAtt", DblValue, DefaultDbl) // Complex1 has a dbl attribute.
  67. // .Element("IntAtt", IntValue).End() // IntAtt can also be set by a sub element.
  68. // .Element("DblAtt", DblValue).End() // DblAtt can also be set by a sub element.
  69. // .End() // That's it for Complex1.
  70. // .Element("Complex2") // Create the Complex2 sub element.
  71. // .Attribute("C2I", IntValue, DefaultInt) // C2I attribute.
  72. // .Attribute("C2D", DblValue) // C2D attribute - no default.
  73. // .Attribute("C2S", StringValue, DefultString) // C2S attribute - string w/ default.
  74. // .End("Complex2") // End of element throws if doesn't match.
  75. // .Element("Complex3", Special.Contents) // Element 3 using a special configurator.
  76. // .Attribute("A1", Special.Attribute1) // Set A1 and A2 and A3 and when the
  77. // .Attribute("A2", Special.Attribute2) // element has been completed, Special()
  78. // .Attribute("A3", Special.Attribute3) // will be called to record the entries.
  79. // .atEndCall(Special) // Here's where we register the handler.
  80. // .End() // Closing Complex3 to be ice.
  81. // .End() // Closing ComplexElements to be nice.
  82. // .End(); // Closing SampleConfiguration to be nice.
  83. //
  84. // The XML might look like this...
  85. //
  86. // <SampleConfiguration>
  87. // <Integer>10</Integer>
  88. // <Double>2.4</Double>
  89. // <String>This is a sample string</String>
  90. // <ComplexElements>
  91. // <Complex1 IntAtt="4" DblAtt="2.1324">
  92. // <IntAtt>24</IntAtt> <!-- changed IntAtt -->
  93. // </Complex1>
  94. // <Complex2 C2I='3' C2D='5.14' C2S='Some "string" we like' />
  95. // <Complex3> stuff in here </Complex3>
  96. // <Complex3> Another instance </Complex3>
  97. // <Complex3> Each one gets passed to Special() on activation </Complex3>
  98. // <Complex3> This way, Special() can build a list or some other </Complex3>
  99. // <Complex3> interesting thing with all of these. </Complex3>
  100. // <ComplexElements>
  101. // </SampleConfiguration>
  102. //
  103. // Include This Header Once Only ===============================================
  104. #ifndef XMLReader_included
  105. #define XMLReader_included
  106. #include <string>
  107. #include <sstream>
  108. #include <fstream>
  109. #include <cstring>
  110. #include <cstdlib>
  111. #include <list>
  112. namespace CodeDweller {
  113. class XMLReaderElement; // Elements exist
  114. class XMLReaderAttribute; // Attributes exist
  115. class XMLReaderData; // Data exists
  116. class XMLReaderTranslator; // Translators exist
  117. class XMLReaderMnemonic; // Mnemonics exist
  118. class XMLerator; // XMLerators exist
  119. class XMLeratorSetTrueOnComplete;
  120. typedef XMLReaderElement ConfigurationElement;
  121. typedef XMLReaderAttribute ConfigurationAttribute;
  122. typedef XMLReaderData ConfigurationData;
  123. typedef XMLReaderTranslator ConfigurationTranslator;
  124. typedef XMLReaderMnemonic ConfigurationMnemonic;
  125. typedef XMLerator Configurator;
  126. typedef XMLeratorSetTrueOnComplete ConfiguratorSetTrueOnComplete;
  127. class RawTranslator {
  128. private:
  129. int *IndexAssignment = 0;
  130. int *EndexAssignment = 0;
  131. std::string *RawDataAssignment = 0;
  132. public:
  133. void setRawDataAssignment(std::string &RawData);
  134. void setIndexAssignment(int &Index, int &Endex);
  135. void translate(int Index, int Endex, XMLReaderData &Data);
  136. };
  137. //// XMLReader Element /////////////////////////////////////////////////////
  138. //
  139. // Elements make up the core of a configuration. That is, a configuration is a
  140. // tree of elements. Elements translate directly to well formed xml elements in
  141. // a configuration file or string.
  142. class XMLReaderElement {
  143. private:
  144. std::string myName; // Elements have a name.
  145. // External important things I remember but don't touch...
  146. XMLReaderElement* myParent; // They may have a parrent.
  147. std::list<XMLerator*> myStartXMLerators; // Call these when we start Interpret()
  148. std::list<XMLerator*> myEndXMLerators; // Call these when we finish Interpret()
  149. // Internal / subordinate things I own and kill...
  150. std::list<XMLReaderAttribute*> myAttributes; // They may have a list of attributes.
  151. std::list<XMLReaderElement*> myElements; // They may have a list of sub-elements.
  152. std::list<XMLReaderMnemonic*> myMnemonics; // They may have a list of mnemonics.
  153. std::list<XMLReaderTranslator*> myTranslators; // They may have a list of translators.
  154. RawTranslator myRawTranslator; // Provides entire element.
  155. // During Interpret() operations we keep track of where we are seen...
  156. int myLine; // Last line number I was seen on.
  157. int myIndex; // Last char position I was seen on.
  158. int myEndex; // Last char of element.
  159. int myLength; // Last segment length.
  160. bool myCleanFlag; // Keep track of initialization.
  161. bool myInitOnInterpretFlag; // Initialize() at each Interpret()?
  162. bool myWasProcessed; // true iff the element was processed.
  163. bool *wasProcessed; // Points to caller's variable.
  164. void runStartXMLerators(XMLReaderData& D); // Does what it says ;-)
  165. void runEndXMLerators(XMLReaderData& D); // Does what it says ;-)
  166. public:
  167. XMLReaderElement(const char* Name); // Must be constructed with a name
  168. XMLReaderElement(const std::string Name); // either c string or c++ string.
  169. XMLReaderElement(const char* Name, XMLReaderElement& Parent); // Sub-elements are constructed with a
  170. XMLReaderElement(const std::string Name, XMLReaderElement& Parent); // parrent.
  171. // Upon desctruction an element will delete all subordinate objects:
  172. // * All sub element objects.
  173. // * All attribute objects.
  174. // * All mnemonic objects.
  175. // * All translator objects.
  176. // It is important to use new when passing one of these objects to an
  177. // element or attribute to prevent problems with the delete operation.
  178. // NORMALLY these things would be created using factory methods on the
  179. // element and attribute objects themselves - so be careful.
  180. // It will not delete XMLerators - they must
  181. // be deleted elsewhere because they may have been
  182. // re-used and this element wouldn't know about it ;-)
  183. ~XMLReaderElement(); // The descrutor clears and deletes all!
  184. // Elements can be probed for some simple, useful things.
  185. std::string Name(); // Get the name of this element.
  186. XMLReaderElement& Parent(); // Get the parent of this element.
  187. XMLReaderElement& Parent(XMLReaderElement& newParent); // Set the parent of this element.
  188. // Note - if there is no parent (an element is the root) then it will
  189. // return a reference to itself when Parent() is called.
  190. int Line(); // Get the last line number.
  191. int Index(); // Get the last data position.
  192. int Length(); // Get the last length.
  193. // Elements can contain either data or sub-elements.
  194. XMLReaderElement& Element(const char* Name); // Add a new sub element by c string name.
  195. XMLReaderElement& Element(const std::string Name); // Add a new sub element by c++ string name.
  196. //// Mapping element factory methods for convenience.
  197. //// Root-Node elements are _usually_ empty and without attributes in xml
  198. //// so we don't make any of that type of convenience constructor here.
  199. // char* versions
  200. XMLReaderElement& Element( // Mapping factory for convenience,
  201. const char* Name, // requires a name, of course,
  202. XMLReaderTranslator& newTranslator); // Add a Translator to this element.
  203. XMLReaderElement& Element( // Mapping factory for convenience,
  204. const char* Name, // requires a name, of course,
  205. std::string& x, std::string init = std::string("")); // Map to a string.
  206. XMLReaderElement& Element( // Mapping factory for convenience,
  207. const char* Name, // requires a name, of course,
  208. int& x, int init = 0, int radix = 0); // Map to an int.
  209. XMLReaderElement& Element( // Mapping factory for convenience,
  210. const char* Name, // requires a name, of course,
  211. double& x, double init = 0.0); // Map to a double.
  212. XMLReaderElement& Element( // Mapping factory for convenience,
  213. const char* Name, // requires a name, of course,
  214. bool& x, bool init = false); // Map to a boolean.
  215. // string versions
  216. XMLReaderElement& Element( // Mapping factory for convenience,
  217. const std::string Name, // requires a name, of course,
  218. XMLReaderTranslator& newTranslator); // Add a Translator to this element.
  219. XMLReaderElement& Element( // Mapping factory for convenience,
  220. const std::string Name, // requires a name, of course,
  221. std::string& x, std::string init = std::string("")); // Map to a string.
  222. XMLReaderElement& Element( // Mapping factory for convenience,
  223. const std::string Name, // requires a name, of course,
  224. int& x, int init = 0, int radix = 0); // Map to an int.
  225. XMLReaderElement& Element( // Mapping factory for convenience,
  226. const std::string Name, // requires a name, of course,
  227. double& x, double init = 0.0); // Map to a double.
  228. XMLReaderElement& Element( // Mapping factory for convenience,
  229. const std::string Name, // requires a name, of course,
  230. bool& x, bool init = false); // Map to a boolean.
  231. XMLReaderElement& RawData( // Copy entire element to
  232. std::string &Element); // a string.
  233. XMLReaderElement& RawIndex( // Copy indices of the entire
  234. int &Index, int &Endex); // element.
  235. XMLReaderElement& indicator(bool& x); // Set x to true iff element is found.
  236. // End methods for heading back up the tree at the end of an element.
  237. class EndNameDoesNotMatch {}; // Throw when End(name) doesn't match.
  238. XMLReaderElement& End(); // Return this element's parent.
  239. XMLReaderElement& End(const char* Name); // Check the name and return the parent
  240. XMLReaderElement& End(const std::string Name); // if the name is correct - or throw!
  241. // Elements can have attributes.
  242. XMLReaderAttribute& Attribute(const char* Name); // Add an attribute using a cstring.
  243. XMLReaderAttribute& Attribute(const std::string Name); // Add an attribute using a c++ string.
  244. //// Mapping Attribute factory methods for convenience.
  245. // char* versions
  246. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  247. const char* Name, // requires a name, of course,
  248. XMLReaderTranslator& newTranslator); // Add a Translator to this element.
  249. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  250. const char* Name, // requires a name, of course,
  251. std::string& x, std::string init = std::string("")); // Map to a string.
  252. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  253. const char* Name, // requires a name, of course,
  254. int& x, int init = 0, int radix = 0); // Map to an int.
  255. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  256. const char* Name, // requires a name, of course,
  257. double& x, double init = 0.0); // Map to a double.
  258. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  259. const char* Name, // requires a name, of course,
  260. bool& x, bool init = false); // Map to a boolean.
  261. // string versions
  262. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  263. const std::string Name, // requires a name, of course,
  264. XMLReaderTranslator& newTranslator); // Add a Translator to this element.
  265. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  266. const std::string Name, // requires a name, of course,
  267. std::string& x, std::string init = std::string("")); // Map to a string.
  268. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  269. const std::string Name, // requires a name, of course,
  270. int& x, int init = 0, int radix = 0); // Map to an int.
  271. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  272. const std::string Name, // requires a name, of course,
  273. double& x, double init = 0.0); // Map to a double.
  274. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  275. const std::string Name, // requires a name, of course,
  276. bool& x, bool init = false); // Map to a boolean.
  277. // Elements can Initialize() at each Interpret() call.
  278. XMLReaderElement& setInitOnInterpret(); // Set the init on interpret flag.
  279. // Elements can call external functions to aid in special operations
  280. // such as building lists.
  281. XMLReaderElement& atStartCall(XMLerator& Functor); // Add an atStart call-back to this element.
  282. XMLReaderElement& atEndCall(XMLerator& Functor); // Add an atEnd call-back to this element.
  283. // Extracting data from the element's contents is done with
  284. // translators. A good set of primatives are built in, but the user
  285. // can also make their own. If an Element is mapped to more than
  286. // one then they are all called once the element's contents are
  287. // collected. A translator takes the data provided by the element,
  288. // converts it into the expected type, and sets one or more variables
  289. // to the converted value. Usually - just one variable.
  290. XMLReaderElement& mapTo(XMLReaderTranslator& newTranslator); // Add a Translator to this element.
  291. XMLReaderElement& mapTo(std::string& x, std::string init = std::string("")); // Map to a string.
  292. XMLReaderElement& mapTo(int& x, int init = 0, int radix = 0); // Map to an int.
  293. XMLReaderElement& mapTo(double& x, double init = 0.0); // Map to a double.
  294. XMLReaderElement& mapTo(bool& x, bool init = false); // Map to a boolean.
  295. // An Element's contents may use some special mnemonics to make a
  296. // XMLReader easier to understand and less error prone. When the
  297. // contents match a mnemnoic then the translation of the mnemonic is
  298. // passed to the Translators instead of the raw contents.
  299. XMLReaderElement& Mnemonic(const char* name, const char* value); // Add a mnemonic using c strings.
  300. XMLReaderElement& Mnemonic(const char* name, const std::string value); // Add a mnemonic using c & c++ strings.
  301. XMLReaderElement& Mnemonic(const std::string name, const char* value); // Add a mnemonic using c++ & c strings.
  302. XMLReaderElement& Mnemonic(const std::string name, const std::string value); // Add a mnemonic using c++ strings.
  303. // The way data gets into an element tree is that it is Interpret()ed
  304. // recursively. The data is loaded into a XMLReaderData object which
  305. // is passed to the top Element. That element interpretes the data, moves
  306. // the interpretation pointers, and passes the data on to it's subordinate
  307. // elements in turn. They do the same recursively. When the last sub -
  308. // element has had it's way with the data, the interpretation process is
  309. // complete. The XMLReaderData object will contain the original data
  310. // and a log of anything that happened during the interpretation process.
  311. //
  312. // Each time an element is asked to Interpret() data, it calls any atStart
  313. // configurators, translates any attributes, then either translates it's
  314. // contents or passes the data to it's children, then calls any atEnd
  315. // configurators.
  316. //
  317. // To ensure that the correct default values are used the Initialize() is
  318. // always called on all internal attributes and elements before any data is
  319. // interpreted. To prevent this from being inefficient, a boolean flag is
  320. // kept in each element to keep track of whether it is clean and if it is
  321. // then the call to Initialize will simply return (skipping subordinate
  322. // elements along the way).
  323. //
  324. // Interpret returns true if this object found itself at the current
  325. // Data.Index and false if not. This helps keep the recursive parsing
  326. // code simpler ;-)
  327. void initialize(); // Reset all translators to defaults.
  328. void notifyDirty(); // Set dirty (if translators change).
  329. bool interpret(XMLReaderData& Data); // (re) Interpret this data.
  330. };
  331. //// Function object to call after /////////////////////////////////////////////////////
  332. //
  333. // Elements make up the core of a configuration. That is, a configuration is a
  334. // tree of elements. Elements translate directly to well formed xml elements in
  335. // a configuration file or string.
  336. //// Attribute Functor //////////////////////////////////////////////////////////////
  337. //
  338. // This functor is passed to XMLReaderAttribute::indicator() as an
  339. // optional parameter, and is called if the attribute is processed.
  340. class AttributeFunctor {
  341. public:
  342. virtual void operator()(XMLReaderAttribute& A, XMLReaderData& D) = 0;
  343. virtual ~AttributeFunctor() {}
  344. };
  345. //// XMLReader Attribute ///////////////////////////////////////////////////
  346. //
  347. // Attributes translate directly to well formed xml attributes (within the
  348. // start tag of an element).
  349. class XMLReaderAttribute {
  350. private:
  351. std::string myName; // Elements have a name.
  352. XMLReaderElement& myParent; // They may have a parrent.
  353. std::list<XMLReaderMnemonic*> myMnemonics; // They may have a list of mnemonics.
  354. std::list<XMLReaderTranslator*> myTranslators; // They may have a list of translators.
  355. int myLine; // Last line number I was seen on.
  356. int myIndex; // Last char position I was seen on.
  357. int myLength; // Last segment length.
  358. bool myWasProcessed; // true iff the attribute was processed.
  359. bool *wasProcessed; // Points to caller's variable.
  360. AttributeFunctor *attrFunc; // Call if attribute was processed.
  361. public:
  362. XMLReaderAttribute(const char* Name, XMLReaderElement& Parent); // Sub-elements are constructed with a
  363. XMLReaderAttribute(const std::string Name, XMLReaderElement& Parent); // parrent.
  364. // Attributes delete their Mnemonics and Translators when they go.
  365. // See Elements for similar warnings about objects provided to
  366. // this object... you must use new to be safe, or better yet - stick to
  367. // the built in factory methods ;-)
  368. ~XMLReaderAttribute(); // Crush, Kill, Destroy!
  369. // Attributes can be probed for some simple, useful things.
  370. std::string Name(); // Get the name of this attribute.
  371. XMLReaderElement& Parent(); // Get the parent of this attribute.
  372. int Line(); // Get the last line number.
  373. int Index(); // Get the last data position.
  374. int Length(); // Get the last length.
  375. void notifyDirty(); // Attributes use this when they change.
  376. // For convenience in building configurations, an Attribute offers
  377. // some call-through methods to it's parrent Element. This allows for
  378. // clear, concise .method() coding that mimics an outline of the
  379. // configuration structure.
  380. //// For switching back to the parent element and adding new sub-elements.
  381. XMLReaderElement& Element(const char* Name); // Add a new sub element by c string name.
  382. XMLReaderElement& Element(const std::string Name); // Add a new sub element by c++ string name.
  383. //// Mapping element factory methods for convenience.
  384. //// Root-Node elements are _usually_ empty and without attributes in xml
  385. //// so we don't make any of that type of convenience constructor here.
  386. // char* versions
  387. XMLReaderElement& Element( // Mapping factory for convenience,
  388. const char* Name, // requires a name, of course,
  389. XMLReaderTranslator& newTranslator); // Add a Translator to this element.
  390. XMLReaderElement& Element( // Mapping factory for convenience,
  391. const char* Name, // requires a name, of course,
  392. std::string& x, std::string init = std::string("")); // Map to a string.
  393. XMLReaderElement& Element( // Mapping factory for convenience,
  394. const char* Name, // requires a name, of course,
  395. int& x, int init = 0, int radix = 0); // Map to an int.
  396. XMLReaderElement& Element( // Mapping factory for convenience,
  397. const char* Name, // requires a name, of course,
  398. double& x, double init = 0.0); // Map to a double.
  399. XMLReaderElement& Element( // Mapping factory for convenience,
  400. const char* Name, // requires a name, of course,
  401. bool& x, bool init = false); // Map to a boolean.
  402. // string versions
  403. XMLReaderElement& Element( // Mapping factory for convenience,
  404. const std::string Name, // requires a name, of course,
  405. XMLReaderTranslator& newTranslator); // Add a Translator to this element.
  406. XMLReaderElement& Element( // Mapping factory for convenience,
  407. const std::string Name, // requires a name, of course,
  408. std::string& x, std::string init = std::string("")); // Map to a string.
  409. XMLReaderElement& Element( // Mapping factory for convenience,
  410. const std::string Name, // requires a name, of course,
  411. int& x, int init = 0, int radix = 0); // Map to an int.
  412. XMLReaderElement& Element( // Mapping factory for convenience,
  413. const std::string Name, // requires a name, of course,
  414. double& x, double init = 0.0); // Map to a double.
  415. XMLReaderElement& Element( // Mapping factory for convenience,
  416. const std::string Name, // requires a name, of course,
  417. bool& x, bool init = false); // Map to a boolean.
  418. // End methods for heading back up the tree at the end of an element.
  419. XMLReaderElement& End(); // Return this element's parent.
  420. XMLReaderElement& End(const char* Name); // Check the name and return the parent
  421. XMLReaderElement& End(const std::string Name); // if the name is correct - or throw!
  422. //// For adding new attributes to the parent element.
  423. XMLReaderAttribute& Attribute(const char* Name); // Add an attribute using a cstring.
  424. XMLReaderAttribute& Attribute(const std::string Name); // Add an attribute using a c++ string.
  425. //// Mapping Attribute factory methods for convenience.
  426. // char* versions
  427. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  428. const char* Name, // requires a name, of course,
  429. XMLReaderTranslator& newTranslator); // Add a Translator to this element.
  430. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  431. const char* Name, // requires a name, of course,
  432. std::string& x, std::string init = std::string("")); // Map to a string.
  433. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  434. const char* Name, // requires a name, of course,
  435. int& x, int init = 0, int radix = 0); // Map to an int.
  436. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  437. const char* Name, // requires a name, of course,
  438. double& x, double init = 0.0); // Map to a double.
  439. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  440. const char* Name, // requires a name, of course,
  441. bool& x, bool init = false); // Map to a boolean.
  442. // string versions
  443. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  444. const std::string Name, // requires a name, of course,
  445. XMLReaderTranslator& newTranslator); // Add a Translator to this element.
  446. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  447. const std::string Name, // requires a name, of course,
  448. std::string& x, std::string init = std::string("")); // Map to a string.
  449. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  450. const std::string Name, // requires a name, of course,
  451. int& x, int init = 0, int radix = 0); // Map to an int.
  452. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  453. const std::string Name, // requires a name, of course,
  454. double& x, double init = 0.0); // Map to a double.
  455. XMLReaderAttribute& Attribute( // Mapping factory for convenience,
  456. const std::string Name, // requires a name, of course,
  457. bool& x, bool init = false); // Map to a boolean.
  458. XMLReaderAttribute& indicator(bool& x); // Set x to true iff attribute is found.
  459. XMLReaderAttribute& indicator(bool& x, AttributeFunctor &f); // Set x to true and invoke f() iff
  460. // attribute is found.
  461. //// Set Init On Interprete for the parent element.
  462. XMLReaderElement& setInitOnInterpret(); // Set the init on interpret flag.
  463. //// For adding configurators to the parent element.
  464. XMLReaderElement& atStartCall(XMLerator& Functor); // Add an atStart call-back to this element.
  465. XMLReaderElement& atEndCall(XMLerator& Functor); // Add an atEnd call-back to this element.
  466. // Of course, the most useful thing about attributes is that they can
  467. // be mapped to variables using translators. The same as those that
  468. // apply to the parent element's contents. Here they are for use on this
  469. // attribute.
  470. XMLReaderAttribute& mapTo(XMLReaderTranslator& newTranslator); // Add a Translator to this attribute.
  471. XMLReaderAttribute& mapTo(std::string& x, std::string init = std::string("")); // Map to a string.
  472. XMLReaderAttribute& mapTo(int& x, int init, int radix = 0); // Map to an int.
  473. XMLReaderAttribute& mapTo(double& x, double init = 0.0); // Map to a double.
  474. XMLReaderAttribute& mapTo(bool& x, bool init = false); // Map to a boolean.
  475. // Attributes can have mnemonics just like elements.
  476. XMLReaderAttribute& Mnemonic(const char* name, const char* value); // Add a mnemonic using a c string.
  477. XMLReaderAttribute& Mnemonic(const char* name, const std::string value); // Add a mnemonic using c & c++ strings.
  478. XMLReaderAttribute& Mnemonic(const std::string name, const char* value); // Add a mnemonic using c++ & c strings.
  479. XMLReaderAttribute& Mnemonic(const std::string name, const std::string value); // Add a mnemonic using a c++ string.
  480. // Attributes participate in the Interprete() task just like elements.
  481. void initialize(); // Reset all translators to defaults.
  482. bool interpret(XMLReaderData& Data); // (re) Interpret this data.
  483. };
  484. //// XMLReader Data ////////////////////////////////////////////////////////
  485. //
  486. // A XMLReaderData object holds on to the configuration source data and
  487. // provideds a place to log any information about how the configuration was
  488. // interpreted. It also creates and destroys a handy char[] to contain the
  489. // data. To make this beastie easier to handle, we use the Named Constructor
  490. // Idiom and hide the true constructor in the private section.
  491. class XMLReaderData { // XMLReader Data Source
  492. private:
  493. char* myDataBuffer; // The actual data buffer.
  494. int myBufferSize; // Size of the current buffer.
  495. int myIndex; // The current interpretation index.
  496. int myLine; // Current line number.
  497. public:
  498. XMLReaderData(const char* FileName); // Constructor from c string file name.
  499. XMLReaderData(const std::string FileName); // Constructor from c++ string file name.
  500. XMLReaderData(const char* Data, int Length); // Raw constructor from text buffer.
  501. ~XMLReaderData(); // Destroys the internal buffer etc.
  502. char Data(int Index); // Returns char from Data[Index]
  503. int Index(); // Reads the current Index.
  504. int Index(int i); // Changes the current Index.
  505. int Line(); // Reads the current Line number.
  506. int addNewLines(int Count); // Increments the Line number.
  507. std::string extract(int Index, int Endex) const ; // Return substring of buffer.
  508. std::stringstream Log; // Convenient Interpret log.
  509. };
  510. //// XMLReader Translator //////////////////////////////////////////////////
  511. //
  512. // A Translator converts the contents provided to it in string form into some
  513. // other data type. The object here is a prototype for that, followed by a
  514. // collection of the basic translators used for built-in mapTo()s.
  515. class XMLReaderTranslator { // Translators exist
  516. public:
  517. virtual ~XMLReaderTranslator(){}; // Stop No Virt Dtor warnings.
  518. virtual void translate(const char* Value) = 0; // Pure virtual translator.
  519. virtual void initialize() = 0; // Pure virtual initializer.
  520. };
  521. class StringTranslator : public XMLReaderTranslator {
  522. private:
  523. std::string& myVariable; // Variable to map.
  524. std::string myInitializer; // Initial/Default value.
  525. public:
  526. StringTranslator( // Construct this with
  527. std::string& Variable, // the variable to map,
  528. std::string Inititializer); // and the default value.
  529. void translate(const char* Value); // Provide a translation method.
  530. void initialize(); // Provide an initialization method.
  531. };
  532. class IntegerTranslator : public XMLReaderTranslator {
  533. private:
  534. int& myVariable; // Variable to map.
  535. int myInitializer; // Initial/Default value.
  536. int myRadix; // Radix for strtol()
  537. public:
  538. IntegerTranslator( // Construct this with
  539. int& Variable, // the variable to map,
  540. int Inititializer, // and the default value.
  541. int Radix); // For this one we also need a Radix.
  542. void translate(const char* Value); // Provide a translation method.
  543. void initialize(); // Provide an initialization method.
  544. };
  545. class DoubleTranslator : public XMLReaderTranslator {
  546. private:
  547. double& myVariable; // Variable to map.
  548. double myInitializer; // Initial/Default value.
  549. public:
  550. DoubleTranslator( // Construct this with
  551. double& Variable, // the variable to map,
  552. double Inititializer); // and the default value.
  553. void translate(const char* Value); // Provide a translation method.
  554. void initialize(); // Provide an initialization method.
  555. };
  556. class BoolTranslator : public XMLReaderTranslator {
  557. private:
  558. bool& myVariable; // Variable to map.
  559. bool myInitializer; // Initial/Default value.
  560. public:
  561. BoolTranslator( // Construct this with
  562. bool& Variable, // the variable to map,
  563. bool Inititializer); // and the default value.
  564. void translate(const char* Value); // Provide a translation method.
  565. void initialize(); // Provide an initialization method.
  566. };
  567. //// XMLReader Mnemonic ////////////////////////////////////////////////////
  568. //
  569. // A Mnemonic allows the actual contents of an element or attribute to be
  570. // exchanged for a different "named" value to help eliminate "magic numbers"
  571. // and "secret codes" from configurations. One way this might be used is to
  572. // map an enumeration to the appropriate integer values, or things like YES and
  573. // NO to boolean true and false (respectively) when turning on/off program
  574. // options.
  575. class XMLReaderMnemonic { // Mnemonics
  576. private:
  577. std::string myName; // What is the Mnemonic?
  578. std::string myValue; // What is the translation?
  579. public:
  580. XMLReaderMnemonic(std::string Name, std::string Value); // To make one, provide both parts.
  581. bool test(std::string Name); // Test to see if this Mnemonic matches.
  582. std::string Value(); // If it does then we will need it's value.
  583. };
  584. //// XMLerator //////////////////////////////////////////////////////////////
  585. //
  586. // An XMLerator is a "functor" or "closure" or "callback" that can be used to
  587. // support sophisticated interpretation options. The most basic and necessary
  588. // of these is support for list building. Consider an object created to contain
  589. // a list of records where each record might be represented as a collection of
  590. // attributes and elements. The object would have data elements mapped to the
  591. // attributes and elements in the configuration and then control elements which
  592. // are functors for initializing the list and storing new entries as they are
  593. // completed. The object here is a pure virtual prototype.
  594. class XMLerator { // XMLerators exist
  595. public:
  596. virtual void operator()(XMLReaderElement& E, XMLReaderData& D) = 0; // Pure virtual configurator.
  597. virtual ~XMLerator() {} // Virtual dtor keeps warnings away.
  598. };
  599. //// Include our inline methods ////////////////////////////////////////////////
  600. #include "XMLReader.inline.hpp"
  601. //// Utilities /////////////////////////////////////////////////////////////////
  602. // SetTrueOnComplete XMLerator //////////////////////////////////////////////
  603. class XMLeratorSetTrueOnComplete : public XMLerator { // XMLerator set's a boolean true.
  604. private:
  605. bool* myBoolean; // The boolean to set.
  606. public:
  607. XMLeratorSetTrueOnComplete(); // Must init to NULL for safety.
  608. void setup(bool& Target); // Link to the target boolean.
  609. void operator()(XMLReaderElement& E, XMLReaderData& D); // Handle the operation.
  610. };
  611. }
  612. #endif
  613. // End Of Include Only Once