File: xml.h

package info (click to toggle)
groops 0%2Bgit20250907%2Bds-1
  • links: PTS, VCS
  • area: non-free
  • in suites: forky, sid
  • size: 11,140 kB
  • sloc: cpp: 135,607; fortran: 1,603; makefile: 20
file content (458 lines) | stat: -rw-r--r-- 13,138 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
/***********************************************/
/**
* @file xml.h
*
* @brief Nodes of a XML tree.
*
* @author Torsten Mayer-Guerr
* @author Sebastian Strasser
* @date 2004-11-14
*
*/
/***********************************************/

#ifndef __GROOPS_XML__
#define __GROOPS_XML__

#include "base/importStd.h"
#include "base/angle.h"
#include "base/time.h"

/** @addtogroup parserGroup */
/// @{

/***** TYPES ***********************************/

class   XmlAttribute;
class   XmlNode;
typedef std::shared_ptr<XmlNode>      XmlNodePtr;
typedef std::shared_ptr<XmlAttribute> XmlAttrPtr;

/***** CLASS ***********************************/

/** @brief Attribute of a XML-node.
* @ingroup parserGroup
* @see XmlNode */
class XmlAttribute
{
public:
  /// Name of Attribute.
  std::string name;

  /// Content of Attribute.
  std::string text;

  /// Name of Attribute.
  const std::string &getName() const {return name;}

  /// Content of Attribute.
  const std::string &getText() const {return text;}

  /** @brief Interpret content as type of @a var.
  * @param[out] var is filled with the content of attribute. */
  template<typename T> void getValue(T &var) const;

  /** @brief Set content of attribute. */
  template<typename T> void setValue(const T &var);
};

/***** CLASS ***********************************/

/** @brief Node of a XML-tree.
* @ingroup parserGroup
* For simple XML files. This means only on block of text is allowed for each node.
*
* Der Baum wird beim auslesen direkt abgebaut,
* so dass nur einmal auslesen moeglich ist.
* Der Speicher wird mit std::shared_ptr verwaltet,
* so dass man keinen Speicher freigeben muss. */
class XmlNode
{
  std::string           name_;
  std::string           text_;
  std::list<XmlNodePtr> children;
  std::list<XmlAttrPtr> attribute;

  void write(std::ostream &stream, UInt depth=0);

public:
  /// Constructor.
  explicit XmlNode(const std::string &name) : name_(name) {}

  XmlNode(const XmlNode &node) = delete;
  XmlNode &operator=(const XmlNode &node) = delete;

  /** @brief Deep copy.
  * Creates a copy of the node and of all children. */
  XmlNodePtr clone() const;

  /** @brief Name of the node. */
  const std::string &getName() const {return name_;}

  /** @brief Set name of the node. */
  void setName(const std::string &name) {name_ = name;}

  /** @brief Content of the node. */
  const std::string &getText() const {return text_;}

  /** @brief Set content of the node. */
  void setText(const std::string &text) {text_ = text;}

  /** @brief Append @a text to the content of the node. */
  void addText(const std::string &text) {text_ += text;}

  /** @brief Interpret content as type of @a var.
  * @param[out] var is filled with the content of node. */
  template<typename T> void getValue(T &var) const;

  /** @brief Set content of node. */
  template<typename T> void setValue(const T &var);

  /** @brief Has the node children nodes? */
  Bool hasChildren() const {return !children.empty();}

  std::list<XmlNodePtr> &getChildren() {return children;}

  /** @brief Number of children with @a name. */
  UInt getChildCount(const std::string &name);

  /** @brief Returns the the first child with @a name.
  * The child is removed from tree. If child does not exist, a NULL pointer is returned. */
  XmlNodePtr getChild(const std::string &name);

  /** @brief Returns the the first child with @a name.
  * The child is NOT removed from tree. If child does not exist, a NULL pointer is returned. */
  XmlNodePtr findChild(const std::string &name);

  /** @brief Append a new child.
  * It is not allowed to have the same node multiple times in the tree.
  * (Create a copy with @a clone() before). */
  void addChild(const XmlNodePtr &child) {children.push_back(child);}

  /** @brief Insert a new child at begin.
  * It is not allowed to have the same node multiple times in the tree.
  * (Create a copy with @a clone() before). */
  void prependChild(const XmlNodePtr &child) {children.push_front(child);}

