How to create json using rapidjson::Writer without creating document in C++? - c++

I am trying to create json using rapidjson::Writer without creating document but it just give json text but don't create full json output like below,
{ "data": { "dataIn": { "hello":"world", "t":true, "f":false }, "dataOut": { "n":null, "i":123, "pi":3.1416 } } }
On rapidjson documents as well not enough info given. Can please help with it. How I can achieve this?

On rapidjson documents as well not enough info given. Can please help with it. How I can achieve this? - That is not true if I correctly understood your intentions.
At RapidJSON:Sax look for paragraph Writer - example given there is almost the same as the one you're asking for.
I wrote It myself to check if it is working .. and it is:
#include <iostream>
#include <rapidjson/writer.h>
// {
// "data":
// {
// "dataIn":
// {
// "hello":"world",
// "t":true,
// "f":false
// },
// "dataOut":
// {
// "n":null,
// "i":123,
// "pi":3.1416
// }
// }
// }
int main(int argc, char** argv)
{
rapidjson::StringBuffer lStringBuffer;
rapidjson::Writer lWriter(lStringBuffer);
lWriter.StartObject();
lWriter.Key("data");
lWriter.StartObject();
lWriter.Key("dataIn");
lWriter.StartObject();
lWriter.Key("hello");
lWriter.String("world");
lWriter.Key("t");
lWriter.Bool(true);
lWriter.Key("f");
lWriter.Bool(false);
lWriter.EndObject();
lWriter.Key("dataOut");
lWriter.StartObject();
lWriter.Key("n");
lWriter.Null();
lWriter.Key("i");
lWriter.Int(123);
lWriter.Key("pi");
lWriter.Double(3.1416);
lWriter.EndObject();
lWriter.EndObject();
lWriter.EndObject();
std::cout << lStringBuffer.GetString() << std::endl;
return 0;
}
The output is:
{"data":{"dataIn":{"hello":"world","t":true,"f":false},"dataOut":{"n":null,"i":123,"pi":3.1416}}}
But if you want to get such a JSON string you might also use raw strings like:
std::string lRawString = R"(
{
"data":
{
"dataIn":
{
"hello":"world",
"t":true, "f":false
},
"dataOut":
{
"n":null,
"i":123,
"pi":3.1416
}
}
}
)";
and then pass it to rapidjson::Document:
rapidjson::Document lDocument;
lDocument.Parse(lRawString.c_str());

Related

clang-format: empty line before and after control statements

Is there any possibility to achieve inserting an empty line before and after control statemets (for, if etc.)?
E.g. I have the following source code:
if(bCondition)
{
// some code
}
for(int i : vecOfInts)
{
// some code
}
if(bAnotherCondition)
{
// some code
}
and this is what I want:
if(bCondition)
{
// some code
}
for(int i : vecOfInts)
{
// some code
}
if(bAnotherCondition)
{
// some code
}
Reading the official documentation, https://clang.llvm.org/docs/ClangFormatStyleOptions.html , there seems to be no such option.

nlohmann json insert value array partially to already existing data

I have a particular case which I am trying to solve with minimal changes if possible.
one of the data is
js["key1"]["subkey2"]["subsubkey3"].push_back({1,2,3,{4,5}});
[ 1,2,3,[[4,5]] ]
Later at some stage I want to insert
{1,2,3,{4,6}}
Then it should become
[ 1,2,3,[[4,5],[4,6]] ]
How can I make this possible without making 1,2,3 value as key?
I did some playing. I didn't get the results you were looking for. Here's my code and results so far.
#include <iostream>
#include <json.hpp>
using namespace std;
using JSON = nlohmann::json;
int main() {
JSON json = JSON::object();
JSON key1JSON = JSON::object();
JSON key2JSON = JSON::object();
JSON key3JSON = JSON::array();
key3JSON.push_back( {1,2,3, {4,5} } );
key3JSON.push_back( {6} );
key2JSON["subsubkey3"] = key3JSON;
key1JSON["subkey2"] = key2JSON;
json["key1"] = key1JSON;
cout << json.dump(2) << endl;
}
Output:
{
"key1": {
"subkey2": {
"subsubkey3": [
[
1,
2,
3,
[
4,
5
]
],
[
6
]
]
}
}
}
You'll see that the first push_back pushed an array inside an array, which is probably one level deeper than you wanted, and the second one added a second array, which is also not what you want.
Which means you're probably going to have to write your own method, especially as you want to also handle uniqueness. I personally never free-format data that way you have in your example. But maybe your method would look something like:
bool contains(const JSON &json, const JSON &value) {
... this looks like fun to write.
}
void appendUnique(JSON &json, const JSON &array) {
for (JSON & thisJson: array) {
if (!contains(json, thisJson)) {
json.push_back(thisJson);
}
}
}
I modified my code like this:
void appendUnique(JSON &json, const JSON & array) {
for (const JSON & thisJSON: array) {
json.push_back(thisJSON);
}
}
...
appendUnique(key3JSON, {1,2,3, {4,5} } );
appendUnique(key3JSON, {6} );
And got this:
{
"key1": {
"subkey2": {
"subsubkey3": [
1,
2,
3,
[
4,
5
],
6
]
}
}
}
I'm not going to write the isUnique method. But I think you may have to take this to conclusion.

