PLCnext API Documentation  22.9.0.33
TicReader.hpp
1 //
3 // Copyright PHOENIX CONTACT Electronics GmbH
4 //
6 #pragma once
7 #include "Arp/System/Core/Arp.h"
8 #include "Arp/System/Commons/Diagnostics/Logging/Loggable.hxx"
9 #include "Arp/System/Commons/Xml/XmlReader.hpp"
10 #include "Arp/System/Commons/Exceptions/XmlException.hpp"
11 #include "Arp/System/Commons/Configuration/TicNodeType.hpp"
12 #include "Arp/System/Commons/Configuration/TicSerializationContext.hpp"
13 #include <map>
14 #include <sstream>
15 
16 namespace Arp { namespace System { namespace Commons { namespace Configuration
17 {
18 
20 using namespace Arp::System::Commons::Xml;
21 
22 class TicReader : private Loggable<TicReader>
23 {
24  friend class TicSerializationContext;
25 
26 private: // typedefs
27  typedef std::map<TicNodeType, String> TicNodeTypeNames;
28  typedef std::map<String, TicNodeType> TicNameNodeTypes;
29 
30 public: // typedefs
31  template<typename T>
32  using SectionReadCallback = void (T::*)(TicReader& reader, TicSerializationContext& context);
33 
34 public: // nested helper class
35  template<class T>
37  {
38  public: // Static fields
39  static SectionReadCallback<T> Null;
40  static SectionReadCallback<T> Empty;
41 
42  private:
43  void EmptySectionReadCallback(TicReader&, TicSerializationContext&) {}
44  };
45 
46 public: // construction/destruction
50  ~TicReader(void) = default;
51 
52 private: // construction/destruction
53  TicReader(const String& filename);
54  TicReader(const TicReader& arg) = delete;
55  TicReader& operator=(const TicReader& arg) = delete;
56 
57 public: // static operations
58  static TicReader Create(const String& filename);
59 
60 public: // setter/getter operations
61  XmlReader& GetXmlReader(void);
62 
63 public: // operations
64  // read unknown tick node and determine nodeType
65  void ReadStartTicNode(TicNodeType& nodeType);
66  bool TryReadStartTicNode(TicNodeType& nodeType);
67  void ReadEndTicNode(TicNodeType nodeType);
68  bool TryReadEndTicNode(TicNodeType nodeType);
69 
70  // Read <EL> or </EL> nodes
71  void ReadStartTicElementList(void);
72  bool TryReadStartTicElementList(void);
73  void ReadEndTicElementList(void);
74  bool TryReadEndTicElementList(void);
75 
76  // Read <AL> or </AL> nodes
77  void ReadStartTicAttributeList(void);
78  bool TryReadStartTicAttributeList(void);
79  void ReadEndTicAttributeList(void);
80  bool TryReadEndTicAttributeList(void);
81 
82  // Read TIC element <E> or </E> nodes
83  void ReadStartTicElement(String& readELementName);
84  bool TryReadStartTicElement(String& readELementName);
85  bool TryReadStartTicElement(const String& elementName, String& readELementName);
86  void ReadEndTicElement(void);
87  bool TryReadEndTicElement(void);
88 
89  // Read TIC attribute <A> or </A> nodes
90  void ReadStartTicAttribute(String& readAttributeName);
91  bool TryReadStartTicAttribute(String& readAttributeName);
92  bool TryReadStartTicAttribute(const String& attributeName, String& readAttributeName);
93  void ReadEndTicAttribute(void);
94  bool TryReadEndTicAttribute(void);
95 
96  // Read TIC attribute values <V>...</V>
97  void SkipTicAttributeValue(void);
98  template<class T>
99  T ReadTicAttributeValue(void);
100  template<class T>
101  bool TryReadTicAttributeValue(T& result);
102 
103  // Read TIC element content containing one <AL>..</AL> (optional) and one <EL>..</EL> section (optional).
104  template<class T>
105  void ReadTicElementContent(
106  TicSerializationContext& context,
107  T& configuration,
108  SectionReadCallback<T> attributesReadMethod,
109  SectionReadCallback<T> childElementsReadMethod = nullptr,
110  bool attributesAreOptional = false,
111  bool elementsAreOptional = false);
112 
113 private: // methods
114  bool TryReadStartTicElement(const String& elementName, String& readELementName, String& errorMessage);
115  bool TryReadStartTicAttribute(const String& attributeName, String& readAttributeName, String& errorMessage);
116  bool TryReadTicAttributeContent(String& result, String& errorMessage);
117  template<class T>
118  bool TryReadTicAttributeValue(T& result, String& errorMessage);
119  void SkipTicAttributeList(void);
120  void SkipTicElementList(void);
121 
122 private: // fields
123  XmlReader xmlReader;
124 
125 private: // static fields
126  static TicNodeTypeNames ticNodeTypeNames;
127  static TicNameNodeTypes ticNameNodeTypes;
128 
129 private: // static const fields
130  static const char* const ticElementNameAttributeName;
131  static const char* const ticAttributeNameAttributeName;
132 };
133 
135 // inline methods of class TicReader
136 
137 inline TicReader TicReader::Create(const String& filename)
138 {
139  return TicReader(filename);
140 }
141 
142 inline XmlReader& TicReader::GetXmlReader()
143 {
144  return this->xmlReader;
145 }
146 
147 inline bool TicReader::TryReadStartTicElementList()
148 {
149  TicNodeType nodeType = TicNodeType::None;
150  return this->TryReadStartTicNode(nodeType) && nodeType == TicNodeType::ElementList;
151 }
152 
153 inline void TicReader::ReadStartTicElementList()
154 {
155  if (!this->TryReadStartTicElementList())
156  {
157  throw XmlException("Invalid Tic file format: missing StartTicElementList tag '<{0}>'.", ticNodeTypeNames[TicNodeType::ElementList]);
158  }
159 }
160 
161 inline bool TicReader::TryReadEndTicElementList()
162 {
163  return this->TryReadEndTicNode(TicNodeType::ElementList);
164 }
165 
166 inline void TicReader::ReadEndTicElementList()
167 {
168  if (!this->TryReadEndTicElementList())
169  {
170  throw XmlException("Invalid Tic file format: missing EndTicElementList tag '</{0}>'.", ticNodeTypeNames[TicNodeType::ElementList]);
171  }
172 }
173 
174 inline bool TicReader::TryReadStartTicAttributeList()
175 {
176  TicNodeType nodeType = TicNodeType::None;
177  return this->TryReadStartTicNode(nodeType) && nodeType == TicNodeType::AttributeList;
178 }
179 
180 inline void TicReader::ReadStartTicAttributeList()
181 {
182  if (!this->TryReadStartTicAttributeList())
183  {
184  throw XmlException("Invalid Tic file format: missing StartTicAttributeList tag '<{0}>'.", ticNodeTypeNames[TicNodeType::AttributeList]);
185  }
186 }
187 
188 inline bool TicReader::TryReadEndTicAttributeList()
189 {
190  return this->TryReadEndTicNode(TicNodeType::AttributeList);
191 }
192 
193 inline void TicReader::ReadEndTicAttributeList()
194 {
195  if (!this->TryReadEndTicAttributeList())
196  {
197  throw XmlException("Invalid Tic file format: missing EndTicAttributeList tag '</{0}>'.", ticNodeTypeNames[TicNodeType::AttributeList]);
198  }
199 }
200 
201 inline void TicReader::ReadStartTicElement(String& readELementName)
202 {
203  String errorMessage;
204  if (!this->TryReadStartTicElement(String::Empty, readELementName, errorMessage))
205  {
206  throw XmlException(errorMessage);
207  }
208 }
209 
210 inline bool TicReader::TryReadStartTicElement(String& readELementName)
211 {
212  String errorMessage;
213  return this->TryReadStartTicElement(String::Empty, readELementName, errorMessage);
214 }
215 
216 inline bool TicReader::TryReadStartTicElement(const String& elementName, String& readELementName)
217 {
218  String errorMessage;
219  return this->TryReadStartTicElement(elementName, readELementName, errorMessage);
220 }
221 
222 inline void TicReader::ReadEndTicElement()
223 {
224  if (!this->TryReadEndTicElement())
225  {
226  throw XmlException("Invalid Tic file format: missing EndTicElement tag '</{0}>'.", ticNodeTypeNames[TicNodeType::Element]);
227  }
228 }
229 
230 inline bool TicReader::TryReadEndTicElement()
231 {
232  return this->TryReadEndTicNode(TicNodeType::Element);
233 }
234 
235 inline void TicReader::ReadStartTicAttribute(String& readAttributeName)
236 {
237  String errorMessage;
238  if (!this->TryReadStartTicAttribute(String::Empty, readAttributeName, errorMessage))
239  {
240  throw XmlException(errorMessage);
241  }
242 }
243 
244 inline bool TicReader::TryReadStartTicAttribute(String& readAttributeName)
245 {
246  String errorMessage;
247  return this->TryReadStartTicAttribute(String::Empty, readAttributeName, errorMessage);
248 }
249 
250 inline bool TicReader::TryReadStartTicAttribute(const String& attributeName, String& readAttributeName)
251 {
252  String errorMessage;
253  return this->TryReadStartTicAttribute(attributeName, readAttributeName, errorMessage);
254 }
255 
256 inline void TicReader::ReadEndTicAttribute(void)
257 {
258  if (!this->TryReadEndTicAttribute())
259  {
260  throw XmlException("Invalid Tic file format: missing EndTicAttribute tag '</{0}>'.", ticNodeTypeNames[TicNodeType::Attribute]);
261  }
262 }
263 
264 inline bool TicReader::TryReadEndTicAttribute()
265 {
266  return this->TryReadEndTicNode(TicNodeType::Attribute);
267 }
268 
269 inline void TicReader::SkipTicAttributeValue()
270 {
271  (void) this->ReadTicAttributeValue<String>();
272 }
273 
274 template<class T>
275 inline T TicReader::ReadTicAttributeValue()
276 {
277  T result;
278  String errorMessage;
279  if (!this->TryReadTicAttributeValue<T>(result, errorMessage))
280  {
281  throw XmlException(errorMessage);
282  }
283  return result;
284 }
285 
286 template<class T>
287 inline bool TicReader::TryReadTicAttributeValue(T& result)
288 {
289  String errorMessage;
290  return this->TryReadTicAttributeValue<T>(result, errorMessage);
291 }
292 
293 template<class T>
294 inline bool TicReader::TryReadTicAttributeValue(T& result, String& errorMessage)
295 {
296  String attributeValue;
297  if (!this->TryReadTicAttributeContent(attributeValue, errorMessage))
298  {
299  return false;
300  }
301  // else convert
302  std::stringstream iss(attributeValue);
303  iss >> std::boolalpha >> result;
304  return !iss.fail();
305 }
306 template<>
307 inline bool TicReader::TryReadTicAttributeValue(String& result, String& errorMessage)
308 {
309  String attributeValue;
310  if (!this->TryReadTicAttributeContent(result, errorMessage))
311  {
312  return false;
313  }
314  return true;
315  // else convert
316  /*std::stringstream iss(attributeValue);
317  iss >> boolalpha >> result;
318  return !iss.fail();*/
319 }
320 
321 template<class T>
322 inline void TicReader::ReadTicElementContent(
323  TicSerializationContext& context,
324  T& configuration,
325  SectionReadCallback<T> attributesReader,
326  SectionReadCallback<T> childElementsReader,
327  bool attributesAreOptional,
328  bool elementsAreOptional)
329 {
330  bool hasAttributesRead = false;
331  bool hasChildElementsRead = false;
332 
333  while (!(hasAttributesRead && hasChildElementsRead))
334  {
335  TicNodeType nodeType = TicNodeType::None;
336  if (this->TryReadStartTicNode(nodeType))
337  {
338  bool mustReadEndTicNode = true;
339  switch (nodeType)
340  {
341  case TicNodeType::AttributeList:
342  if (attributesReader == nullptr)
343  {
344  this->SkipTicAttributeList();
345  }
346  else
347  {
348  (configuration.*attributesReader)(*this, context);
349  }
350  hasAttributesRead = true;
351  break;
352  case TicNodeType::ElementList:
353  if (childElementsReader == nullptr)
354  {
355  this->SkipTicElementList();
356  mustReadEndTicNode = false; // xmlReader.Skip() reads also EndElement of current node
357  }
358  else
359  {
360  (configuration.*childElementsReader)(*this, context);
361  }
362  hasChildElementsRead = true;
363  break;
364  default:
365  throw XmlException("Invalid TIC file format: expecting attribute or element list");
366  break;
367  }
368  if(mustReadEndTicNode)
369  {
370  this->ReadEndTicNode(nodeType);
371  }
372  }
373  else // a further start tic node could not be read
374  {
375  if (!hasAttributesRead && !attributesAreOptional)
376  {
377  throw XmlException("Invalid TIC file format: expecting attribute list");
378  }
379  else if (attributesReader == nullptr && attributesAreOptional)
380  {
381  hasAttributesRead = true;
382  }
383 
384  if (!hasChildElementsRead && !elementsAreOptional)
385  {
386  throw XmlException("Invalid TIC file format: expecting element list");
387  }
388  else if (elementsAreOptional)
389  {
390  hasChildElementsRead = true;
391  }
392  }
393  }
394 }
395 
397 // initializing of static fields of class TicReader::SectionReadCallbacks
398 template<class T>
399 TicReader::SectionReadCallback<T> TicReader::SectionReadCallbacks<T>::Null = nullptr;
400 template<class T>
402 
403 }}}} // end of namespace Arp::System::Commons::Configuration
~TicReader(void)=default
Destructs this instance and frees all resources.
TicReader(TicReader &&arg)
Move contructor.
Definition: TicSerializationContext.hpp:19
This exception is used for xml parsing errors.
Definition: XmlException.hpp:15
Class to read an XML File. Non buffered reader, can only read forward
Definition: XmlReader.hpp:25
static const SelfType Empty
An emtpy static string instance.
Definition: BasicString.hxx:214
Arp::BasicString< char8 > String
The Arp String class.
Definition: TypeSystem.h:27
@ System
System components used by the System, Device, Plc or Io domains.
Namespace for logging classes
Definition: LoggingForwards.h:10
Namespace for classes to read XML files
Definition: ConfigHeader.hpp:12
Root namespace for the PLCnext API