Extension: Json and NetCDF utilities
#include "dg/file/file.h"
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules
json_wrapper.h
Go to the documentation of this file.
1#pragma once
2
3#include <iostream>
4#include <fstream>
5#include <string>
6#include <sstream>
7#include <stdexcept> //std::runtime_error
8
9#ifdef DG_USE_JSONHPP
10#include <nlohmann/json.hpp>
11#else
12#include "json/json.h"
13#endif
14
15//Note that the json utilities are separate from netcdf utilities because
16//of the different library dependencies that they incur
17namespace dg
18{
19namespace file
20{
26#ifdef DG_USE_JSONHPP
27using JsonType = nlohmann::json;
28#else
37using JsonType = Json::Value;
38#endif
39
40
42enum class error{
43 is_throw,
46};
47
49enum class comments{
50 are_kept,
53};
54
121{
124 WrappedJsonValue() : m_js(0), m_mode( error::is_throw){}
127 WrappedJsonValue( error mode): m_js(0), m_mode( mode) {}
130 WrappedJsonValue(JsonType js): m_js(js), m_mode( error::is_throw) {}
134 WrappedJsonValue(JsonType js, error mode): m_js(js), m_mode( mode) {}
137 void set_mode( error new_mode){
138 m_mode = new_mode;
139 }
141 const JsonType& asJson( ) const{ return m_js;}
143 JsonType& asJson( ) { return m_js;}
144
150 std::string access_string() const {return m_access_str;}
151
157 std::string toStyledString() const{
158#ifdef DG_USE_JSONHPP
159 return m_js.dump(4);
160#else
161 return m_js.toStyledString();
162#endif
163 }
164
166 bool isMember(std::string key) const{
167#ifdef DG_USE_JSONHPP
168 return m_js.contains(key);
169#else
170 return m_js.isMember(key);
171#endif
172 }
173
174 // //////////Members imitating the original JsonType///////////////
177 WrappedJsonValue operator[](std::string key) const{
178#ifdef DG_USE_JSONHPP
179 return get( key, nlohmann::json::object(), "empty object ");
180#else
181 return get( key, Json::ValueType::objectValue, "empty object ");
182#endif
183 }
184// The problem with this is that if key is misspelled then
185// it will silently generate it
186// JsonType& operator[]( std::string key){
187// return m_js[key];
188// }
190 WrappedJsonValue get( std::string key, const JsonType& value) const{
191 std::stringstream default_str;
192 default_str << "value "<<value;
193 return get( key, value, default_str.str());
194 }
196 WrappedJsonValue operator[]( unsigned idx) const{
197#ifdef DG_USE_JSONHPP
198 return get( idx, nlohmann::json::object(), "empty array");
199#else
200 return get( idx, Json::ValueType::objectValue, "empty array");
201#endif
202 }
204 WrappedJsonValue get( unsigned idx, const JsonType& value) const{
205 std::stringstream default_str;
206 default_str << "value "<<value;
207 return get( idx, value, default_str.str());
208 }
210 unsigned size() const{
211 return m_js.size();
212 }
214 double asDouble( double value = 0) const{
215#ifdef DG_USE_JSONHPP
216 if( m_js.is_number()) // we just want anything that can be cast to double
217 return m_js.template get<double>();
218#else
219 if( m_js.isDouble())
220 return m_js.asDouble();
221#endif
222 return type_error<double>( value, "a Double");
223 }
225 unsigned asUInt( unsigned value = 0) const{
226#ifdef DG_USE_JSONHPP
227 if( m_js.is_number()) // check for sign?
228 return m_js.template get<unsigned>();
229#else
230 if( m_js.isUInt())
231 return m_js.asUInt();
232#endif
233 return type_error<unsigned>( value, "an Unsigned");
234 }
236 int asInt( int value = 0) const{
237#ifdef DG_USE_JSONHPP
238 if( m_js.is_number())
239 return m_js.template get<int>();
240#else
241 if( m_js.isInt())
242 return m_js.asInt();
243#endif
244 return type_error<int>( value, "an Int");
245 }
247 bool asBool( bool value = false) const{
248#ifdef DG_USE_JSONHPP
249 if( m_js.is_boolean())
250 return m_js.template get<bool>();
251#else
252 if( m_js.isBool())
253 return m_js.asBool();
254#endif
255 return type_error<bool>( value, "a Bool");
256 }
258 std::string asString( std::string value = "") const{
259#ifdef DG_USE_JSONHPP
260 if( m_js.is_string())
261 return m_js.template get<std::string>();
262#else
263 //return m_js["hhaha"].asString(); //does not throw
264 if( m_js.isString())
265 return m_js.asString();
266#endif
267 return type_error<std::string>( value, "a String");
268 }
269 private:
270 WrappedJsonValue(JsonType js, error mode, std::string access):m_js(js), m_mode( mode), m_access_str(access) {}
271 WrappedJsonValue get( std::string key, const JsonType& value, std::string default_str) const
272 {
273 std::string access = m_access_str + "\""+key+"\": ";
274 std::stringstream message;
275#ifdef DG_USE_JSONHPP
276 if( !m_js.is_object( ) || !m_js.contains(key))
277#else
278 if( !m_js.isObject( ) || !m_js.isMember(key))
279#endif
280 {
281 message <<"*** Key error: "<<access<<" not found.";
282 raise_error( message.str(), default_str);
283 return WrappedJsonValue( value, m_mode, access);
284 }
285 return WrappedJsonValue(m_js[key], m_mode, access);
286 }
287 WrappedJsonValue get( unsigned idx, const JsonType& value, std::string default_str) const
288 {
289 std::string access = m_access_str + "["+std::to_string(idx)+"] ";
290#ifdef DG_USE_JSONHPP
291 if( !m_js.is_array() || !(idx < m_js.size()))
292#else
293 if( !m_js.isArray() || !m_js.isValidIndex(idx))
294#endif
295 {
296 std::stringstream message;
297 //if( !m_js.isArray())
298 // message <<"*** Key error: "<<m_access_str<<" is not an Array.";
299 //else
300 if( m_access_str.empty())
301 message <<"*** Index error: Index "<<idx<<" not present.";
302 else
303 message <<"*** Index error: Index "<<idx<<" not present in "<<m_access_str<<".";
304 raise_error( message.str(), default_str);
305 return WrappedJsonValue( value, m_mode, access);
306 }
307 return WrappedJsonValue(m_js[idx], m_mode, access);
308 }
309 template<class T>
310 T type_error( T value, std::string type) const
311 {
312 std::stringstream message, default_str;
313 default_str << "value "<<value;
314 message <<"*** Type error: "<<m_access_str<<" "<<m_js<<" is not "<<type<<".";
315 raise_error( message.str(), default_str.str());
316 return value;
317 }
318 void raise_error( std::string message, std::string default_str) const
319 {
320 if( error::is_throw == m_mode)
321 throw std::runtime_error( message);
322 else if ( error::is_warning == m_mode)
323 std::cerr <<"WARNING "<< message<<" Using default "<<default_str<<"\n";
324 else
325 ;
326 }
327 JsonType m_js;
328 error m_mode;
329 std::string m_access_str = "";
330};
332
335
347inline JsonType file2Json(std::string filename, enum comments comm =
349{
350 std::ifstream isI( filename);
351 if( !isI.good())
352 {
353 std::string message = "\nAn error occured while parsing "+filename+"\n";
354 message += "*** File does not exist! *** \n\n";
355 if( err == error::is_throw)
356 throw std::runtime_error( message);
357 else if (err == error::is_warning)
358 std::cerr << "WARNING: "<<message<<std::endl;
359 else
360 ;
361 return JsonType();
362 }
363 JsonType js;
364#ifdef DG_USE_JSONHPP
365 bool ignore_comments = false, allow_exceptions = false;
367 ignore_comments = true;
368 if ( err == error::is_throw)
369 allow_exceptions = true; //throws nlohmann::json::parse_error
370
371 js = nlohmann::json::parse( isI, nullptr, allow_exceptions, ignore_comments);
372 if( !allow_exceptions && err == error::is_warning && js.is_discarded())
373 {
374 std::string message = "An error occured while parsing "+filename+"\n";
375 std::cerr << "WARNING: "<<message<<std::endl;
376 }
377#else
378 Json::CharReaderBuilder parser;
379 if( comments::are_forbidden == comm )
380 Json::CharReaderBuilder::strictMode( &parser.settings_);
381 else if( comments::are_discarded == comm )
382 {
383 Json::CharReaderBuilder::strictMode( &parser.settings_);
384 // workaround for a linker bug in jsoncpp from package manager
385 JsonType js_true (true);
386 JsonType js_false (false);
387 parser.settings_["allowComments"].swap( js_true);
388 parser.settings_["collectComments"].swap(js_false);
389 }
390 else
391 Json::CharReaderBuilder::setDefaults( &parser.settings_);
392
393 std::string errs;
394 if( !parseFromStream( parser, isI, &js, &errs) )
395 {
396 std::string message = "An error occured while parsing "+filename+"\n"+errs;
397 if( err == error::is_throw)
398 throw std::runtime_error( message);
399 else if (err == error::is_warning)
400 std::cerr << "WARNING: "<<message<<std::endl;
401 else
402 ;
403 }
404#endif
405 return js;
406}
407
409inline void file2Json(std::string filename, JsonType& js, enum comments comm = file::comments::are_discarded, enum error err = file::error::is_throw)
410{
411 js = file2Json( filename, comm, err);
412}
413
414
430{
431 JsonType js;
432#ifdef DG_USE_JSONHPP
433 bool ignore_comments = false, allow_exceptions = false;
435 ignore_comments = true;
436 if ( err == error::is_throw)
437 allow_exceptions = true; //throws nlohmann::json::parse_error
438
439
440 js = nlohmann::json::parse( input, nullptr, allow_exceptions, ignore_comments);
441 if( !allow_exceptions && err == error::is_warning && js.is_discarded())
442 {
443 std::string message = "An error occured while parsing \n";
444 std::cerr << "WARNING: "<<message<<std::endl;
445 }
446 return js;
447
448#else
449
450 Json::CharReaderBuilder parser;
451 if( comments::are_forbidden == comm )
452 Json::CharReaderBuilder::strictMode( &parser.settings_);
453 else if( comments::are_discarded == comm )
454 {
455 Json::CharReaderBuilder::strictMode( &parser.settings_);
456 parser.settings_["allowComments"] = true;
457 parser.settings_["collectComments"] = false;
458 }
459 else
460 Json::CharReaderBuilder::setDefaults( &parser.settings_);
461
462 std::string errs;
463 std::stringstream ss(input);
464 if( !parseFromStream( parser, ss, &js, &errs) )
465 {
466 if( err == error::is_throw)
467 throw std::runtime_error( errs);
468 else if (err == error::is_warning)
469 std::cerr << "WARNING: "<<errs<<std::endl;
470 else
471 ;
472 }
473#endif
474 return js;
475}
476
478inline void string2Json(std::string input, JsonType& js, enum comments comm = file::comments::are_discarded, enum error err = file::error::is_throw)
479{
480 js = string2Json( input, comm, err);
481}
482
488template<class ContainerType>
489dg::file::JsonType vec2json( const ContainerType& shared)
490{
491#ifdef DG_USE_JSONHPP
492 return nlohmann::json(shared);
493#else
494 Json::Value val;
495 for( const auto& value : shared)
496 val.append(value);
497 return val;
498#endif
499}
500
502template<class T>
503dg::file::JsonType vec2json( std::initializer_list<T> shared)
504{
505 std::vector<T> cc( shared);
506 return vec2json(cc);
507}
509
510
511}//namespace file
512}//namespace dg
JsonType string2Json(std::string input, enum comments comm=file::comments::are_discarded, enum error err=file::error::is_throw)
Convenience wrapper to parse a string into a JsonType.
Definition json_wrapper.h:429
JsonType file2Json(std::string filename, enum comments comm=file::comments::are_discarded, enum error err=file::error::is_throw)
Convenience wrapper to open a file and parse it into a JsonType.
Definition json_wrapper.h:347
dg::file::JsonType vec2json(const ContainerType &shared)
convert a vector to a json arrray
Definition json_wrapper.h:489
Json::Value JsonType
Json Type to use in dg::file functions and classes.
Definition json_wrapper.h:37
error
Switch between how to handle errors in a Json utitlity functions.
Definition json_wrapper.h:42
comments
Switch how comments are treated in a json string or file.
Definition json_wrapper.h:49
@ is_warning
Handle the error by writing a warning to std::cerr.
@ is_silent
Ignore the error and silently continue execution.
@ is_throw
throw an error (std::runtime_error)
@ are_discarded
Allow comments but discard them in the Json value.
@ are_kept
Keep comments in the Json value.
@ are_forbidden
Treat comments as invalid Json.
Definition easy_atts.h:15
Wrapped Access to Json values with error handling.
Definition json_wrapper.h:121
std::string asString(std::string value="") const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:258
WrappedJsonValue()
Default constructor By default the error mode is error::is_throw.
Definition json_wrapper.h:124
WrappedJsonValue(JsonType js)
By default the error mode is error::is_throw.
Definition json_wrapper.h:130
bool isMember(std::string key) const
Return true if key is a Member of the json value.
Definition json_wrapper.h:166
WrappedJsonValue operator[](unsigned idx) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:196
WrappedJsonValue get(unsigned idx, const JsonType &value) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:204
bool asBool(bool value=false) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:247
unsigned asUInt(unsigned value=0) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:225
void set_mode(error new_mode)
Change the error mode.
Definition json_wrapper.h:137
double asDouble(double value=0) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:214
WrappedJsonValue get(std::string key, const JsonType &value) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:190
std::string toStyledString() const
The stored json object as a formatted string.
Definition json_wrapper.h:157
WrappedJsonValue(JsonType js, error mode)
Construct with Json value and error mode.
Definition json_wrapper.h:134
WrappedJsonValue(error mode)
Construct with error mode.
Definition json_wrapper.h:127
std::string access_string() const
The creation history of the object.
Definition json_wrapper.h:150
WrappedJsonValue operator[](std::string key) const
Definition json_wrapper.h:177
const JsonType & asJson() const
Read access to the raw Json value.
Definition json_wrapper.h:141
JsonType & asJson()
Write access to the raw Json value (if you know what you are doing)
Definition json_wrapper.h:143
unsigned size() const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:210
int asInt(int value=0) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:236