  /** @brief Returns the next child.
  * The child is removed from tree. If child not exists, a NULL pointer is returned. */
  XmlNodePtr getNextChild();

  /** @brief Returns the next child.
  * The child is NOT removed from tree. If child not exists, a NULL pointer is returned. */
  XmlNodePtr findNextChild();

  /** @brief Has the node attributes? */
  Bool hasAttribute() const {return !attribute.empty();}

  /** @brief Returns the the first attribute with @a name.
  * The attribute is removed from the node. If attribute does not exist, a NULL pointer is returned. */
  XmlAttrPtr getAttribute(const std::string &name);

  /** @brief Returns the the first attribute with @a name.
  * The attribute is NOT removed from the node. If attribute does not exist, a NULL pointer is returned. */
  XmlAttrPtr findAttribute(const std::string &name);

  /** @brief Append a new attribute.
  * It is not allowed to have the same attribute multiple times in the tree. */
  void addAttribute(const XmlAttrPtr &attr) {attribute.push_back(attr);}

  /** @brief Returns the next attribute.
  * The attribute is removed from the node. If attribute does not exist, a NULL pointer is returned. */
  XmlAttrPtr getNextAttribute();

  /** @brief XmlNode factory. */
  static XmlNodePtr create(const std::string &name);

  /** @brief Read XML tree from stream.
  * @param stream Input stream.
  * @return Root node of the XML tree. */
  static XmlNodePtr read(std::istream &stream);

  /** @brief Write XML tree to stream.
  * @param stream output stream.
  * @param root Root node of the XML tree. */
  static void write(std::ostream &stream, const XmlNodePtr &root);

  /** @brief Replace characters with entity references
  * @param in string to be parsed
  * @return out string with character entitiy references
  */
  static std::string sanitizeXML(const std::string& in);
};


/***** FUNCTIONS ***********************************/

/** @brief Anzahl der Kinder mit Namen @a name.
* If @a mustSet==TRUE, an Exception is thrown.
* @relates XmlNode */
UInt childCount(const XmlNodePtr &parent, const std::string &name, Bool mustGreaterZero=FALSE);

/** @brief Returns the next child.
* In @a name the name of the child is returned.
* If child not exists, a NULL pointer is returned.
* @relates XmlNode */
XmlNodePtr getNextChild(const XmlNodePtr &parent, std::string &name);

/** @brief Returns the the first child with @a name.
* The child is removed from tree. If child not exists and @a mustSet==TRUE,
* an Exception is thrown otherwise a NULL pointer is returned.
* @relates XmlNode */
XmlNodePtr getChild(const XmlNodePtr &parent, const std::string &name, Bool mustSet=FALSE);

/** @brief Reads a variable from XML.
* Locking for child with @a name and interpret the content as type of @a var.
* The child is removed from tree. If child not exists the @a var is untouched
* and if additionally @a mustSet==TRUE, an Exception is thrown.
* @relates XmlNode */
template<class T>
XmlNodePtr readXml(const XmlNodePtr &parent, const std::string &name, T &var, Bool mustSet=FALSE);

/** @brief Write a variable to a XML tree.
* A XML child with @a name is created and is appended to @a parent.
* The value of @a var is written as content of the child.
* @relates XmlNode */
template<class T>
XmlNodePtr writeXml(const XmlNodePtr &parent, const std::string &name, const T &var);

/** @brief Reads a variable from XmlAttribute.
* Locking for a attribute with @a name and interpret the content as type of @a var.
* The attribute is removed from node. If attribute not exists the @a var is untouched
* and if additionally @a mustSet==TRUE, an Exception is thrown.
* @relates XmlNode */
template<class T>
XmlAttrPtr readAttribute(const XmlNodePtr &node, const std::string &name, T &var, Bool mustSet=FALSE);

/** @brief Write a variable as attribute to a XML node.
* A XmlAttribute with @a name is created and is appended to @a node.
* The value of @a var is written as content of the attribute.
* @relates XmlNode */
template<class T>
XmlAttrPtr writeAttribute(const XmlNodePtr &node, const std::string &name, const T &var);

/** @brief XmlNode factory.
* A XML child with @a name is created and is appended to @a parent.
* @relates XmlNode */
XmlNodePtr createXmlNode(const XmlNodePtr &parent, const std::string &name);

/// @}

/***********************************************/
/***** INLINES *********************************/
/***********************************************/

