Extension: Json and NetCDF utilities
#include "dg/file/file.h"
Loading...
Searching...
No Matches
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 }
174 bool isString() const {
175#ifdef DG_USE_JSONHPP
176 return m_js.is_string();
177#else
178 return m_js.isString();
179#endif
180 }
181
182 // //////////Members imitating the original JsonType///////////////
185 WrappedJsonValue operator[](std::string key) const{
186#ifdef DG_USE_JSONHPP
187 return get( key, nlohmann::json::object(), "empty object ");
188#else
189 return get( key, Json::ValueType::objectValue, "empty object ");
190#endif
191 }
192// The problem with this is that if key is misspelled then
193// it will silently generate it
194// JsonType& operator[]( std::string key){
195// return m_js[key];
196// }
198 WrappedJsonValue get( std::string key, const JsonType& value) const{
199 std::stringstream default_str;
200 default_str << "value "<<value;
201 return get( key, value, default_str.str());
202 }
204 WrappedJsonValue operator[]( unsigned idx) const{
205#ifdef DG_USE_JSONHPP
206 return get( idx, nlohmann::json::object(), "empty array");
207#else
208 return get( idx, Json::ValueType::objectValue, "empty array");
209#endif
210 }
212 WrappedJsonValue get( unsigned idx, const JsonType& value) const{
213 std::stringstream default_str;
214 default_str << "value "<<value;
215 return get( idx, value, default_str.str());
216 }
218 unsigned size() const{
219 return (unsigned)m_js.size();
220 }
222 double asDouble( double value = 0) const{
223#ifdef DG_USE_JSONHPP
224 if( m_js.is_number()) // we just want anything that can be cast to double
225 return m_js.template get<double>();
226#else
227 if( m_js.isDouble())
228 return m_js.asDouble();
229#endif
230 return type_error<double>( value, "a Double");
231 }
233 unsigned asUInt( unsigned value = 0) const{
234#ifdef DG_USE_JSONHPP
235 if( m_js.is_number()) // check for sign?
236 return m_js.template get<unsigned>();
237#else
238 if( m_js.isUInt())
239 return m_js.asUInt();
240#endif
241 return type_error<unsigned>( value, "an Unsigned");
242 }
244 int asInt( int value = 0) const{
245#ifdef DG_USE_JSONHPP
246 if( m_js.is_number())
247 return m_js.template get<int>();
248#else
249 if( m_js.isInt())
250 return m_js.asInt();
251#endif
252 return type_error<int>( value, "an Int");
253 }
255 bool asBool( bool value = false) const{
256#ifdef DG_USE_JSONHPP
257 if( m_js.is_boolean())
258 return m_js.template get<bool>();
259#else
260 if( m_js.isBool())
261 return m_js.asBool();
262#endif
263 return type_error<bool>( value, "a Bool");
264 }
266 std::string asString( std::string value = "") const{
267#ifdef DG_USE_JSONHPP
268 if( m_js.is_string())
269 return m_js.template get<std::string>();
270#else
271 //return m_js["hhaha"].asString(); //does not throw
272 if( m_js.isString())
273 return m_js.asString();
274#endif
275 return type_error<std::string>( value, "a String");
276 }
277 private:
278 WrappedJsonValue(JsonType js, error mode, std::string access):m_js(js), m_mode( mode), m_access_str(access) {}
279 WrappedJsonValue get( std::string key, const JsonType& value, std::string default_str) const
280 {
281 std::string access = m_access_str + "\""+key+"\": ";
282 std::stringstream message;
283#ifdef DG_USE_JSONHPP
284 if( !m_js.is_object( ) || !m_js.contains(key))
285#else
286 if( !m_js.isObject( ) || !m_js.isMember(key))
287#endif
288 {
289 message <<"*** Key error: "<<access<<" not found.";
290 raise_error( message.str(), default_str);
291 return WrappedJsonValue( value, m_mode, access);
292 }
293 return WrappedJsonValue(m_js[key], m_mode, access);
294 }
295 WrappedJsonValue get( unsigned idx, const JsonType& value, std::string default_str) const
296 {
297 std::string access = m_access_str + "["+std::to_string(idx)+"] ";
298#ifdef DG_USE_JSONHPP
299 if( !m_js.is_array() || !(idx < m_js.size()))
300#else
301 if( !m_js.isArray() || !m_js.isValidIndex(idx))
302#endif
303 {
304 std::stringstream message;
305 //if( !m_js.isArray())
306 // message <<"*** Key error: "<<m_access_str<<" is not an Array.";
307 //else
308 if( m_access_str.empty())
309 message <<"*** Index error: Index "<<idx<<" not present.";
310 else
311 message <<"*** Index error: Index "<<idx<<" not present in "<<m_access_str<<".";
312 raise_error( message.str(), default_str);
313 return WrappedJsonValue( value, m_mode, access);
314 }
315 return WrappedJsonValue(m_js[idx], m_mode, access);
316 }
317 template<class T>
318 T type_error( T value, std::string type) const
319 {
320 std::stringstream message, default_str;
321 default_str << "value "<<value;
322 message <<"*** Type error: "<<m_access_str<<" "<<m_js<<" is not "<<type<<".";
323 raise_error( message.str(), default_str.str());
324 return value;
325 }
326 void raise_error( std::string message, std::string default_str) const
327 {
328 if( error::is_throw == m_mode)
329 throw std::runtime_error( message);
330 else if ( error::is_warning == m_mode)
331 std::cerr <<"WARNING "<< message<<" Using default "<<default_str<<"\n";
332 else
333 {
334 }
335 }
336 JsonType m_js;
337 error m_mode;
338 std::string m_access_str = "";
339};
341
344
356inline JsonType file2Json(std::string filename, enum comments comm =
358{
359 std::ifstream isI( filename);
360 if( !isI.good())
361 {
362 std::string message = "\nAn error occured while parsing "+filename+"\n";
363 message += "*** File does not exist! *** \n\n";
364 if( err == error::is_throw)
365 throw std::runtime_error( message);
366 else if (err == error::is_warning)
367 std::cerr << "WARNING: "<<message<<std::endl;
368 else
369 {
370 }
371 return JsonType();
372 }
373 JsonType js;
374#ifdef DG_USE_JSONHPP
375 bool ignore_comments = false, allow_exceptions = false;
377 ignore_comments = true;
378 if ( err == error::is_throw)
379 allow_exceptions = true; //throws nlohmann::json::parse_error
380
381 js = nlohmann::json::parse( isI, nullptr, allow_exceptions, ignore_comments);
382 if( !allow_exceptions && err == error::is_warning && js.is_discarded())
383 {
384 std::string message = "An error occured while parsing "+filename+"\n";
385 std::cerr << "WARNING: "<<message<<std::endl;
386 }
387#else
388 Json::CharReaderBuilder parser;
389 if( comments::are_forbidden == comm )
390 Json::CharReaderBuilder::strictMode( &parser.settings_);
391 else if( comments::are_discarded == comm )
392 {
393 Json::CharReaderBuilder::strictMode( &parser.settings_);
394 // workaround for a linker bug in jsoncpp from package manager
395 JsonType js_true (true);
396 JsonType js_false (false);
397 parser.settings_["allowComments"].swap( js_true);
398 parser.settings_["collectComments"].swap(js_false);
399 }
400 else
401 Json::CharReaderBuilder::setDefaults( &parser.settings_);
402
403 std::string errs;
404 if( !parseFromStream( parser, isI, &js, &errs) )
405 {
406 std::string message = "An error occured while parsing "+filename+"\n"+errs;
407 if( err == error::is_throw)
408 throw std::runtime_error( message);
409 else if (err == error::is_warning)
410 std::cerr << "WARNING: "<<message<<std::endl;
411 else
412 {
413 }
414 }
415#endif
416 return js;
417}
418
420inline void file2Json(std::string filename, JsonType& js, enum comments comm = file::comments::are_discarded, enum error err = file::error::is_throw)
421{
422 js = file2Json( filename, comm, err);
423}
424
425
441{
442 JsonType js;
443#ifdef DG_USE_JSONHPP
444 bool ignore_comments = false, allow_exceptions = false;
446 ignore_comments = true;
447 if ( err == error::is_throw)
448 allow_exceptions = true; //throws nlohmann::json::parse_error
449
450
451 js = nlohmann::json::parse( input, nullptr, allow_exceptions, ignore_comments);
452 if( !allow_exceptions && err == error::is_warning && js.is_discarded())
453 {
454 std::string message = "An error occured while parsing \n";
455 std::cerr << "WARNING: "<<message<<std::endl;
456 }
457 return js;
458
459#else
460
461 Json::CharReaderBuilder parser;
462 if( comments::are_forbidden == comm )
463 Json::CharReaderBuilder::strictMode( &parser.settings_);
464 else if( comments::are_discarded == comm )
465 {
466 Json::CharReaderBuilder::strictMode( &parser.settings_);
467 parser.settings_["allowComments"] = true;
468 parser.settings_["collectComments"] = false;
469 }
470 else
471 Json::CharReaderBuilder::setDefaults( &parser.settings_);
472
473 std::string errs;
474 std::stringstream ss(input);
475 if( !parseFromStream( parser, ss, &js, &errs) )
476 {
477 if( err == error::is_throw)
478 throw std::runtime_error( errs);
479 else if (err == error::is_warning)
480 std::cerr << "WARNING: "<<errs<<std::endl;
481 else
482 {
483 }
484 }
485#endif
486 return js;
487}
488
490inline void string2Json(std::string input, JsonType& js, enum comments comm = file::comments::are_discarded, enum error err = file::error::is_throw)
491{
492 js = string2Json( input, comm, err);
493}
494
500template<class ContainerType>
501dg::file::JsonType vec2json( const ContainerType& shared)
502{
503#ifdef DG_USE_JSONHPP
504 return nlohmann::json(shared);
505#else
506 Json::Value val;
507 for( const auto& value : shared)
508 val.append(value);
509 return val;
510#endif
511}
512
514template<class T>
515dg::file::JsonType vec2json( std::initializer_list<T> shared)
516{
517 std::vector<T> cc( shared);
518 return vec2json(cc);
519}
521
522
523}//namespace file
524}//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:440
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:356
dg::file::JsonType vec2json(const ContainerType &shared)
convert a vector to a json arrray
Definition json_wrapper.h:501
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:266
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 isString() const
Call corresponding JsonType function.
Definition json_wrapper.h:174
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:204
WrappedJsonValue get(unsigned idx, const JsonType &value) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:212
bool asBool(bool value=false) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:255
unsigned asUInt(unsigned value=0) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:233
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:222
WrappedJsonValue get(std::string key, const JsonType &value) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:198
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:185
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:218
int asInt(int value=0) const
Wrap the corresponding JsonType function with error handling.
Definition json_wrapper.h:244