parse json data in c++ with Qt library - c++

I have exactly following json data as follows:
[
{
"id":"01323",
"name":"Json Roy",
"contacts":[
"CONTACT1=+917673267299",
"CONTACT2=+917673267292",
"CONTACT3=+917673267293",
"CONTACT4=+917673267294",
]
}
]
I want to parse above jsonData data and extract contacts of that data.
QJsonParseError jerror;
QJsonDocument jsonData = QJsonDocument::fromJson(jsonData.c_str(),&jerror);
QJsonArray jsonArray = jsonData.array();
QJsonObject jsonObject = jsonData.object();
foreach (const QJsonValue & value, jsonArray){
string contact=jsonObject["contacts"].toString().toUtf8().constData();
}
can anybody suggest me how can i accomplish this with same above library?

I removed latest comma in the contacts list.
Your mistake is treating QJsonValue as you want but QJsonValue is something like a wrapper so you should convert it to appropriate object ( array, object, string etc. ).
jsonData is not an object sojsonData.object() doesn't give you what you want.
Here is the code, it could be the starting point for you.
#include <QString>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QJsonParseError>
#include <QDebug>
#include <string>
int main(){
auto json_input = R"([
{
"id":"01323",
"name":"Json Roy",
"contacts":[
"CONTACT1=+917673267299",
"CONTACT2=+917673267292",
"CONTACT3=+917673267293",
"CONTACT4=+917673267294"
]
}
])";
QJsonParseError err;
auto doc = QJsonDocument::fromJson( QString::fromStdString( json_input ).toLatin1() , &err );
auto objects = doc.array();
if ( err.error != QJsonParseError::NoError )
{
qDebug() << err.errorString();
return 1;
}
for( auto obj_val : objects )
{
auto obj = obj_val.toObject();
auto contacts = obj.value( "contacts" ).toArray();
for ( auto contact_val : contacts )
{
auto cotact_str = contact_val.toString();
qDebug() << cotact_str;
}
}
}
Output :
CONTACT1=+917673267299
CONTACT2=+917673267292
CONTACT3=+917673267293
CONTACT4=+917673267294

Related

ROS2 reading bag files

I have got a bag file in db3 format and I was trying to read its messages, deserialise them and access their fields. I couldn't find any appropriate document or working example anywhere. I only managed to load the file and display all its message types using the rosbag2_cpp API as follows:
#include <rclcpp/rclcpp.hpp>
#include <tf2_msgs/msg/tf_message.hpp>
#include <ament_index_cpp/get_package_share_directory.hpp>
#include <rosbag2_cpp/readers/sequential_reader.hpp>
#include <rosbag2_cpp/converter_interfaces/serialization_format_converter.hpp>
#include <rosbag2_storage/storage_options.hpp>
int main(int argc, char** argv)
{
(void) argc;
(void) argv;
rclcpp::init(argc, argv);
rclcpp::Node node("test");
rosbag2_storage::StorageOptions storage_options{};
auto file_path = ament_index_cpp::get_package_share_directory("test")
+ "/data/rosbag_autoware_receiver_0.db3";
storage_options.uri = file_path;
storage_options.storage_id = "sqlite3";
rosbag2_cpp::ConverterOptions converter_options{};
converter_options.input_serialization_format = "cdr";
converter_options.output_serialization_format = "cdr";
rosbag2_cpp::readers::SequentialReader reader;
reader.open(storage_options, converter_options);
const auto topics = reader.get_all_topics_and_types();
for (const auto topic : topics)
RCLCPP_INFO(node.get_logger(), topic.name.c_str());
return 0;
}
Any hint, help or guide on reading the actual messages and deserialising them is much appreciated.
Regards
What you're looking for is the has_next() property.
Declare a msg variable of the type(s) you're looking for (such as sensor_msgs::msg::Image msg), and deserialize as following:
while (reader.has_next())
{
// serialized data
auto serialized_message = reader.read_next();
rclcpp::SerializedMessage extracted_serialized_msg(*serialized_message->serialized_data);
auto topic = serialized_message->topic_name;
if (topic.find("whatever...") != std::string::npos)
{
serialization_info.deserialize_message(&extracted_serialized_msg, &msg);
}
}

Write in JSON file - Data not inserted in the correct order