template<typename T> void XmlAttribute::getValue(T &var) const
{
  try
  {
    std::stringstream ss(text);
    ss>>var;
    if(!(ss.good()||ss.eof()))
      throw Exception("stream error");
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

template<> inline void XmlAttribute::getValue(std::string &var) const // Spezialization
{
  var = text;
}

/***********************************************/

inline XmlNodePtr XmlNode::create(const std::string &name)
{
  return XmlNodePtr(new XmlNode(name));
}

/***********************************************/

template<typename T> void XmlAttribute::setValue(const T &var)
{
  try
  {
    std::stringstream ss;
    ss.setf(std::ios::scientific,std::ios::floatfield);
    ss.precision(18);
    ss<<var; ss>>text;
    if(!(ss.good()||ss.eof()))
      throw Exception("stream error");
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

template<> inline void XmlAttribute::setValue(const std::string &var) // Spezialization
{
  text = var;
}

/***********************************************/

template<typename T> void XmlNode::getValue(T &var) const
{
  try
  {
    std::stringstream ss(text_);
    ss>>var;
    if(!(ss.good()||ss.eof()))
      throw Exception("stream error");
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

template<> inline void XmlNode::getValue(Double &var) const // Spezialization
{
  try
  {
    var = std::stod(text_);
  }
  catch(std::invalid_argument &)
  {
    throw(Exception("cannot read number: "+text_));
  }
}

template<> inline void XmlNode::getValue(Time &var) const // Spezialization
{
  Double mjd;
  getValue(mjd);
  var = mjd2time(mjd);
}

template<> inline void XmlNode::getValue(Angle &var) const // Spezialization
{
  Double x;
  getValue(x);
  var = Angle(x*DEG2RAD);
}

template<> inline void XmlNode::getValue(std::string &var) const
{
  var = getText();
}

/***********************************************/

template<typename T> void XmlNode::setValue(const T &var)
{
  try
  {
    std::stringstream ss;
    ss.setf(std::ios::scientific,std::ios::floatfield);
    ss.precision(18);
    ss<<var; ss>>text_;
    if(!(ss.good()||ss.eof()))
      throw Exception("stream error");
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

template<> inline void XmlNode::setValue(const Time  &var) // Spezialization
{
  setValue(var.mjd());
}

template<> inline void XmlNode::setValue(const Angle &var) // Spezialization
{
  setValue(static_cast<Double>(var*RAD2DEG));
}

template<> inline void XmlNode::setValue(const std::string &var) // Spezialization
{
  text_ = var;
}

/***********************************************/

template<class T> inline XmlNodePtr readXml(const XmlNodePtr &parent, const std::string &name, T &var, Bool mustSet)
{
  XmlNodePtr child = getChild(parent, name, mustSet);
  if(child!=nullptr)
    child->getValue(var);
  return child;
}

/***********************************************/

template<class T> inline XmlNodePtr writeXml(const XmlNodePtr &parent, const std::string &name, const T &var)
{
  XmlNodePtr child = createXmlNode(parent, name);
  child->setValue(var);
  return child;
}

/***********************************************/

inline XmlNodePtr getChild(const XmlNodePtr &parent, const std::string &name, Bool mustSet)
{
  try
  {
    XmlNodePtr child = parent->getChild(name);
    if((child==nullptr) && mustSet)
      throw(Exception("'"+parent->getName()+"' must contain '"+name+"'"));
    return child;
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

/***********************************************/

inline XmlNodePtr createXmlNode(const XmlNodePtr &parent, const std::string &name)
{
  XmlNodePtr child = XmlNode::create(name);
  parent->addChild(child);
  return child;
}

/***********************************************/

template<class T>
inline XmlAttrPtr readAttribute(const XmlNodePtr &node, const std::string &name, T &var, Bool mustSet)
{
  try
  {
    XmlAttrPtr attr = node->getAttribute(name);
    if((attr==nullptr) && mustSet)
      throw(Exception("'"+node->getName()+"' muss contain '"+name+"'"));
    if(attr!=nullptr)
      attr->getValue(var);
    return attr;
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

/***********************************************/

template<class T>
inline XmlAttrPtr writeAttribute(const XmlNodePtr &node, const std::string &name, const T &var)
{
  XmlAttrPtr attr = XmlAttrPtr(new XmlAttribute());
  attr->name = name;
  attr->setValue(var);
  node->addAttribute(attr);
  return attr;
}

/***********************************************/
/***********************************************/

#endif /* __GROOPS_XML__ */