PLCnext API Documentation  21.0.0.35466
XmlReader.hpp
1 //
3 // Copyright PHOENIX CONTACT Electronics GmbH
4 //
6 #pragma once
7 #include "Arp/System/Core/Arp.h"
8 #include "Arp/System/Core/Enum.hxx"
9 #include "Arp/System/Core/TypeName.hxx"
10 #include "Arp/System/Commons/Chrono/Duration.hpp"
11 #include "Arp/System/Commons/Exceptions/Exceptions.h"
12 #include "Arp/System/Commons/Xml/XmlErrorHandler.hpp"
13 #include "Arp/System/Commons/Xml/XmlNodeType.hpp"
14 
15 #include <sstream>
16 #include "boost/lexical_cast.hpp"
17 
18 namespace Arp { namespace System { namespace Commons { namespace Xml
19 {
20 
22 class XmlReader
23 {
24 public: // typedefs
25 public: // construction/destruction
27  XmlReader(void);
29  XmlReader(XmlReader&& arg);
31  ~XmlReader(void);
32 
33 private: // construction/destruction
34  XmlReader(void* pReader);
35  XmlReader(const XmlReader& arg) = delete;
36  XmlReader& operator=(const XmlReader& arg) = delete;
37 
38 public: // static factory operations
45  static XmlReader Create(const String& filename);
46 
53  static bool TryCreate(const String& filename, XmlReader& reader);
54 
68  static XmlReader Create(const String& filename, const String& xsdFile);
69 
70 
78  static XmlReader CreateForString(const String& buffer);
79 
80 public: // setter/getter operations
88 
95  long GetLineNumber();
96 
103  const String& GetDocumentFileName();
104 
105 public: // operations
112  bool Read();
113 
120  XmlNodeType GetCurrentNodeType();
127  bool IsEmptyElement();
128 
135  int GetCurrentDepth();
143  bool Skip(); // TODO: remove this due to unclear naming
150  bool SkipElement();
151 
159  bool SkipElementContent();
160 
161  // moves to the element that contains the current attribute
162 
170  bool MoveToElement();
171  // moves to the next element with name
172 
182  bool ReadToFollowing(const String& name);
183  // reads to the next element with name included in current element
184 
196  bool ReadToDescendant(const String& name);
197  // skips the current element and reads until the next sibling with name
198 
209  bool ReadToNextSibling(const String& name);
210 
211  // reads to the next start element and tests the name against name, not needed after
212  // ReadEndElement
213 
221  void ReadStartElement(const char* elementName = nullptr);
222 
233  bool TryReadStartElement(const char* elementName = nullptr);
243  bool TryReadStartElement(String& elementName, bool conditioned = true);
244 
249  void ReadEndElement(void);
257  bool TryReadEndElement(void);
266  // reads the content as CData section of the current element
267  // read CDATA is not required, ReadElementContent removes CDATA Tags automatically
268  // String ReadElementContentCData(void);
269  // bool TryReadElementContentCData(String& result);
270 
278  template<class T>
280  {
281  return boost::lexical_cast<T>(ReadElementContent());
282  }
283 
295  template<class T>
296  T GetAttributeValue(const char* attributeName)
297  {
298  T returnValue;
299  if (TryGetAttributeValue<T>(attributeName, returnValue))
300  {
301  return returnValue;
302  }
303  else
304  {
305  throw XmlException(
306  "GetAttributeValue failed for mandatory attribute: {0} elementName: {1}",
307  attributeName, GetElementLocalName());
308  }
309  }
310 
322  template<class T>
323  Enum<T> GetAttributeValueEnum(const char* attributeName)
324  {
325  Enum<T> returnValue;
326 
327  if (TryGetAttributeValueEnum<T>(attributeName, returnValue))
328  {
329  return returnValue;
330  }
331  else
332  {
333  throw XmlException(
334  "GetAttributeValueEnum failed for mandatory attribute: {0} elementName: {1}",
335  attributeName, GetElementLocalName());
336  }
337  }
338 
353  template<class T>
354  bool TryGetAttributeValueEnum(const char* attributeName, Enum<T>& value)
355  {
356  char* charValue = GetAttributeValueInternal(attributeName);
357  if (charValue == nullptr)
358  {
359  return false;
360  }
361 
362  value = Enum<T>::Parse(charValue);
363  FreeInternalAttributeValue(charValue);
364  return true;
365  }
366 
384  template<class T>
385  bool TryGetAttributeValueEnum(const char* attributeName, T defaultValue, Enum<T>& value)
386  {
387  value = defaultValue;
388  return TryGetAttributeValueEnum<T>(attributeName, value);
389  }
390 
391 
404  template<class T>
405  T GetAttributeValueDuration(const char* attributeName)
406  {
407  T returnValue;
408 
409  if (TryGetAttributeValueDuration<T>(attributeName, returnValue))
410  {
411  return returnValue;
412  }
413  else
414  {
415  throw XmlException(
416  "GetAttributeValueDuration failed for mandatory attribute: {0} elementName: {1}",
417  attributeName, GetElementLocalName());
418  }
419  }
433  template<class T>
434  bool TryGetAttributeValueDuration(const char* attributeName, T& value)
435  {
436  char* charValue = GetAttributeValueInternal(attributeName);
437  Chrono::Duration tempDurationValue;
438 
439  if (charValue == nullptr)
440  {
441  return false;
442  }
443 
444  bool result = Chrono::Duration::TryParse(charValue, tempDurationValue);
445  tempDurationValue.GetDuration(value);
446 
447  FreeInternalAttributeValue(charValue);
448  return result;
449  }
450 
468  template<class T>
469  bool TryGetAttributeValueDuration(const char* attributeName, T defaultValue, T& value)
470  {
471  value = defaultValue;
472  return TryGetAttributeValueDuration<T>(attributeName, value);
473  }
474 
475 
489  template<class T>
490  bool TryGetAttributeValue(const char* attributeName, T& value)
491  {
492  char* charValue = nullptr;
493  try
494  {
495  charValue = GetAttributeValueInternal(attributeName);
496  if (charValue == nullptr)
497  {
498  return false;
499  }
500 
501  // boost::lexical_cast seems fast enough:
502  // http://stackoverflow.com/questions/23582089/is-boostlexical-cast-redundant-with-c11-stoi-stof-and-family
503  // boost::lexical_cast is 10 times slower than atoi on Linux but has more error checks
504  // http://tinodidriksen.com/2010/02/16/cpp-convert-string-to-int-speed/
505  value = boost::lexical_cast<T>(charValue);
506  FreeInternalAttributeValue(charValue);
507  return true;
508  }
509  catch (boost::bad_lexical_cast&)
510  {
511 
512  String strValue(charValue);
513  FreeInternalAttributeValue(charValue);
514  throw XmlException("Cast of attribute {0} to {1} failed value: {2}", attributeName,
515  TypeName<T>(), strValue);
516  }
517  }
518 
519 
537  template<class T>
538  bool TryGetAttributeValue(const char* attributeName, T defaultValue, T& value)
539  {
540 
541  value = defaultValue;
542  return TryGetAttributeValue<T>(attributeName, value);
543  }
544 
545  void EnableValidationException();
546  void DisableValidationException();
547 
557  template<typename... Args>
558  XmlException CreateException(const char* message, const Args& ... args);
559 
560 protected: // operations
561 private: // static methods
562 private: // methods
563  int ReaderState();
564  char* GetAttributeValueInternal(const char* attributeName);
565  void FreeInternalAttributeValue(char* attributeValue);
566  // Move to the content node, if the element is not an content node
567  // content nodes are: non-whitespace text, CDATA, Element, EndElement, EntityReference,
568  // EndEntity
569  XmlNodeType MoveToContent();
570  void EnableValidation(const String& xsdFile);
571  void CheckForValidationException();
572 
573 private: // fields
574  String filename;
575  // internal reader ptr
576  void* reader;
577  bool validationEnabled;
578  XmlErrorHandler* errorHandler;
579  bool exceptionOnValidationError; // defines whether to throw an exception when a validation
580  // error occurs while parsing
581  String lastError;
582  bool startElementRead;
583 
584 private: // static fields
585 };
586 
587 // gcc does not allow full template specialization in class definition
588 // boost::lexical_cast does not understand true and false so implement special version
589 template<>
590 bool XmlReader::TryGetAttributeValue(const char*, bool& value);
591 
592 template<>
593 bool XmlReader::TryGetAttributeValue(const char* attributeName, String& value);
594 
595 template<>
596 bool XmlReader::TryGetAttributeValue(const char* attributeName, Chrono::Duration& value);
597 
598 template<>
599 bool XmlReader::TryGetAttributeValue(const char* attributeName, uint8& value);
600 
601 template<>
602 bool XmlReader::TryGetAttributeValue(const char* attributeName, int8& value);
603 
605 // inline methods of class XmlReader
606 template<typename... Args>
607 inline XmlException XmlReader::CreateException(const char* message, const Args& ... args)
608 {
609  return XmlException::Create(this->filename, this->GetLineNumber(), message, args...);
610 }
611 
613 {
614  return this->filename;
615 }
616 
617 }}}} // namespace Arp::System::Commons::Xml
bool TryGetAttributeValueEnum(const char *attributeName, Enum< T > &value)
trys reads an attribute value from the current element and converts the String to Enum<T> ...
Definition: XmlReader.hpp:354
T ReadElementContent()
reads the content of the current element if a CDATA section is found, the CDATA enclosure is removed ...
Definition: XmlReader.hpp:279
bool MoveToElement()
Moves the position of the current instance to the node that contains the current Attribute node...
XmlException CreateException(const char *message, const Args &... args)
Creates an exception by prefixing the given message with current doc name and line number ...
Definition: XmlReader.hpp:607
This (meta programming) class provides the C++ typename of the as template argument passed type...
Definition: TypeName.hxx:55
bool TryReadEndElement(void)
tries to read until the next end element is reached skips over an empty element
bool Read()
Reads to the next element inside the xml file
bool TryReadStartElement(const char *elementName=nullptr)
trys to read the next element and test if this is a start element with the given name ...
static Enum Parse(const char *input)
Parses the given input string.
Definition: Enum.hxx:190
bool ReadToDescendant(const String &name)
reads the xml file until an element with name is reached or the current element is closed reads to th...
T GetAttributeValueDuration(const char *attributeName)
reads an attribute value from the current element and converts the String to std::chrono::duration i...
Definition: XmlReader.hpp:405
const String & GetDocumentFileName()
Gets the current document filename of this XML reader
Definition: XmlReader.hpp:612
bool TryGetAttributeValue(const char *attributeName, T &value)
tries to read an attribute value from the current element
Definition: XmlReader.hpp:490
static XmlReader Create(const String &filename)
Creates a new Instance of the XmlReader
long GetLineNumber()
Gets the actual line number of this XML reader
bool TryGetAttributeValue(const char *attributeName, T defaultValue, T &value)
tries to read an attribute value from the current element if the attribute was not found or the conve...
Definition: XmlReader.hpp:538
Adapter class for enums to make them loggable and parsable from e.g. XML files.
Definition: Enum.hxx:23
internal base class to handle xml parsing errors in XmlReader
Definition: XmlErrorHandler.hpp:14
~XmlReader(void)
Destructs this instance and frees all resources.
static XmlException Create(void)
Creates an XmlException instance using a default message text.
Definition: XmlException.hpp:79
static bool TryCreate(const String &filename, XmlReader &reader)
Tries to creates a new Instance of the XmlReader
static XmlReader CreateForString(const String &buffer)
Creates a new Instance of the XmlReader reading from an in memory buffer
Definition: Duration.hpp:17
String ReadElementContent(void)
reads the content of the current element if a CDATA section is found, the CDATA enclosure is removed ...
bool IsEmptyElement()
test if the current element is an empty element
bool SkipElement()
skips the current element with its whole subtree
T GetAttributeValue(const char *attributeName)
reads an attribute value from the current element
Definition: XmlReader.hpp:296
void ReadEndElement(void)
reads until the next end element is reached skips over an empty element
bool Skip()
skips the current element with its whole subtree (use SkipElement() because naming is more clear) ...
std::uint8_t uint8
The Arp unsigned integer type of 1 byte size.
Definition: PrimitiveTypes.hpp:27
Root namespace for the PLCnext API
This exception is used for xml parsing errors.
Definition: XmlException.hpp:14
XmlNodeType GetCurrentNodeType()
gets the type of the current xml element
Class to read an XML File. Non buffered reader, can only read forward
Definition: XmlReader.hpp:22
String GetElementLocalName(void)
Reads the local name of the current active element
bool TryGetAttributeValueDuration(const char *attributeName, T &value)
trys reads an attribute value from the current element and converts the String to std::chrono::durati...
Definition: XmlReader.hpp:434
int GetCurrentDepth()
gets the current depth of the current element inside the xml document
bool ReadToNextSibling(const String &name)
reads to the next element with name which is a sibling of the current element
std::int8_t int8
The Arp integer type of 1 byte size.
Definition: PrimitiveTypes.hpp:29
void ReadStartElement(const char *elementName=nullptr)
reads to the next element and test if this is a start element with the given name ...
bool ReadToFollowing(const String &name)
reads the xml file until an element with name is reached or end of file is reached ...
System components used by the System, Device, Plc or Io domains.
XmlReader(void)
Default contructor.
bool TryGetAttributeValueDuration(const char *attributeName, T defaultValue, T &value)
tries to read an attribute value from the current element as std::crono::duration if the attribute wa...
Definition: XmlReader.hpp:469
Enum< T > GetAttributeValueEnum(const char *attributeName)
reads an attribute value from the current element and converts the String to Enum<T> ...
Definition: XmlReader.hpp:323
bool SkipElementContent()
skips the content of current element with its whole subtree but does not read end element tag ...
bool TryGetAttributeValueEnum(const char *attributeName, T defaultValue, Enum< T > &value)
tries to read an attribute value from the current element as enum if the attribute was not found or t...
Definition: XmlReader.hpp:385