bpmn++
A BPMN parser library, written in C++
XMLObject.h
Go to the documentation of this file.
1 // schematic++ v0.4.0
2 #ifndef XMLObject_H
3 #define XMLObject_H
4 #include <memory>
5 #include <sstream>
6 #include <string>
7 #include <string_view>
8 #include <unordered_map>
9 #include <vector>
10 #include <optional>
11 
12 #include <xercesc/dom/DOM.hpp>
13 
14 /**
15  * @brief The `XML` namespace contains classes representing XML-nodes defined in given XML-schema(s).
16  */
17 namespace XML {
18 
19 class XMLObject;
20 
21 typedef std::string ClassName;
22 typedef std::string ElementName;
23 typedef std::string TextContent;
24 typedef std::string Namespace;
25 typedef std::string AttributeName;
26 
27 /**
28  * @brief A struct representing the value of an XML-node attribute.
29  *
30  * The Value struct stores a value and provides implicit conversion and assignment operators
31  * to facilitate easy conversion between different types and convenient assignment
32  * of values.
33  *
34  * Example usage:
35  * ```
36  * Value value;
37  * value = std::to_string("a_string"); // Assignment using a std::string.
38  * value = true; // Assignment using a bool.
39  * value = 42; // Assignment using an int.
40  * value = 3.14; // Assignment using a double.
41  *
42  * std::string stringValue = value; // Implicit conversion to std::string.
43  * bool booleanValue = value; // Implicit conversion to bool.
44  * int integerValue = value; // Implicit conversion to int.
45  * double realValue = value; // Implicit conversion to double.
46  * ```
47  */
48 struct Value {
49  std::string value;
50  operator std::string_view() const { return value; };
51  operator std::string() const { return value; };
52  operator bool() const { return (value == True); };
53  operator int() const { try { return std::stoi(value); } catch(...) { throw std::runtime_error("Cannot convert '" + value + "' to int"); } };
54  operator double() const { try { return std::stod(value); } catch(...) { throw std::runtime_error("Cannot convert '" + value + "' to double"); } };
55  Value& operator=(const std::string& s) { value = s; return *this; };
56  Value& operator=(bool b) { value = (b ? True : False); return *this; };
57  Value& operator=(int i) { value = std::to_string(i); return *this; };
58  Value& operator=(double d) { value = std::to_string(d); return *this; };
59  Value(const std::string& s) : value(s) {};
60  Value(bool b) : value(b ? True : False) {};
61  Value(int i) : value(std::to_string(i)) {};
62  Value(double d) : value(std::to_string(d)) {};
63  inline static std::string True = "true";
64  inline static std::string False = "false";
65 };
66 
67 /**
68  * @brief A struct representing an attribute of an XML-node.
69  *
70  * The `Attribute` struct stores information about the namespace, prefix, name, and
71  * value of the attribute.
72  */
73 struct Attribute {
78 };
79 
80 typedef std::vector<Attribute> Attributes;
81 typedef std::vector<std::unique_ptr<XMLObject>> Children;
82 
83 /// @brief Template function used to store in factory
84 template<typename T> XMLObject* createInstance(const Namespace& xmlns, const ClassName& className, const xercesc::DOMElement* element) { return new T(xmlns, className, element, T::defaults); }
85 
86 /// @brief Factory used to create instance depending on element name
87 typedef std::unordered_map<ElementName, XMLObject* (*)(const Namespace& xmlns, const ClassName& className, const xercesc::DOMElement* element)> Factory;
88 
89 
90 /**
91  * @brief A class representing a node in an XML-tree.
92  *
93  * The XMLObject class allows to read and store an XML-tree. The root element can be created using
94  * - @ref XMLObject::createFromStream(std::istream& xmlStream)
95  * - @ref XMLObject::createFromString(const std::string& xmlString)
96  * - @ref XMLObject::createFromFile(const std::string& filename)
97  *
98  * Each object has the following members:
99  * - @ref xmlns : refers to the XML namespace
100  * - @ref className : refers to the class it belong to
101  * - @ref elementName : refers to the name used in the XML
102  * - @ref prefix : refers to the namespace prefix in the XML
103  * - @ref textContent : textual content of XML element without children
104  * - @ref attributes : a list of attributes containing the namespace, prefix, attribute name,
105  * and attribute value
106  * - @ref children : a list of child elements
107  *
108  * Derived classes with dedicated members for attributes and children are automatically generated by
109  * schematic++ according to respective XML schema definition(s).
110  *
111  * Each XMLObject can be converted to a string using @ref stringify() and printed to an output stream
112  * using @ref operator<<(std::ostream& os, const XMLObject* obj) and
113  * @ref operator<<(std::ostream& os, const XMLObject& obj) .
114  */
115 class XMLObject {
116 
117 public:
118  /**
119  * @brief Create an XMLObject from the input stream.
120  *
121  * @param xmlStream The input stream containing the XML data.
122  * @return A pointer to the created XMLObject.
123  * @throws std::runtime_error if parsing the XML fails.
124  */
125  static XMLObject* createFromStream(std::istream& xmlStream);
126 
127  /**
128  * @brief Create an XMLObject from a string representation of XML.
129  *
130  * @param xmlString The string containing the XML data.
131  * @return A pointer to the created XMLObject.
132  * @throws std::runtime_error if parsing the XML fails.
133  */
134  static XMLObject* createFromString(const std::string& xmlString);
135 
136  /**
137  * @brief Create an XMLObject from an XML file.
138  *
139  * @param filename The path to the XML file.
140  * @return A pointer to the created XMLObject.
141  * @throws std::runtime_error if loading the file or parsing the XML fails.
142  */
143  static XMLObject* createFromFile(const std::string& filename);
144 
145  virtual ~XMLObject() {};
146 
147 protected:
148  static XMLObject* createObject(const xercesc::DOMElement* element);
149 
150 template<typename T> friend XMLObject* createInstance(const Namespace& xmlns, const ClassName& className, const xercesc::DOMElement* element);
151 
152 protected:
153  XMLObject(const Namespace& xmlns, const ClassName& className, const xercesc::DOMElement* element, const Attributes& defaultAttributes);
154 
155  inline static Factory factory;
156 public:
157  /// @brief Returns a pointer of type T of the object.
158  template<typename T> inline T* is() {
159  return dynamic_cast<T*>(this);
160  }
161 
162  template<typename T> inline const T* is() const {
163  return dynamic_cast<const T*>(this);
164  }
165 
166  /**
167  * @brief Attempt to cast the current instance to the specified type T.
168  * @return A pointer to the casted object.
169  * @throws std::runtime_error if the cast fails.
170  */
171  template<typename T> inline T* get() {
172  T* ptr = dynamic_cast<T*>(this);
173  if ( ptr == nullptr ) {
174  throw std::runtime_error("XMLObject: Illegal cast");
175  }
176  return ptr;
177  }
178 
179  /**
180  * @brief Attempt to cast the current instance to the specified type T.
181  * @return A pointer to the casted object.
182  * @throws std::runtime_error if the cast fails.
183  */
184  template<typename T> inline const T* get() const {
185  const T* ptr = dynamic_cast<const T*>(this);
186  if ( ptr == nullptr ) {
187  throw std::runtime_error("XMLObject: Illegal cast");
188  }
189  return ptr;
190  }
191 
192 private:
193  template<typename T>
194  void findRecursive(std::vector<std::reference_wrapper<T> >& result, const Children& descendants)
195  {
196  for (auto& descendant : descendants) {
197  if (descendant->is<T>()) {
198  result.push_back(*descendant->get<T>());
199  }
200  findRecursive(result, descendant->children );
201  }
202  }
203 
204  template<typename T>
205  void findRecursive(std::vector<std::reference_wrapper<const T> >& result, const Children& descendants) const
206  {
207  for (auto& descendant : descendants) {
208  if (descendant->is<const T>()) {
209  result.push_back(*descendant->get<const T>());
210  }
211  findRecursive(result, descendant->children );
212  }
213  }
214 
215 public:
216  /**
217  * @brief Find all descendants of type T.
218  *
219  * @return A vector of references to descendants of type T.
220  */
221  template<typename T>
222  std::vector<std::reference_wrapper<T> > find()
223  {
224  std::vector<std::reference_wrapper<T> > result;
225  findRecursive(result, children);
226  return result;
227  }
228 
229  /**
230  * @brief Find all descendants of type T.
231  *
232  * @return A vector of const references to descendants of type T.
233  */
234  template<typename T>
235  std::vector<std::reference_wrapper<const T> > find() const
236  {
237  std::vector<std::reference_wrapper<const T> > result;
238  findRecursive(result, children);
239  return result;
240  }
241 
246 
247  TextContent textContent; ///< Textual content of XML element without children
248  Children children; ///< Child nodes of the XML element
249  Attributes attributes; /// Attributes of the XML element
250  inline static const Attributes defaults = {};
251 
252  /**
253  * @brief Convert the XMLObject and its children to a string representation.
254  *
255  * @return The string representation of the XMLObject.
256  */
257  std::string stringify() const;
258 
259  /**
260  * @brief Creates formated string representing the XMLObject including its children.
261  *
262  * @return A formated string representing the XMLObject.
263  */
264  std::string format(std::string indentation = "\t", unsigned int depth = 0) const;
265 
266  /**
267  * @brief Get a required child of type T.
268  *
269  * @return A reference to the required child.
270  * @throws std::runtime_error if the required child is not found.
271  */
272  template<typename T> T& getRequiredChild() {
273  for ( auto& child : children ) {
274  if ( child->is<T>() ) {
275  return *child->get<T>();
276  }
277  }
278  throw std::runtime_error("Failed to get required child of element '" + elementName + "'");
279  }
280 
281  /**
282  * @brief Get an optional child of type T.
283  *
284  * @return An optional containing a reference to the optional child if found,
285  * or `std::nullopt` if the optional child is not found.
286  */
287  template<typename T> std::optional< std::reference_wrapper<T> > getOptionalChild() {
288  for ( auto& child : children ) {
289  if ( child->is<T>() ) {
290  return *child->get<T>();
291  }
292  }
293  return std::nullopt;
294  }
295 
296  /**
297  * @brief Get all children of type T.
298  *
299  * @return A vector of references to the children of type T.
300  */
301  template<typename T> std::vector< std::reference_wrapper<T> > getChildren() {
302  std::vector< std::reference_wrapper<T> > result;
303  for ( auto& child : children ) {
304  if ( child->is<T>() ) {
305  result.push_back(*child->get<T>());
306  }
307  }
308  return result;
309  }
310 
311  /**
312  * @brief Get a required child with the specified element name.
313  *
314  * @param elementName The name of the child element without namespace prefix.
315  * @return A reference to the required child.
316  * @throws std::runtime_error if the required child is not found.
317  */
319 
320  /**
321  * @brief Get the optional child with the specified element name.
322  *
323  * @param elementName The name of the child element without namespace prefix.
324  * @return An optional containing a reference to the optional child if found,
325  * or `std::nullopt` if the optional child is not found.
326  */
327  std::optional< std::reference_wrapper<XMLObject> > getOptionalChildByName(const ElementName& elementName);
328 
329  /**
330  * @brief Get all children with the specified element name.
331  *
332  * @param elementName The name of the child elements without namespace prefix.
333  * @return A vector of references to the children with the specified element name.
334  */
335  std::vector< std::reference_wrapper<XMLObject> > getChildrenByName(const ElementName& elementName);
336 
337  /**
338  * @brief Get a required attribute with the specified attribute name.
339  *
340  * @param attributeName The name of the attribute without namespace prefix.
341  * @return A reference to the required attribute.
342  * @throws std::runtime_error if the required attribute is not found.
343  */
344  Attribute& getRequiredAttributeByName(const AttributeName& attributeName);
345 
346  /**
347  * @brief Get an optional attribute with the specified attribute name.
348  *
349  * @param attributeName The name of the attribute without namespace prefix.
350  * @return An optional containing a reference to the optional attribute if found,
351  * or `std::nullopt` if the optional attribute is not found.
352  */
353  std::optional< std::reference_wrapper<Attribute> > getOptionalAttributeByName(const AttributeName& attributeName);
354 
355 
356 };
357 
358 /// @brief Allows printing of stringified XML object
359 std::ostream& operator<<(std::ostream& os, const XMLObject* obj);
360 /// @brief Allows printing of stringified XML object
361 std::ostream& operator<<(std::ostream& os, const XMLObject& obj);
362 
363 } // end namespace XML
364 
365 #endif // XML_H
A class representing a node in an XML-tree.
Definition: XMLObject.h:115
std::optional< std::reference_wrapper< T > > getOptionalChild()
Get an optional child of type T.
Definition: XMLObject.h:287
Attributes attributes
Definition: XMLObject.h:249
static XMLObject * createFromFile(const std::string &filename)
Create an XMLObject from an XML file.
Definition: XMLObject.cpp:80
std::vector< std::reference_wrapper< T > > find()
Find all descendants of type T.
Definition: XMLObject.h:222
static XMLObject * createFromString(const std::string &xmlString)
Create an XMLObject from a string representation of XML.
Definition: XMLObject.cpp:74
static XMLObject * createObject(const xercesc::DOMElement *element)
Definition: XMLObject.cpp:113
std::optional< std::reference_wrapper< Attribute > > getOptionalAttributeByName(const AttributeName &attributeName)
Get an optional attribute with the specified attribute name.
Definition: XMLObject.cpp:197
ElementName elementName
Definition: XMLObject.h:245
const ClassName className
Definition: XMLObject.h:243
friend XMLObject * createInstance(const Namespace &xmlns, const ClassName &className, const xercesc::DOMElement *element)
Template function used to store in factory.
Definition: XMLObject.h:84
const T * is() const
Definition: XMLObject.h:162
std::string format(std::string indentation="\t", unsigned int depth=0) const
Creates formated string representing the XMLObject including its children.
Definition: XMLObject.cpp:222
Children children
Child nodes of the XML element.
Definition: XMLObject.h:248
Namespace prefix
Definition: XMLObject.h:244
T & getRequiredChild()
Get a required child of type T.
Definition: XMLObject.h:272
XMLObject & getRequiredChildByName(const ElementName &elementName)
Get a required child with the specified element name.
Definition: XMLObject.cpp:159
const T * get() const
Attempt to cast the current instance to the specified type T.
Definition: XMLObject.h:184
T * is()
Returns a pointer of type T of the object.
Definition: XMLObject.h:158
TextContent textContent
Textual content of XML element without children.
Definition: XMLObject.h:247
std::string stringify() const
Convert the XMLObject and its children to a string representation.
Definition: XMLObject.cpp:207
std::vector< std::reference_wrapper< XMLObject > > getChildrenByName(const ElementName &elementName)
Get all children with the specified element name.
Definition: XMLObject.cpp:177
XMLObject(const Namespace &xmlns, const ClassName &className, const xercesc::DOMElement *element, const Attributes &defaultAttributes)
Definition: XMLObject.cpp:123
static XMLObject * createFromStream(std::istream &xmlStream)
Create an XMLObject from the input stream.
Definition: XMLObject.cpp:46
std::vector< std::reference_wrapper< const T > > find() const
Find all descendants of type T.
Definition: XMLObject.h:235
static const Attributes defaults
Attributes of the XML element.
Definition: XMLObject.h:250
std::optional< std::reference_wrapper< XMLObject > > getOptionalChildByName(const ElementName &elementName)
Get the optional child with the specified element name.
Definition: XMLObject.cpp:168
virtual ~XMLObject()
Definition: XMLObject.h:145
std::vector< std::reference_wrapper< T > > getChildren()
Get all children of type T.
Definition: XMLObject.h:301
T * get()
Attempt to cast the current instance to the specified type T.
Definition: XMLObject.h:171
Attribute & getRequiredAttributeByName(const AttributeName &attributeName)
Get a required attribute with the specified attribute name.
Definition: XMLObject.cpp:187
static Factory factory
Definition: XMLObject.h:155
Namespace xmlns
Definition: XMLObject.h:242
The XML namespace contains classes representing XML-nodes defined in given XML-schema(s).
Definition: XMLObject.cpp:8
std::string ElementName
Definition: XMLObject.h:22
std::string Namespace
Definition: XMLObject.h:24
std::ostream & operator<<(std::ostream &os, const XMLObject *obj)
Allows printing of stringified XML object.
Definition: XMLObject.cpp:249
std::vector< Attribute > Attributes
Definition: XMLObject.h:80
std::vector< std::unique_ptr< XMLObject > > Children
Definition: XMLObject.h:81
std::string ClassName
Definition: XMLObject.h:19
std::unordered_map< ElementName, XMLObject *(*)(const Namespace &xmlns, const ClassName &className, const xercesc::DOMElement *element)> Factory
Factory used to create instance depending on element name.
Definition: XMLObject.h:87
XMLObject * createInstance(const Namespace &xmlns, const ClassName &className, const xercesc::DOMElement *element)
Template function used to store in factory.
Definition: XMLObject.h:84
std::string AttributeName
Definition: XMLObject.h:25
std::string TextContent
Definition: XMLObject.h:23
A struct representing an attribute of an XML-node.
Definition: XMLObject.h:73
Namespace prefix
Definition: XMLObject.h:75
AttributeName name
Definition: XMLObject.h:76
Namespace xmlns
Definition: XMLObject.h:74
A struct representing the value of an XML-node attribute.
Definition: XMLObject.h:48
Value(const std::string &s)
Definition: XMLObject.h:59
Value(bool b)
Definition: XMLObject.h:60
Value(int i)
Definition: XMLObject.h:61
Value & operator=(double d)
Definition: XMLObject.h:58
Value & operator=(bool b)
Definition: XMLObject.h:56
Value & operator=(int i)
Definition: XMLObject.h:57
static std::string False
Definition: XMLObject.h:64
Value & operator=(const std::string &s)
Definition: XMLObject.h:55
static std::string True
Definition: XMLObject.h:63
std::string value
Definition: XMLObject.h:49
Value(double d)
Definition: XMLObject.h:62