I am creating a desktop app using QT C++ that take a text file and convert it to JSON File like this example:
{
"102": {
"NEUTRAL": {
"blend": "100"
},
"AE": {
"blend": "100"
}
},
"105": {
"AE": {
"blend": "100"
},
"NEUTRAL": {
"blend": "100"
}
}
}
This is the code I am using:
for (int i = 0; i < output_list1.size(); i++) {
if (output_list1[i] == "-") {
c_frame++;
continue;
}
if (output_list1[i] != "NEUTRAL") {
QJsonObject neutralBlendObject;
neutralBlendObject.insert("blend", "100");
QJsonObject phonemeObject;
phonemeObject.insert("NEUTRAL", neutralBlendObject);
QJsonObject keyBlendObject;
keyBlendObject.insert("blend", output_list1[i].split(' ')[1]);
phonemeObject.insert(output_list1[i].split(' ')[0], keyBlendObject);
mainObject.insert(QString::number(c_frame), phonemeObject);
}
c_frame++;
}
jsonDoc.setObject(mainObject);
file.write(jsonDoc.toJson());
file.close();
As you can see, I am inserting the NEUTRAL object first but I am getting data not in the correct order, somtimes NEUTRAL is the the first following with the next object and somtimes not.
How can I correct this issue?
In JSON there are two structures you can use for saving data:
1.) JSON Objects: A collection of key/value pairs. This collection is NOT ordered. In various languages its realized via associative data structures like dictionaries, hash tables etc. Internally qt saves JSON objects via QHash<QString, QVariant> containers.
2.) JSON Arrays: An ordered list of values (which can be JSON Objects). In programming languages this is realized as an array/vector/whatever. Qt uses a QVariantList (QList<QVariant) internally.
I did resolve it using rapidjson library instead of QJsonObject
Based on this example
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
#include "rapidjson/filewritestream.h"
#include <string>
#include "RapidJson/prettywriter.h"
using namespace rapidjson;
using namespace std;
FILE* fp = fopen("output.json", "wb"); // non-Windows use "w"
char writeBuffer[65536];
FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));
Document d;
d.SetObject();
rapidjson::Document::AllocatorType& allocator = d.GetAllocator();
size_t sz = allocator.Size();
d.AddMember("version", 1, allocator);
d.AddMember("testId", 2, allocator);
d.AddMember("group", 3, allocator);
d.AddMember("order", 4, allocator);
Value tests(kArrayType);
Value obj(kObjectType);
Value val(kObjectType);
string description = "a description";
//const char *description = "a description";
//val.SetString()
val.SetString(description.c_str(), static_cast<SizeType>(description.length()), allocator);
obj.AddMember("description", val, allocator);
string help = "some help";
val.SetString(help.c_str(), static_cast<SizeType>(help.length()), allocator);
obj.AddMember("help", val, allocator);
string workgroup = "a workgroup";
val.SetString(workgroup.c_str(), static_cast<SizeType>(workgroup.length()), allocator);
obj.AddMember("workgroup", val, allocator);
val.SetBool(true);
obj.AddMember("online", val, allocator);
tests.PushBack(obj, allocator);
d.AddMember("tests", tests, allocator);
// Convert JSON document to string
PrettyWriter<FileWriteStream> writer(os);
char indent = ' '; // single space x 4
writer.SetIndent(indent, 4);
d.Accept(writer);
Thank you all for your time

Apache arrow - read serialized VectorSchemaRoot to C++

I have a Java library that is writing an Arrow Table to a VectorSchemaRoot object in memory. Those serailized bytes are available to me in a std::string object in C++. How do I de-serialize and read the data?
Java:
try (final ArrowStreamWriter arrowStreamWriter
= new ArrowStreamWriter(vectorSchemaRoot, provider, outputStream)) {
arrowStreamWriter.start();
arrowStreamWriter.writeBatch();
arrowStreamWriter.end();
return buffer.byteArray();
}
C++
std::string bytes;
???
Assuming you've writen a RecordBatch, I think you can read it back this way:
#include <arrow/api.h>
#include <arrow/ipc/writer.h>
#include <arrow/io/memory.h>
// ...
std::shared_ptr<arrow::io::BufferReader> bufferReader = std::make_shared<arrow::io::BufferReader>(bytes);
std::shared_ptr<arrow::ipc::RecordBatchStreamReader> reader = arrow::ipc::RecordBatchStreamReader::Open(bufferReader.get()).ValueOrDie();
std::shared_ptr<arrow::RecordBatch> recordBatchBack = reader->Next().ValueOrDie();
std::cout << recordBatchBack->num_rows() << std::endl;
Here's an end to end test in c++:
#include <arrow/api.h>
#include <arrow/ipc/writer.h>
#include <arrow/ipc/reader.h>
#include <arrow/io/memory.h>
BOOST_AUTO_TEST_CASE(RecordBatchStreamReaderTest) {
arrow::Int32Builder builder;
builder.Append(1);
builder.Append(2);
builder.Append(3);
auto schema = arrow::schema({arrow::field("hello", arrow::int32())});
auto structArray = arrow::StructArray::Make({builder.Finish().ValueOrDie()}, {"hello"}).ValueOrDie();
auto recordBatch = arrow::RecordBatch::FromStructArray(structArray).ValueOrDie();
auto outputStream = arrow::io::BufferOutputStream::Create().ValueOrDie();
auto writer = arrow::ipc::MakeStreamWriter(outputStream.get(), schema).ValueOrDie();
writer->WriteRecordBatch(*recordBatch);
writer->Close();
auto buffer = outputStream->Finish().ValueOrDie();
std::string bytes = buffer->ToString();
std::shared_ptr<arrow::io::BufferReader> bufferReader = std::make_shared<arrow::io::BufferReader>(bytes);
std::shared_ptr<arrow::ipc::RecordBatchStreamReader> reader = arrow::ipc::RecordBatchStreamReader::Open(bufferReader.get()).ValueOrDie();
std::shared_ptr<arrow::RecordBatch> recordBatchBack = reader->Next().ValueOrDie();
std::cout << recordBatchBack->num_rows() << std::endl;
}

