GEOS
xmlWrapper.hpp
Go to the documentation of this file.
1 /*
2  * ------------------------------------------------------------------------------------------------------------
3  * SPDX-License-Identifier: LGPL-2.1-only
4  *
5  * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
6  * Copyright (c) 2018-2024 TotalEnergies
7  * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
8  * Copyright (c) 2023-2024 Chevron
9  * Copyright (c) 2019- GEOS/GEOSX Contributors
10  * All rights reserved
11  *
12  * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
13  * ------------------------------------------------------------------------------------------------------------
14  */
15 
20 #ifndef GEOS_DATAREPOSITORY_XMLWRAPPER_HPP_
21 #define GEOS_DATAREPOSITORY_XMLWRAPPER_HPP_
22 
23 // Source includes
24 #include "common/DataTypes.hpp"
25 #include "DefaultValue.hpp"
26 #include "common/GEOS_RAJA_Interface.hpp"
27 #include "LvArray/src/output.hpp"
28 #include "LvArray/src/input.hpp"
30 #include "codingUtilities/RTTypes.hpp"
31 
32 // TPL includes
33 #include <pugixml.hpp>
34 
35 // System includes
36 #include <algorithm>
37 #include <regex>
38 #include <sstream>
39 
40 namespace geos
41 {
42 
43 
51 namespace xmlWrapper
52 {
53 
55 using xmlResult = pugi::xml_parse_result;
56 
60 using xmlNode = pugi::xml_node;
61 
65 using xmlAttribute = pugi::xml_attribute;
66 
68 using xmlNodeType = pugi::xml_node_type;
69 
70 class xmlDocument;
71 
78 {
80  string filePath;
83  size_t const line;
86  size_t const offsetInLine;
89  size_t const offset;
90 
98  xmlAttributePos( string const & filePath, size_t line, size_t offsetInLine, size_t offset );
102  bool isFound() const;
106  string toString() const;
107 };
108 
115 {
118 
127  xmlNodePos( xmlDocument const & document, string const & filePath, size_t line, size_t offsetInLine, size_t offset );
131  bool isFound() const;
137  xmlAttributePos getAttributeLine( string const & attName ) const;
138 };
139 
148 {
149 public:
151  static constexpr size_t npos = string::npos;
152 
160  xmlDocument( const xmlDocument & ) = delete;
164  xmlDocument( xmlDocument && ) = default;
165 
174  xmlNode getChild( string const & name ) const;
178  string const & getOriginalBuffer() const;
185  string const * getOriginalBuffer( string const & filePath ) const;
194  string const & getFilePath() const;
202 
211  xmlResult loadString( string_view content, bool loadNodeFileInfo = false );
212 
220  xmlResult loadFile( string const & path, bool loadNodeFileInfo = false );
221 
227  xmlNode appendChild( string const & name );
234  xmlNode appendChild( xmlNodeType type = xmlNodeType::node_element );
235 
242  bool saveFile( string const & path ) const;
243 
254  void addIncludedXML( xmlNode & targetNode, int level = 0 );
255 
259  bool hasNodeFileInfo() const;
260 
261 private:
263  pugi::xml_document pugiDocument;
264 
266  map< string, string > m_originalBuffers;
268  string m_rootFilePath;
269 };
270 
277 constexpr char const filePathString[] = "__filePath__";
278 
285 constexpr char const charOffsetString[] = "__charOffset__";
286 
288 constexpr char const includedListTag[] = "Included";
289 
291 constexpr char const includedFileTag[] = "File";
292 
302 string buildMultipleInputXML( string_array const & inputFileList,
303  string const & outputDir = {} );
304 
309 bool isFileMetadataAttribute( string const & name );
310 
319 
326 void validateString( string const & value, Regex const & regex );
327 
336 void processInputException( std::exception const & ex, string const & targetAttributeName,
337  xmlWrapper::xmlNode const & targetNode,
338  xmlWrapper::xmlNodePos const & nodePos );
339 
350 template< typename T >
351 std::enable_if_t< traits::CanStreamInto< std::istringstream, T > >
352 stringToInputVariable( T & target, string const & value, Regex const & regex )
353 {
354  validateString( value, regex );
355  string_view stringTrimed = stringutilities::trimSpaces( value );
356  std::istringstream ss( (string( stringTrimed )) );
357  ss >> target;
358  GEOS_THROW_IF( ss.fail() || !ss.eof(),
359  GEOS_FMT( "Error detected while parsing string \"{}\" to type {}",
360  value,
361  LvArray::system::demangleType< T >() ),
362  InputError );
363 }
364 
373 template< typename T, int SIZE >
374 void
375 stringToInputVariable( Tensor< T, SIZE > & target, string const & value, Regex const & regex );
376 
389 template< typename T, int NDIM, typename PERMUTATION >
390 std::enable_if_t< traits::CanStreamInto< std::istringstream, T > >
391 stringToInputVariable( Array< T, NDIM, PERMUTATION > & array, string const & value, Regex const & regex )
392 {
393  try
394  {
395  validateString( value, regex );
396  }
397  catch( std::regex_error const & error )
398  {
399  // libc++ rejects the deeply nested regexes used for multidimensional arrays.
400  if( error.code() != std::regex_constants::error_complexity )
401  {
402  throw;
403  }
404  }
405 
406  LvArray::input::stringToArray( array, string( stringutilities::trimSpaces( value ) ) );
407 }
408 
415 void stringToInputVariable( stdVector< std::string > & array, string const & value, Regex const & regex );
416 
418 
419 namespace internal
420 {
421 
424 IS_VALID_EXPRESSION( canParseVariable, T, stringToInputVariable( std::declval< T & >(), string(), Regex() ) );
425 
432 template< typename T >
433 static void equate( T & lhs, T const & rhs )
434 { lhs = rhs; }
435 
444 template< typename T, int NDIM, typename PERM >
445 static void equate( Array< T, NDIM, PERM > const & lhs, T const & rhs )
446 { lhs.template setValues< serialPolicy >( rhs ); }
447 
448 template< typename T >
449 static void equate( stdVector< T > & lhs, T const & rhs )
450 {
451  for( auto & val : lhs )
452  {
453  val = rhs;
454  }
455 }
456 
457 } // namespace internal
458 
463 
474 template< typename T, typename U >
475 std::enable_if_t< !internal::canParseVariable< T >, bool >
476 readAttributeAsType( T &, string const & name, Regex const &, xmlNode const &, U const & )
477 {
478  GEOS_THROW( GEOS_FMT( "Cannot parse key with name ({}) with the given type {}",
479  name,
480  LvArray::system::demangleType< T >() ),
481  InputError );
482  return false;
483 }
484 
498 template< typename T, typename T_DEF = T >
499 std::enable_if_t< internal::canParseVariable< T >, bool >
501  string const & name,
502  Regex const & regex,
503  xmlNode const & targetNode,
504  T_DEF const & defVal )
505 {
506  xmlAttribute const xmlatt = targetNode.attribute( name.c_str() );
507  if( !xmlatt.empty() )
508  {
509  // parse the string/attribute into a value
510  stringToInputVariable( rval, xmlatt.value(), regex );
511  return true;
512  }
513  else
514  {
515  // set the value to the default value
516  internal::equate( rval, defVal );
517  return false;
518  }
519 }
520 
533 template< typename T >
534 std::enable_if_t< internal::canParseVariable< T >, bool >
536  string const & name,
537  Regex const & regex,
538  xmlNode const & targetNode,
539  bool const required )
540 {
541  xmlAttribute const xmlatt = targetNode.attribute( name.c_str() );
542 
543  bool const success = !(xmlatt.empty() && required);
544 
545  if( success )
546  {
547  // parse the string/attribute into a value
548  stringToInputVariable( rval, xmlatt.value(), regex );
549  }
550  return success;
551 }
552 
564 template< typename T >
565 std::enable_if_t< !dataRepository::DefaultValue< T >::has_default_value, bool >
567  string const & name,
568  Regex const & regex,
569  xmlNode const & targetNode,
571 {
572  return readAttributeAsType( rval, name, regex, targetNode, false );
573 }
574 
587 template< typename T >
588 typename std::enable_if_t< dataRepository::DefaultValue< T >::has_default_value, bool >
590  string const & name,
591  Regex const & regex,
592  xmlNode const & targetNode,
593  dataRepository::DefaultValue< T > const & defVal )
594 {
595  return readAttributeAsType( rval, name, regex, targetNode, defVal.value );
596 }
597 
599 
600 }
601 
602 } /* namespace geos */
603 
604 #endif /*GEOS_DATAREPOSITORY_XMLWRAPPER_HPP_ */
#define GEOS_THROW(MSG,...)
Conditionally raise a hard error and terminate the program.
Definition: Logger.hpp:299
#define GEOS_THROW_IF(COND, MSG,...)
Conditionally raise a hard error and terminate the program.
Definition: Logger.hpp:289
Lightweight wrapper around a c-array.
Definition: Tensor.hpp:31
Base template for ordered and unordered maps.
xmlNode appendChild(string const &name)
Add a root element to the document.
xmlDocument(xmlDocument &&)=default
move constructor
void addIncludedXML(xmlNode &targetNode, int level=0)
Function to add xml nodes from included files.
string const & getFilePath() const
map< string, string > const & getOriginalBuffers() const
bool saveFile(string const &path) const
Save the XML to a file.
xmlNode appendChild(xmlNodeType type=xmlNodeType::node_element)
Add a root element to the document.
string const & getOriginalBuffer() const
xmlDocument()
Construct an empty xmlDocument that waits to load something.
xmlNode getChild(string const &name) const
xmlNodePos getNodePosition(xmlWrapper::xmlNode const &node) const
If the node file information are loaded, compute the position of a node.
xmlDocument(const xmlDocument &)=delete
non-copyable
xmlResult loadString(string_view content, bool loadNodeFileInfo=false)
Load document from zero-terminated string. No encoding conversions are applied. Free any previously l...
static constexpr size_t npos
Error value for when an offset / line position is undefined.
Definition: xmlWrapper.hpp:151
xmlResult loadFile(string const &path, bool loadNodeFileInfo=false)
Load document from file. Free any previously loaded xml tree. Wrapper of pugi::xml_document::loadBuff...
string const * getOriginalBuffer(string const &filePath) const
internal::Helper< T > DefaultValue
A templated alias to hold default values.
pugi::xml_node_type xmlNodeType
Alias for the type variant of an xml node.
Definition: xmlWrapper.hpp:68
pugi::xml_node xmlNode
Definition: xmlWrapper.hpp:60
constexpr char const includedFileTag[]
XML tag name for included files.
Definition: xmlWrapper.hpp:291
std::enable_if_t< traits::CanStreamInto< std::istringstream, T > > stringToInputVariable(T &target, string const &value, Regex const &regex)
Parse a string and fill a variable with the value(s) in the string.
Definition: xmlWrapper.hpp:352
void validateString(string const &value, Regex const &regex)
pugi::xml_attribute xmlAttribute
Definition: xmlWrapper.hpp:65
std::enable_if_t< !internal::canParseVariable< T >, bool > readAttributeAsType(T &, string const &name, Regex const &, xmlNode const &, U const &)
Extract attribute in an xml tree, and translate its value into a typed variable. This SFINAE implemen...
Definition: xmlWrapper.hpp:476
pugi::xml_parse_result xmlResult
Alias for the type of the result from an xml parse attempt.
Definition: xmlWrapper.hpp:55
constexpr char const charOffsetString[]
constexpr variable to hold node character offset from the start of the xml file.
Definition: xmlWrapper.hpp:285
bool isFileMetadataAttribute(string const &name)
constexpr char const includedListTag[]
XML tag name for included sections.
Definition: xmlWrapper.hpp:288
constexpr char const filePathString[]
constexpr variable to hold name for inserting the file path into the xml file.
Definition: xmlWrapper.hpp:277
void processInputException(std::exception const &ex, string const &targetAttributeName, xmlWrapper::xmlNode const &targetNode, xmlWrapper::xmlNodePos const &nodePos)
Helper method to process an exception that has been thrown during xml parsing.
string buildMultipleInputXML(string_array const &inputFileList, string const &outputDir={})
Function to handle multiple input xml files.
stdVector< string > string_array
A 1-dimensional array of geos::string types.
Definition: DataTypes.hpp:361
LvArray::Array< T, NDIM, PERMUTATION, localIndex, LvArray::ChaiBuffer > Array
Multidimensional array type. See LvArray:Array for details.
Definition: DataTypes.hpp:141
std::string_view string_view
String type.
Definition: DataTypes.hpp:93
internal::StdVectorWrapper< T, Allocator, USE_STD_CONTAINER_BOUNDS_CHECKING > stdVector
Exception class used to report errors in user input.
string filePath
Path of the file containing this element.
Definition: xmlWrapper.hpp:80
xmlAttributePos(string const &filePath, size_t line, size_t offsetInLine, size_t offset)
Constructor of this struct.
xmlAttributePos getAttributeLine(string const &attName) const
Compute the xmlAttributePos of an xml attribute.
xmlNodePos(xmlDocument const &document, string const &filePath, size_t line, size_t offsetInLine, size_t offset)
Constructor of this struct.
xmlDocument const & document
Reference of the main xmlDocument that contains all original file buffers.
Definition: xmlWrapper.hpp:117