How to extract number from json?

I want to extract a specific array from a json file:
{
"status": "OK",
"type": "startVehicle",
"info": {
"idTransit": 36612,
"timestampUTCTransit": {
"epochUTCTransitMS": 1606935562810,
"dateUTCTransit": "2020/12/2",
"hourUTCTransit": "18:59:22.810"
},
"timestampUTCReported": {
"epochUTCReportedMS": 1606935562810,
"dateUTCReported": "2020/12/2",
"hourUTCReported": "18:59:22.810"
},
"road": 0,
"lane": 0,
"xCoordinates": [
143.6,
-456.335
]
}
}
I want extract the values of xCoordinates. This is what I tried:
#include <rapidjson/document.h>
void Vdac::addStart(std::string json_str)
{
Document rjsondoc;
rjsondoc.Parse(json_str.c_str());
if(rjsondoc.HasParseError())
slog.getLogger()->debug("Invalid json");
else
{
auto coordinates = rjsondoc["info"]["xCoordinates"].GetArray();
for(SizeType i=0;i<coordinates.Size();i++)
slog.getLogger()->debug("The start coordinates are: {0:d}",coordinates[i].GetInt());
return;
}
}
But I have an error when the program accesses the value. The error is:
../include/rapidjson/document.h:1737: int rapidjson::GenericValue<Encoding, Allocator>::GetInt() const [with Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>]: Assertion `data_.f.flags & kIntFlag' failed.
How can I extract the value?
Can't give you any help with rapidjson.
But an alternative is ThorsSerializer (note: I wrote it. So take that as you will). But it is designed to be easy to use. With zero (or very little) code that need to be written to parse the JSON into C++ objects.
Note: If you don't want to read a field just remove it.
#include <fstream>
#include "ThorSerialize/Traits.h"
#include "ThorSerialize/JsonThor.h"
struct TimeStamp
{
long epochUTCTransitMS;
std::string dateUTCTransit;
std::string hourUTCTransit;
};
// If you want to read a class then
// Add this declaration with the name of the class and the
// fields you want to read/write in JSON.
ThorsAnvil_MakeTrait(TimeStamp, epochUTCTransitMS, dateUTCTransit, hourUTCTransit);
struct Info
{
long idTransit;
TimeStamp timestampUTCTransit;
TimeStamp timestampUTCReported;
int road;
int lane;
std::vector<double> xCoordinates;
};
ThorsAnvil_MakeTrait(Info, idTransit, timestampUTCTransit, timestampUTCReported, road, lane, xCoordinates);
struct Object
{
std::string status;
std::string type;
Info info;
};
ThorsAnvil_MakeTrait(Object, status, type, info);
int main()
{
std::ifstream data("pl1.data");
Object object;
using ThorsAnvil::Serialize::jsonImporter;
// jsonImporter to read or jsonExporter to write:
data >> jsonImporter(object);
std::cout << object.info.xCoordinates[0] << "\n";
}
Easy to install via brew:
> brew install thors-serializer
Build your code with:
> g++ -std=c++17 <file>.cpp -lThorSerialize17 -lThorsLogging17
Note on new M1 machs you will also need -L /opt/homebrew/lib (still working on that).
All code on github

How to retrieve json value from 3 fields dynamically depends on the parameter being passed

The basic idea is to dynamically retrieve the value of 3 fields in the main function from the Config.json, namely Id, Encoding, Signature depends on the Id being passed.
First of all, in the Config.json file:
Depends on the id, different selection will be applied
e.g. if Id 509 is passed:
{
"Id": 509,
"Encoding": "NO-ENCODING",
"Signature": "X509"
}
will be applied.
Config.json
{
"SchemaIdForUsage":509,
"Schema":[
{
"Id":100,
"Encoding":"NO-ENCODING",
"Signature":"MD5"
},
{
"Id":509,
"Encoding":"NO-ENCODING",
"Signature":"X509"
}
]
}
I have used below code to parse JSON from the Config.json:
test.cpp
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int getfile()
{
string line;
ifstream myfile("E:\\config.json");
if (myfile.is_open())
{
while (myfile.good())
{
getline(myfile, line);
cout << line << endl;
}
myfile.close();
}
else cout << "Unable to open file";
system("pause");
return 0;
}
int main()
{
getfile();
return 0;
}
JSON library
https://github.com/mrtazz/restclient-cpp
Hopefully, I've made myself clear as a novice in C++.
I am wondering what's a better approach to retrieve those 3 fields value dynamically from the JSON file depends on the Id being passed. Thank you for your help.
Updated Response: using the restclient library to parse JSON
I used below code to try to retrieve JSON
std::ifstream file_input("E:\\test.txt");
Json::Reader reader;
Json::Value root;
reader.parse(file_input, root);
std::cout<<root["Id"];
Json::Value testing = root["Schema"]["Id"];
In the Debugger
I am trying to get the value of the fields Id eg :100, Encoding eg "NO-ENCODING"
There's error shows unhandled error
Any idea would be greatly appreciated. Thank you,

Poco C++ building nested JSON objects

I have a nested JSON object. I'm trying to build it in a function and add the inner object to the original, but I can't extract the result.
void build_object (Poco::JSON::Object * const result)
{
/* Construct some int/bool/string fields here */
Poco::JSON::Object inner;
inner.set("some_number", 5);
inner.set("some_string", "xyz");
/* This is where it breaks down */
std::string key = "new_object";
result->set("new_object", inner);
/* Then some debugging and testing */
// The new object is printed inside the first -> seems like it's working
result->stringify(std::cout);
printf("result has(key): %i\n", result->has(key)); // true
printf("isObject: %i\n", result->isObject(key)); // false - huh?
printf("isNull: %i\n", result->isNull(key)); // false
printf("isArray: %i\n", result->isArray(key)); // false
Poco::JSON::Object::Ptr ptr = result->getObject(key);
// unsurpisingly fails since the above indicates it's not an object
printf("ptr isNull: %i\n", ptr.isNull()); // true
// ptr->has("some_number"); // throws NullPointerException
// if it's not an object/null/array, it must be a value
Poco::Dynamic::Var v = result->get(key);
// at least one of these things should be true, otherwise what is it?
printf("var isString: %i\n", v.isString()); // false
printf("var isStuct: %i\n", v.isStruct()); // false
printf("var isEmpty: %i\n", v.isEmpty()); // false
printf("var isArray: %i\n", v.isArray()); // false
printf("var isSigned: %i\n", v.isSigned()); // false
printf("var isNumeric: %i\n", v.isNumeric());// false
}
So, I have an inner object that is correctly put into the result, it is being printed via stringify with all the correct values and result->has() is successful. But, according to the result, it is not an object, array, or null, so you should be able to get it with var. But, once it's gotten from var, it's not a string, struct, array, or number, and it's also not empty. The inner object seems to exist and not exist at the same time.
So, how do I put this object into my result? And how do I get it out?
Thanks
note: I've seen this thread Correct usage of Poco C++ JSON for parsing data, but it's building the JSON object from string and then parsing it. I suppose I could build everything as a string and convert to the Poco Object at the last step, but I'm still curious why the above is happening. Also, using result->set() and result->get() are a cleaner, less hack-y solution than going through a string.
References: Poco JSON Doc,
Poco Dynamic Var Doc
Poco::JSON Objects and Arrays are held as shared pointers internally by default (optimization to avoid values copying) and everything is Dynamic::Var, so it works for both pointers and values. When you insert an Object as value it works because Dynamic::Var will hold pretty much anything, but the problem you experience when inspecting it comes from the fact that internal comparison does not return true for Object values because it compares only with default type - Poco::SharedPtr<Poco::JSON::Object>.
Here's a workaround:
void build_object (Poco::JSON::Object * const result)
{
// smart pointer, so don't worry about cleaning up
Poco::JSON::Object::Ptr inner = new Poco::JSON::Object;
inner->set("some_number", 5);
inner->set("some_string", "xyz");
std::string key = "new_object";
result->set(key, inner);
printf("isObject: %i\n", result->isObject(key)); // true
}
I have opened a github issue to alleviate this caveat.
I have been trying to create json file having nested object using poco library. Finally able to do with Poco::Json::Array.
Please find the posted code sinippet. Hope it will help. Json output attached with post.
#include "Poco\JSON\JSON.h"
#include "Poco\JSON\Stringifier.h"
#include "Poco\JSON\Object.h"
#include "Poco\Dynamic\Var.h"
using namespace std;
using Poco::JSON::Stringifier;
using Poco::JSON::Object;
using Poco::JSON::Array;
void makeJsonNestedObject()
{
Object RootObj(true);
Array FLArray;
for(int i=0; i<3; i++)
{
Object::Ptr FirstLevelArrayNode = new Poco::JSON::Object(true);
TCHAR strNameBuff[15];
_stprintf(strNameBuff, _T("%s_%d"),_T("Servername"),i);
std::basic_string<TCHAR> strName = strNameBuff;
FirstLevelArrayNode->set("HostName", strName);
FirstLevelArrayNode->set("Overall Impact", "Dummy Data");
Array SLArray;
for(int j=0; j<3;j++)
{
Object::Ptr SecondLevelArrayNode = new Poco::JSON::Object(true);
TCHAR attr1NameBuff[15];
TCHAR attr2NameBuff[15];
_stprintf(attr1NameBuff, _T("%s_%d"),_T("AttrOne"),j);
_stprintf(attr2NameBuff, _T("%s_%d"),_T("AttrTwo"),j);
std::basic_string<TCHAR> attr1Name = attr1NameBuff;
std::basic_string<TCHAR> attr2Name = attr2NameBuff;
SecondLevelArrayNode->set("Attribute", attr1Name);
SecondLevelArrayNode->set("SubAttribute", attr2Name);
Poco::Dynamic::Var obj(SecondLevelArrayNode);
SLArray.add(obj);
}
FirstLevelArrayNode->set("Attribute_Details",SLArray);
Poco::Dynamic::Var FLArrayNodeobj(FirstLevelArrayNode);
FLArray.add(FLArrayNodeobj);
}
std::ostringstream os;
std::cout <<"before stringlify.." << std::endl;
FLArray.stringify(os, 2);
std::cout << os.str() << std::endl;
}
Json output:
[
{
"HostName" : "Servername_0",
"Overall Impact" : "Dummy Data",
"Attribute_Details" : [
{
"Attribute" : "AttrOne_0",
"SubAttribute" : "AttrTwo_0"
},
{
"Attribute" : "AttrOne_1",
"SubAttribute" : "AttrTwo_1"
},
{
"Attribute" : "AttrOne_2",
"SubAttribute" : "AttrTwo_2"
}
]
},
{
"HostName" : "Servername_1",
"Overall Impact" : "Dummy Data",
"Attribute_Details" : [
{
"Attribute" : "AttrOne_0",
"SubAttribute" : "AttrTwo_0"
},
{
"Attribute" : "AttrOne_1",
"SubAttribute" : "AttrTwo_1"
},
{
"Attribute" : "AttrOne_2",
"SubAttribute" : "AttrTwo_2"
}
]
},
{
"HostName" : "Servername_2",
"Overall Impact" : "Dummy Data",
"Attribute_Details" : [
{
"Attribute" : "AttrOne_0",
"SubAttribute" : "AttrTwo_0"
},
{
"Attribute" : "AttrOne_1",
"SubAttribute" : "AttrTwo_1"
},
{
"Attribute" : "AttrOne_2",
"SubAttribute" : "AttrTwo_2"
}
]
}
]