QJson data serialization order

I have implemented a code that will take input from QLineEdit and the data will be saved in a json file format.
void MainWindow::fileWriteOperationJson()
{
QString filename = "C:/Users/.../Documents/Qt/save.json";
QFile saveFile(filename);
saveFile.open(QIODevice::WriteOnly|QIODevice::Text);
if (!saveFile.open(QIODevice::WriteOnly))
{
qWarning("Couldn't open save file.");
}
QJsonObject obj; //this is the root
QJsonArray personalData;
QJsonObject json;
json["name"] = ui->nameLineEdit->text();
json["address"] = ui->addressLineEdit->toPlainText();
personalData.append(json);
obj["personalData"] = personalData;
QTextStream out(&saveFile);
out << QJsonDocument(obj).toJson(QJsonDocument::Indented);
}
Problem: When I open the json file, I want to find my data in the below format:
"name" = xyz
"address" = xyz
But, I am having result like this,
"address" = xyz
"name" = xyz
How to get this intended order?
JSON (JavaScript Object Notation) is a lightweight data-interchange format and as such, the structure is important, but the order of items is not.
If you need to print the items in a specific order, you'll need to extract them from Json into suitable data structures and handle that yourself.
Alternatively, you could save to a different format, but note that Qt's XML will act the same as Json. Perhaps a CSV may be more useful to you.
Qt generates JSON data with keys sorted alphabetically. AFAIK, there is no option to get around it. You could try encapsulating objects with a single key/value pair into an array, though, and preserve the order:
[
{"address": xyz},
{"name": xyz}
]
Or you could try using a different storage format altogether.
The underlying problem is that QMap does not have an ordered form.
Here's a possible solution by subclassing QVariantMap:
#ifndef ORDEREDVARIANTMAP_H
#define ORDEREDVARIANTMAP_H
#include <QtCore>
class OrderedVariantMap : public QMap<QString, QVariant> {
// Test:
// OrderedVariantMap test_map;
// test_map.insert("xxx", 1);
// test_map.insert("aaa", 2);
// test_map.insert("kkk", 3);
// test_map["321"] = 4;
// test_map["000"] = 5;
// test_map["123"] = 6;
// qDebug() << "QMap.keys()" << test_map.keys();
// qDebug() << "QMap.orderedKeys()" << test_map.orderedKeys();
// QVariant test_variant;
// test_variant.setValue(test_map);
// qDebug() << "test_variant.typeName()" << test_variant.typeName();
// OrderedVariantMap test_map_recovered = qvariant_cast<OrderedVariantMap>(test_variant);
// qDebug() << "test_map_recovered.orderedKeys()" << test_map_recovered.orderedKeys();
// Test results:
// QMap.keys() ("000", "123", "321", "aaa", "kkk", "xxx")
// QMap.orderedKeys() ("xxx", "aaa", "kkk", "321", "000", "123")
// test_variant.typeName() OrderedVariantMap
// test_map_recovered.orderedKeys() ("xxx", "aaa", "kkk", "321", "000", "123")
public:
OrderedVariantMap ( );
~OrderedVariantMap ( );
void
clear ( );
void // QMap::iterator
insert ( const QString &key,
const QVariant &value );
QVariant&
operator[] ( const QString &key );
const QVariant
operator[] ( const QString &key ) const;
const QString
orderedKey ( int index ) const;
const QVariant
orderedValue ( int index ) const;
QStringList
orderedKeys ( ) const ;
private:
QStringList Ordered_Keys;
protected:
};
Q_DECLARE_METATYPE(OrderedVariantMap)
#endif // ORDEREDVARIANTMAP_H
and
#include "OrderedVariantMap.h"
OrderedVariantMap::OrderedVariantMap ( ) : QMap ( ) {
}
OrderedVariantMap::~OrderedVariantMap ( ) {
}
QStringList
OrderedVariantMap::orderedKeys ( ) const {
return Ordered_Keys;
}
void
OrderedVariantMap::clear ( ) {
Ordered_Keys.clear();
QMap::clear();
}
void // QMap::iterator
OrderedVariantMap::insert ( const QString &key,
const QVariant &value ) {
Ordered_Keys.append(key);
QMap::insert(key, value);
}
QVariant&
OrderedVariantMap::operator[] ( const QString &key ) {
Ordered_Keys.append(key);
return QMap::operator [](key);
}
const QVariant
OrderedVariantMap::operator[] ( const QString &key ) const {
return this->value(key);
}
const QString
OrderedVariantMap::orderedKey ( int index ) const {
return Ordered_Keys[index];
}
const QVariant
OrderedVariantMap::orderedValue ( int index ) const {
return this->value(Ordered_Keys[index]);
}
More functionality could be provided, for example an ordered iterator.

