Converting a Json::Value to std::string? - c++

I am using JsonCpp to build a JSON object. Once the object is built, is there a way I can get the object as an std::string?

You can use a Json::Writer to do exactly this, since I assume you want to save it somewhere so you don't want human readable output, your best bet would be to use a Json::FastWriter and then you can call the write method with the parameter of your Json::Value (ie. your root) and then that simply returns a std::string like so:
Json::FastWriter fastWriter;
std::string output = fastWriter.write(root);

Json::Writer is deprecated. Use Json::StreamWriter or Json::StreamWriterBuilder instead.
Json::writeString writes into a stringstream and then returns a string:
Json::Value json = ...;
Json::StreamWriterBuilder builder;
builder["indentation"] = ""; // If you want whitespace-less output
const std::string output = Json::writeString(builder, json);
Kudos to cdunn2001's answer here: How to get JsonCPP values as strings?

You can also use the method toStyledString().
jsonValue.toStyledString();
The method "toStyledString()" converts any value to a formatted string.
See also the link: doc for toStyledString

If your Json::value is of string type, e.g. "bar" in the following json
{
"foo": "bar"
}
You can use Json::Value.asString to get the value of bar without extra quotes(which will be added if you use StringWriterBuilder). Here is an example:
Json::Value rootJsonValue;
rootJsonValue["foo"] = "bar";
std::string s = rootJsonValue["foo"].asString();
std::cout << s << std::endl; // bar

In my context, I instead used a simple .asString() at the end of my json value object. As #Searene said, it gets rid of the extra quotes that you don't necessary wants if you want to process it after.
Json::Value credentials;
Json::Reader reader;
// Catch the error if wanted for the reader if wanted.
reader.parse(request.body(), credentials);
std::string usager, password;
usager = credentials["usager"].asString();
password = credentials["password"].asString();
If the value is a int instead of a string, .asInt() works great as well.

This little helper might do.
//////////////////////////////////////////////////
// json.asString()
//
std::string JsonAsString(const Json::Value &json)
{
std::string result;
Json::StreamWriterBuilder wbuilder;
wbuilder["indentation"] = ""; // Optional
result = Json::writeString(wbuilder, json);
return result;
}

Related

How do I convert a std::string to System.String in C++ with Il2CppInspector?

I am using Il2CppInspector to generate scaffolding for a Unity game. I am able to convert System.String (app::String in Il2CppInspector) to std::string using the functions provided below.
How would I reverse this process; how do I convert a std::string to System.String?
helpers.cpp
// Helper function to convert Il2CppString to std::string
std::string il2cppi_to_string(Il2CppString* str) {
std::u16string u16(reinterpret_cast<const char16_t*>(str->chars));
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(u16);
}
// Helper function to convert System.String to std::string
std::string il2cppi_to_string(app::String* str) {
return il2cppi_to_string(reinterpret_cast<Il2CppString*>(str));
}
In short, I am looking for a function that takes in a std::string and returns an app::String
// Helper function to convert std::string to System.String
app::String string_to_il2cppi(std::string str) {
// Conversion code here
}
The accepted answer is actually wrong, there is no size parameter and copying stops at the first null byte (0x00) according to the MSDN documentation.
The following code fixes these problems and works correctly:
app::String* string_to_il2cppi(const std::string& string)
{
const auto encoding = (*app::Encoding__TypeInfo)->static_fields->utf8Encoding;
const auto managed_string = app::String_CreateStringFromEncoding((uint8_t*)&string.at(0), string.size(), encoding, nullptr);
return managed_string;
}
A quote from djkaty:
To create a string, you cannot use System.String‘s constructors –
these are redirected to icalls that throw exceptions. Instead, you
should use the internal Mono function String.CreateString. This
function has many overloads accepting various types of pointer and
array; an easy one to use accepts a uint16_t* to a Unicode string and
can be called as follows [...]
Export Il2CppInspector with all namespaces, which will give you access to Marshal_PtrToStringAnsi.
app::String* string_to_il2cppi(std::string str) {
return app::Marshal_PtrToStringAnsi((void*)&str, NULL);
}
Limitation: do not attempt to convert a string with null terminators inside of them example:
std::string test = "Hello\0world";
Use BullyWiiPlaza's solution if this is an issue for you.

What is the way to replace jsoncpp FastWriter with Streambuilder?

