PLCnext API Documentation 23.6.0.37
TicReader.hpp
1
2//
3// Copyright PHOENIX CONTACT Electronics GmbH
4//
6#pragma once
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
16namespace Arp { namespace System { namespace Commons { namespace Configuration
17{
18
20using namespace Arp::System::Commons::Xml;
21
22class TicReader : private Loggable<TicReader>
23{
24 friend class TicSerializationContext;
25
26private: // typedefs
27 typedef std::map<TicNodeType, String> TicNodeTypeNames;
28 typedef std::map<String, TicNodeType> TicNameNodeTypes;
29
30public: // typedefs
31 template<typename T>
32 using SectionReadCallback = void (T::*)(TicReader& reader, TicSerializationContext& context);
33
34public: // 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
46public: // construction/destruction
50 ~TicReader(void) = default;
51
52private: // construction/destruction
53 TicReader(const String& filename);
54 TicReader(const TicReader& arg) = delete;
55 TicReader& operator=(const TicReader& arg) = delete;
56
57public: // static operations
58 static TicReader Create(const String& filename);
59
60public: // setter/getter operations
61 XmlReader& GetXmlReader(void);
62
63public: // 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(
107 T& configuration,
108 SectionReadCallback<T> attributesReadMethod,
109 SectionReadCallback<T> childElementsReadMethod = nullptr,
110 bool attributesAreOptional = false,
111 bool elementsAreOptional = false);
112
113private: // 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
122private: // fields
123 XmlReader xmlReader;
124
125private: // static fields
126 static TicNodeTypeNames ticNodeTypeNames;
127 static TicNameNodeTypes ticNameNodeTypes;
128
129private: // static const fields
130 static const char* const ticElementNameAttributeName;
131 static const char* const ticAttributeNameAttributeName;
132};
133
135// inline methods of class TicReader
136
137inline TicReader TicReader::Create(const String& filename)
138{
139 return TicReader(filename);
140}
141
142inline XmlReader& TicReader::GetXmlReader()
143{
144 return this->xmlReader;
145}
146
147inline bool TicReader::TryReadStartTicElementList()
148{
149 TicNodeType nodeType = TicNodeType::None;
150 return this->TryReadStartTicNode(nodeType) && nodeType == TicNodeType::ElementList;
151}
152
153inline 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
161inline bool TicReader::TryReadEndTicElementList()
162{
163 return this->TryReadEndTicNode(TicNodeType::ElementList);
164}
165
166inline 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
174inline bool TicReader::TryReadStartTicAttributeList()
175{
176 TicNodeType nodeType = TicNodeType::None;
177 return this->TryReadStartTicNode(nodeType) && nodeType == TicNodeType::AttributeList;
178}
179
180inline 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
188inline bool TicReader::TryReadEndTicAttributeList()
189{
190 return this->TryReadEndTicNode(TicNodeType::AttributeList);
191}
192
193inline 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
201inline 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
210inline bool TicReader::TryReadStartTicElement(String& readELementName)
211{
212 String errorMessage;
213 return this->TryReadStartTicElement(String::Empty, readELementName, errorMessage);
214}
215
216inline bool TicReader::TryReadStartTicElement(const String& elementName, String& readELementName)
217{
218 String errorMessage;
219 return this->TryReadStartTicElement(elementName, readELementName, errorMessage);
220}
221
222inline 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
230inline bool TicReader::TryReadEndTicElement()
231{
232 return this->TryReadEndTicNode(TicNodeType::Element);
233}
234
235inline 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
244inline bool TicReader::TryReadStartTicAttribute(String& readAttributeName)
245{
246 String errorMessage;
247 return this->TryReadStartTicAttribute(String::Empty, readAttributeName, errorMessage);
248}
249
250inline bool TicReader::TryReadStartTicAttribute(const String& attributeName, String& readAttributeName)
251{
252 String errorMessage;
253 return this->TryReadStartTicAttribute(attributeName, readAttributeName, errorMessage);
254}
255
256inline 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
264inline bool TicReader::TryReadEndTicAttribute()
265{
266 return this->TryReadEndTicNode(TicNodeType::Attribute);
267}
268
269inline void TicReader::SkipTicAttributeValue()
270{
271 (void) this->ReadTicAttributeValue<String>();
272}
273
274template<class T>
275inline 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
286template<class T>
287inline bool TicReader::TryReadTicAttributeValue(T& result)
288{
289 String errorMessage;
290 return this->TryReadTicAttributeValue<T>(result, errorMessage);
291}
292
293template<class T>
294inline 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}
306template<>
307inline 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
321template<class T>
322inline void TicReader::ReadTicElementContent(
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
398template<class T>
399TicReader::SectionReadCallback<T> TicReader::SectionReadCallbacks<T>::Null = nullptr;
400template<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:224
@ System
System components used by the System, Device, Plc or Io domains.
Namespace for logging classes
Definition: LogAdapter.hpp:20
Namespace for classes to read XML files
Definition: ConfigHeader.hpp:12
Root namespace for the PLCnext API