Sorting through an object vector and creating subvectors

I just deleted an earlier post with a similar question because my example was not very clear, So I am trying again.
I have created a simple class called SportsSchedules.cpp The class stores 4 items; sportType, TeamName, city and number of wins. I have created a "sports vector" of SportsSchedules objects. I want to run the sportsVector through a loop and for each sport type I want to create a new vector. Each created sub vector should contain only the unique sportType.
Ideally, this sportsVector would run in a loop and would pop each object into its repsective subVector until it was empty(I guess)
Here is the code from my main:
#include <iostream>
#include "SportsSchedules.h"
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <functional>
bool sportType( std::string type);
int main (int argc, const char * argv[])
{
SportsSchedules *theSport;
theSport = new SportsSchedules("Football", "Chicago", "Bears", 7);
std::vector<SportsSchedules*> *sportsVector = new std::vector<SportsSchedules*>();
sportsVector->push_back(theSport);
theSport = NULL;
theSport = new SportsSchedules("Football", "Chicago", "Bears", 7);
sportsVector->push_back(theSport);
theSport = NULL;
theSport = new SportsSchedules("Baseball", "Boston", "RedSox", 62);
sportsVector->push_back(theSport);
theSport = NULL;
theSport = new SportsSchedules("Football", "GreenBay", "Packers", 15);
sportsVector->push_back(theSport);
theSport = NULL;
theSport = new SportsSchedules("Basketball", "Portland", "Trailblazers", 60);
sportsVector->push_back(theSport);
theSport = NULL;
theSport = new SportsSchedules("Football", "Seattle", "Seahawks", 7);
sportsVector->push_back(theSport);
theSport = NULL;
theSport = new SportsSchedules("Baseball", "Oakland", "A's", 67);
sportsVector->push_back(theSport);
std::cout<<"Test the SportsSchedules Vector "<<std::endl;
std::vector<SportsSchedules*>::iterator itr;
for(itr = sportsVector->begin(); itr != sportsVector->end(); ++itr ){
std::cout<<(*itr)->getSportType()<<" "<<(*itr)->getCity()<<" "<<(*itr)->getTeamName()<<" "
<<(*itr)->getNumWins()<<std::endl;
}
return 0;
}
bool trackType( std::string type){
SportsSchedules * sptPtr;
if(sptPtr->getSportType()== type)
return true;
else
return false;
}
The bool function was from an earlier attempt to try remove_copy_if. I kept getting a compiler error about no int pointer or function pointer. Not sure if that what I need as it creates a blue print of all the vector indexes. I want something that would push - pop if possible Someone also suggested using map or multi map but I didn't quite understand it
Thanks
Someone suggested you a map because they are associative containers. Ie. instead of looking for a certain value using a positional index (0, 1, 2, ...) you look up using an arbitrary value, which can be a string, for example.
So, how can it be useful for you? See this example:
#include <map>
#include <string>
#include <vector>
#include <iostream>
int main() {
std::map< std::string, std::vector<SportsSchedules*> > uniques;
// Initialization code here...
std::vector<SportsSchedules*>::iterator itr;
for(itr = sportsVector->begin(); itr != sportsVector->end(); ++itr ) {
uniques[(*itr)->getSportType()].push_back((*itr));
}
return 0;
}
uniques[(*itr)->getSportType()] retrieves from uniques a std::vector<SportsSchedules*> indexed by the value of (*itr)->getSportType(). If the key doesn't exist in the map (first time you see the sport in the sportsVector), it will create a new one before doing it - otherwise, you get the previously created vector.
To retrieve the info once it's there, you can either look it up by name:
std::vector<SportsSchedules*> vec = uniques["Football"];
or iterating over it to get the (key, value) pairs. Have a look to map's API for more info.