I have a jsoncpp value that I want to serialize. The most straightforward way is like this:
Json::Value val; // population is left as an exercise for the reader
std::string str = Json::FastWriter().write(val);
The problem is that FastWriter is deprecated, and I can't tolerate compiler warnings. According to the less-than-intuitive documentation, I'm supposed to use StreamWriterBuilder instead:
Json::StreamWriterBuilder builder;
builder["commentStyle"] = "None";
builder["indentation"] = "";
std::unique_ptr<Json::StreamWriter> writer( builder.newStreamWriter() );
std::ostringstream os;
writer->write(val, &os);
std::string str = os.str();
Surely this can't be "better"? I'm assuming the fault lies with me and there is a straightforward way to perform minimal serialization (without extraneous whitespace).
This shows a slightly more compact form (although it appears to simply wrap the above in a function call).
Json::StreamWriterBuilder builder;
builder["indentation"] = ""; // assume default for comments is None
std::string str = Json::writeString(builder, val);
Is that the right way now?
You're doing it the right way.
The second example is just a shorthand for the first — in both instances, a builder dynamically allocates a writer, the writer is used and then the writer is freed.
Why the older FastWriter implementation was deprecated I could not say. Personally I miss it a bit. But a factory is more flexible and permits different implementations slotting into the same suite of functions. You'd have to ask the JsonCpp developers whether that was the core of their decision.
If you always want to write with the same settings (e.g. your ["indentation"] = ""), you can supply a Json::Value representing the settings to Json::StreamWriterBuilder::setDefault, then writing strings doesn't need to name Json::StreamWriterBuilder again (but does default construct one)
Startup
Json::Value streamWriterSettings{R"({ "indentation" : "" })"};
Json::StreamWriterBuilder::setDefault(&streamWriterSettings);
Usage
std::string str = Json::writeString({}, val);

C++ nlohmann/json how to use runtime provided json_pointers to read json values

I am using the json parser Json for Modern C++ (https://github.com/nlohmann/json). I know that I can get the value of a JSON value with a JSON_Pointer:
auto v1 = j["/a/b/c"_json_pointer];
But how would I go about getting the value if the JSON Pointer is defined at runtime (passed into my function)?
std:string s1 = "/a/b/c";
auto v1 = j[s1]; // doesn't work
You can't append "json_pointer" to either the std::string assignment or to the s1 variable. Is there a function that will convert a std::string to a json_pointer? The caller knows nothing about json and can't have access to the "json.hpp" header. I've also tried
std::string s1 = "/a/b/c";
json_pointer p1(s1);
but "json_pointer" class is undefined. Other than this issue this is a great library that does everything else I need. TIA.
Look at the source code:
inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t)
{
return nlohmann::json::json_pointer(s);
}
If json_pointer is undefined, then you aren't using the right namespaces. Try
using nlohmann::json::json_pointer;
std::string s1 = "/a/b/c";
json_pointer p1(s1);

Accept null values for strings with rapidjson inside cereal, make them ""

For deserializing JSON into a c++ class, I'm using Cereal, which uses RapidJSON. As expected, c++ std::string can't have a null value. But other platforms do support null for strings (.NET SQL etc) and I get JSON from them with null values for strings. I need to tolerate this, and just make an empty string for nulls. What's the best way to do that?
I default to string substitute on the JSON changing nulls to "" like the following, but it is not a clean solution.
#include <cereal/archives/json.hpp>
#include <boost/algorithm/string.hpp>
// i.e. substitue all ":null with ":"" Like {"key":null} into {"key":""}
boost::replace_all(json, "\":null", "\":\"\"");
auto r = std::make_shared<R>();
std::stringstream ss(json);
{
cereal::JSONInputArchive archive(ss);
r->serialize(archive);
}
In case someone looks for this answer based on the exception generated by Cereal, it is: "rapidjson internal assertion failure: IsString()"
in cereal-1.1.2\include\cereal\external\rapidjson\document.h
change this
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
to this
const Ch* GetString() const { if (IsNull_()) return ""; RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
I'm not proposing this should be changed in the cereal source because some people may want strict type checking like the original

No suitable method for adding c++ stl string to C++ rest sdk json object utility string_t

I want to add a string into C++ rest sdk json object. I tried
json::value obj;
obj[L"Login"] = json::value::string();
But the problem is this adds only strings as U("str") and not const std::string.
So I can add as
obj[L"Login"] = json::value::string(U("Login"));
but not do as follows:
json::value obj;
string Login= "login";
obj[L"Login"] = json::value::string(Login);
I am using C++ rest sdk 2.8.0.
Try the following type conversion:
json::value obj;
string Login= "login";
std::wstring_convert<std::codecvt_utf8<wchar_t> > converter;
std::wstring uLogin = converter.from_bytes(Login);
obj[L"Login"] = json::value::string(uLogin);
Better switch all your
std::string
to
std::wstring
objects.
cppRest only works with wide strings, so you will end up converting all over the place...