0

I am working on a c++ project where I need to compare two or more Json string that will be passed to me as arguments in a function and i have to return a bool accordingly. I am using Jsoncpp but I am unable to compare the entirety of the two Json datas. I want to know the best procedure to loop in the key and value and check the value with corresponding value of another json string (both String will be passed to the function and will be parsed using reader.parse() of jsoncpp and then i need to compare them both and return the bool value). Can anyone help me with this please? thank you in advance. The place where I am stuck:

class test {
public:
static bool isequalstring(const std::string &item1, const std::string 
&item2, const std::string &temp) {

    Document d1;
    d1.Parse(item1.c_str());
    Document d2;
    d2.Parse(item2.c_str());

    Document d3;
    d3.Parse(temp.c_str());


    bool matched = true;
    //itr= iterate through the third json to get the keys and match the keys in first and second
    for (auto itr = d3.MemberBegin(); itr != d3.MemberEnd(); itr++) {

        if (d1.HasMember(itr->name) && d2.HasMember(itr->name)) {       // if the member doesn't exist in both, break
            if (d1[itr->name] != d2[itr->name]) {
                // value doesn't match, then break
                matched = false;

                break;

            }

        } else {
            matched = false;
            break;
        }
    }
    return matched;
}
  };
bool testDeepNestedJson_should_succeed(){
bool expectedTestResult = true;
bool testResult;

// Input 1 JSON Object
const char* input1 = "{\"array\":[1,2,3],\"boolean\":true,\"null\":null,\"number\":123,\"object\":{\"a\":\"b\",\"c\":\"d\",\"e\":\"f\"},\"string\":\"Hello World\",\"object_array\":[{\"key\":\"value1\"},{\"key\":\"value2\"},{\"key\":\"value3\"}],\"deep_nested_array\":[{\"object_array\":[{\"key\":\"value1\"},{\"key\":\"value2\"},{\"key\":\"value3\"}]},{\"object_array\":[{\"key\":\"value4\"},{\"key\":\"value5\"},{\"key\":\"value6\"}]}]}";
const char* input2 = "{\"array\":[1,2,3],\"justsomedata\":true,\"boolean\":true,\"null\":null,\"object\":{\"a\":\"b\",\"c\":\"d\",\"e\":\"f\"},\"number\":123,\"object_array\":[{\"key\":\"value1\"},{\"key\":\"value2\"},{\"key\":\"value3\"}],\"deep_nested_array\":[{\"object_array\":[{\"key\":\"value1\"},{\"key\":\"value2\"},{\"key\":\"value3\"}]},{\"object_array\":[{\"key\":\"value4\"},{\"key\":\"value5\"},{\"key\":\"value6\",\"ignoreme\":12346}]}],\"string\":\"Hello World\"}";
const char* stencil = "{\"array\":[null],\"boolean\":null,\"null\":null,\"object\":{\"a\":null,\"c\":null,\"e\":null},\"number\":null,\"object_array\":[{\"key\":null}],\"deep_nested_array\":[{\"object_array\":[{\"key\":null}]}],\"string\":null}";

testResult = test::isequalstring(input1, input2, stencil);

if(testResult != expectedTestResult){
    std::cout<<"testDeepNestedJson_should_succeed:"<<std::endl;
    std::cout<<"Item1:"<<input1<<std::endl;
    std::cout<<"Item2:"<<input2<<std::endl;
    std::cout<<"Stencil:"<<stencil<<std::endl;

    std::cout<<"Test Failed result is: False expected was: True"<<std::endl;

    return false;
}

std::cout<<"PASSED: testDeepNestedJson_should_succeed"<<std::endl;

return true;
}
int main() {
testDeepNestedJson_should_succeed();
return 0;
}
Bishal Sahoo
  • 71
  • 2
  • 11
  • Welcome to StackoverFlow. Please [take the tour](https://stackoverflow.com/tour), read about [how to ask good questions](https://stackoverflow.com/help/how-to-ask) and learn about [how to create a Minimal, Complete and Verifiable Example](https://stackoverflow.com/help/mcve). – Gaurang Dave Apr 13 '18 at 03:24
  • If you are flexible in using RapidJson, you can compare using `==` after parsing – Wander3r Apr 13 '18 at 04:30
  • Its showing error as it says "Cant compare structures". Can you show me a sample on the above code, will be posting a reference for you. – Bishal Sahoo Apr 13 '18 at 04:38
  • Test cases: isEqualItem({id: 1, name: "test", randomNo: 1}, {id: 1, name: "test", randomNo: 1}, {id: null, name: null, randomNo: null}) //shoult assert true isEqualItem({id: 1, name: "test", randomNo: 1}, {id: 1, name: "test", randomNo: 2}, {id: null, name: null, randomNo: null}) //shoult assert false isEqualItem({id: 1, name: "test", randomNo: 1}, {id: 1, name: "test", randomNo: 3}, {id: null, name: null}) //shoult assert true – Bishal Sahoo Apr 13 '18 at 04:38
  • `bool operator ==(const Json::value&, const Json::Value)` exist, so `root1 == root2` should do the job. – Jarod42 Apr 13 '18 at 08:12
  • will it function according to the Test case provided ? It will be helpful if you can show me a reference please because operator== has not been able to compare the entire json – Bishal Sahoo Apr 13 '18 at 08:38
  • You can edit your question instead of writing hard to read json in comment. – Jarod42 Apr 13 '18 at 11:18
  • 1
    [bool Json::Value::operator== (const Value & other) const](http://jsoncpp.sourceforge.net/class_json_1_1_value.html#14363dda23a6ae2def9afd1590ae85d3) – Jarod42 Apr 13 '18 at 11:19
  • You parse `item1` to `root`, `item2` to `root1` and `temp` to `root2`. You could be more consistent in naming things. – el.pescado - нет войне Apr 16 '18 at 10:12
  • What's the purpose of `temp`. I assume you want to compare values of `item1` and `item2` assigned to keys provided in `temp`, right? – el.pescado - нет войне Apr 16 '18 at 10:14
  • yes thats right. – Bishal Sahoo Apr 16 '18 at 13:15

2 Answers2

0

Using RapidJSON, the code would be something like this

#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include <iostream>


using namespace rapidjson;


//({ id: 1, name : "test", randomNo : 1 }, { id: 1, name : "test", randomNo : 1 }, { id: null, name : null, randomNo : null }) //shoult assert true 
//isEqualItem({id: 1, name: "test", randomNo: 1}, {id: 1, name: "test", randomNo: 2}, {id: null, name: null, randomNo: null}) //shoult assert false 
//isEqualItem({id: 1, name: "test", randomNo: 1}, {id: 1, name: "test", randomNo: 3}, {id: null, name: null}) //shoult assert true

bool is_same(const std::string& s1, const std::string& s2, const std::string& s3) {

    Document d1;
    d1.Parse(s1.c_str());
    Document d2;
    d2.Parse(s2.c_str());

    Document d3;
    d3.Parse(s3.c_str());

    bool matched = true;
    // iterate through the third json to get the keys and match the keys in first and second
    for (Value::ConstMemberIterator itr = d3.MemberBegin(); itr != d3.MemberEnd(); itr++) {
        if (d1.HasMember(itr->name) && d2.HasMember(itr->name)) {       // if the member doesn't exist in both, break
            if (d1[itr->name] != d2[itr -> name]) {                     // value doesn't match, then break
                matched = false;
                break;
            }
        }
        else {
            matched = false;
            break;
        }
    }
    return matched;
}

int main() {
    // 1. Parse a JSON string into DOM.
    const char* json = "{\"id\":1,\"name\":\"test\",\"randomNo\":1}";
    const char* json2 = "{\"id\":1,\"name\":\"test\",\"randomNo\":2}";
    const char* keys = "{\"id\":\"null\",\"name\":\"null\"}";


    if (is_same(json, json2,keys)) {
        std::cout << "Both are same" << std::endl;
    }
    return 0;
}
Wander3r
  • 1,801
  • 17
  • 27
  • @BishalSahoo Ok. I understood now why the third `temp` is there, check the edit – Wander3r Apr 13 '18 at 06:30
  • @BishalSahoo it's unclear as to what you are asking here.. the above code does check each and every key. If the value should match with third json as well, then adjust the if condition accordingly – Wander3r Apr 13 '18 at 07:07
  • @bishalsahoo `itr` is an iterator for third json document. `itr` will have `name` (key) and `value` as members. `itr->name` refers to key like `random` or `id` in your example – Wander3r Apr 13 '18 at 07:42
  • The Code seems to built but every output is true.Might be you can have a look – Bishal Sahoo Apr 16 '18 at 09:11
  • @BishalSahoo it's returning `true` and `false` as expected for the test cases you posted. Which test case if failing? – Wander3r Apr 16 '18 at 09:36
  • @BishalSahoo check the edit on full code with `main` – Wander3r Apr 16 '18 at 09:37
  • libraryTest: /home/mavericks/CLionProjects/libraryTest/include/rapidjson/document.h:1162: rapidjson::GenericValue::ConstMemberIterator rapidjson::GenericValue::MemberEnd() const [with Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>; rapidjson::GenericValue::ConstMemberIterator = rapidjson::GenericMemberIterator, rapidjson::MemoryPoolAllocator<> >]: Assertion `IsObject()' failed. Process finished with exit code 134 (interrupted by signal 6: SIGABRT) – Bishal Sahoo Apr 16 '18 at 09:57
  • @BishalSahoo is this compiler error? if not, why not debug and find which test case it's failing. Please understand that the above code is written with keeping your test cases in mind and if you have more test cases that are failing, you should be able to debug and improvise. – Wander3r Apr 16 '18 at 11:55
  • I am facing some issue with a certain json comparison . I tried to debug , even though both the json are equal its showing they are not can you help me with that please – Bishal Sahoo Apr 18 '18 at 06:44
  • It will be a great help If you can have a look @Sailesh D – Bishal Sahoo Apr 18 '18 at 07:11
  • @BishalSahoo I don't know all the test cases that you have and where it would be failing. Debugging this should be straightforward as it's a one loop function iterating over each key. Have you tried outputting the `itr->name` when it's failing to match? It will show the key name that failed the test case – Wander3r Apr 18 '18 at 08:50
  • Yes I have tried that with itr->name.GetString(); but they are same just it has a value that doesnt meant to be compared(not in the template). They object_array,deep_nested_array please have a look according to your code@Sailesh D – Bishal Sahoo Apr 18 '18 at 09:06
  • I got the problem as the code just gets the key and compare the value , so when it is an array it compares all the value even though some keys in the sub array need not to be matched , so the code should enter the array and loop to get key and match the value. the code need some work to make it effective @Sailesh D – Bishal Sahoo Apr 19 '18 at 03:34
0

You could iterate over root2, get name of keys using name(), access values with that names in root and root1 using operator[], and compare them using operator==:

for (auto it = root2.begin(); it != root2.end(); ++it) {
    auto name = it.name();
    if (root[name] != root1[name])
        return false;
}
return true;

BTW. You parse item1 to root, item2 to root1 and temp to root2. You could be more consistent in naming things.