Created
January 30, 2017 08:45
Star
You must be signed in to star a gist
picojson::value に入った picojson::object のネスト構造をドット区切りのパス文字列で引っ張り出すヘルパー ref: http://qiita.com/usagi/items/da3568d8fa61e4aafede
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 理想: picojson には実装されていないが時折欲しくなる使用例 | |
const auto element_value = root_value.[ "aaa.bbb.ccc" ].as< double >(); | |
// 現実: 毎度こんなに書きたくない | |
const double element_value | |
try | |
{ | |
element_value = | |
root_value.get< picojson::object >().at( "aaa" ) | |
.get< picojson::object >().at( "bbb" ) | |
.get< picojson::object >().at( "ccc" ) | |
.get< double >() | |
; | |
} | |
catch( ... ) | |
{ ... } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <picojson.h> | |
#include <boost/algorithm/string.hpp> | |
#include <boost/optional.hpp> | |
#include <vector> | |
namespace usagi::json::picojson | |
{ | |
using object_type = ::picojson::object; | |
using value_type = ::picojson::value; | |
/// @brief value_type に対しドット区切りのパスで object_type の階層を辿り value_type を引っ張り出す | |
static inline auto get_value( const value_type& source, const std::string& dot_separated_path ) | |
-> value_type& | |
{ | |
std::vector< std::string > path; | |
boost::split( path, dot_separated_path, boost::is_any_of( "." ) ); | |
auto out = const_cast< const value_type* >( &source ); | |
for ( const auto& path_part : path ) | |
out = &out->get< object_type >().at( path_part ); | |
return const_cast< value_type& >( *out ); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// @brief get_value が out_of_range や runtime_error など例外で失敗する場合に optional で例外の送出をカバーする版 | |
static inline auto get_value_optional( const value_type& source, const std::string& dot_separated_path ) | |
noexcept | |
-> boost::optional< value_type& > | |
{ | |
try | |
{ return get_value( source, dot_separated_path ); } | |
catch ( ... ) | |
{ return { }; } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// @brief get_value + picojson::get + 可能な限りの自動的な型変換( double や string を float で取り出したり、 null を string で取り出したりもできる ) | |
/// @param type_conversion true の場合には可能な限りの自動的な型変換を試みる。 false の場合には value_type::get のみ。 | |
template < typename T > | |
static inline auto get_value_as | |
( const value_type& source | |
, const std::string& dot_separated_path | |
, const bool type_conversion = true | |
) -> T | |
{ | |
const auto& v = get_value( source, dot_separated_path ); | |
if ( type_conversion ) | |
{ | |
// T が数値型の場合の変換込みの処理 | |
if ( std::is_integral< T >::value or std::is_floating_point< T >::value ) | |
{ | |
// double -> T | |
if ( v.is< double >() ) | |
return static_cast< T >( v.get< double >() ); | |
// string -> T | |
if ( v.is< std::string >() ) | |
{ | |
std::stringstream s; | |
s << v.get< std::string >(); | |
T out; | |
s >> out; | |
if ( s.fail() ) | |
throw std::runtime_error( "cannot convert to a number type from std::string type." ); | |
return out; | |
} | |
} | |
} | |
throw std::runtime_error( "cannot convert to a number type from value_type type." ); | |
} | |
template < > | |
inline auto get_value_as< double > | |
( const value_type& source | |
, const std::string& dot_separated_path | |
, const bool type_conversion | |
) -> double | |
{ | |
const auto& v = get_value( source, dot_separated_path ); | |
if ( v.is< double >() ) | |
return v.get< double >(); | |
if ( type_conversion ) | |
{ | |
// string -> double | |
if ( v.is< std::string >() ) | |
{ | |
std::stringstream s; | |
s << v.get< std::string >(); | |
double out; | |
s >> out; | |
if ( s.fail() ) | |
throw std::runtime_error( "cannot convert to a number type from std::string type." ); | |
return out; | |
} | |
} | |
// note: picojson による cast 失敗で適当な std::runtime_error が発行される | |
return v.get< double >(); | |
} | |
template < > | |
inline auto get_value_as< std::string > | |
( const value_type& source | |
, const std::string& dot_separated_path | |
, const bool type_conversion | |
) -> std::string | |
{ | |
const auto& v = get_value( source, dot_separated_path ); | |
if ( v.is< std::string >() ) | |
return v.get< std::string >(); | |
if ( type_conversion ) | |
{ | |
// value_type の operator<< で string にして返す | |
std::stringstream s; | |
s << v; | |
return s.str(); | |
} | |
// note: picojson による cast 失敗で適当な std::runtime_error が発行される | |
return v.get< std::string >(); | |
} | |
template < > | |
inline auto get_value_as< object_type > | |
( const value_type& source | |
, const std::string& dot_separated_path | |
, const bool type_conversion | |
) -> object_type | |
{ | |
const auto& v = get_value( source, dot_separated_path ); | |
// note: picojson による cast 失敗で適当な std::runtime_error が発行される | |
return v.get< object_type >(); | |
} | |
template < > | |
inline auto get_value_as< array_type > | |
( const value_type& source | |
, const std::string& dot_separated_path | |
, const bool type_conversion | |
) -> array_type | |
{ | |
const auto& v = get_value( source, dot_separated_path ); | |
// note: picojson による cast 失敗で適当な std::runtime_error が発行される | |
return v.get< array_type >(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// @brief get_value_as が out_of_range や runtime_error など例外で失敗する場合に optional で例外の送出をカバーする版 | |
template < typename T > | |
static inline auto get_value_as_optional | |
( const value_type& source | |
, const std::string& dot_separated_path | |
, const bool type_conversion = true | |
) noexcept -> boost::optional< T > | |
{ | |
try | |
{ return get_value_as< T >( source, dot_separated_path, type_conversion ); } | |
catch ( ... ) | |
{ return { }; } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <usagi/json/picojson/get_value.hxx> | |
#include <iostream> | |
#include <iomanip> | |
auto main() -> int | |
{ | |
using namespace std; | |
picojson::value v; | |
if ( const auto& e = picojson::parse | |
( v | |
, "{ 'aaa':" | |
" { 'bbb':" | |
" { 'ccc': 1.23" | |
" , 'ddd': '345.6789012345678e+9'" | |
" }" | |
"}" | |
) | |
) | |
throw runtime_error( e.what() ); | |
cout << v << '\n'; | |
using namespace usagi::json::picojson; | |
cout << get_value_as< double >( v, "aaa.bbb.ccc" ) << '\n'; | |
cout << get_value_as< float >( v, "aaa.bbb.ccc" ) << '\n'; | |
cout << get_value_as< int >( v, "aaa.bbb.ccc" ) << '\n'; | |
cout << get_value_as< uint16_t >( v, "aaa.bbb.ccc" ) << '\n'; | |
cout << to_string( get_value_as< uint8_t >( v, "aaa.bbb.ccc" ) ) << '\n'; | |
cout << get_value_as< string >( v, "aaa.bbb.ccc" ) << '\n'; | |
cout << get_value_as< picojson::object >( v, "aaa.bbb" ).at( "ccc" ) << '\n'; | |
cout << setprecision( 10 ) << get_value_as< float >( v, "aaa.bbb.ddd" ) << '\n'; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"aaa":{"bbb":{"ccc":1.23,"ddd":2.3399999141693115,"eee":"345.6789012345678e+9"}}} | |
1.23 | |
1.23 | |
1 | |
1 | |
1 | |
1.23 | |
1.23 | |
3.456789053e+011 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment