C++ convert JSON to XML - c++

I am trying to find a way to convert JSON string to XML document. For this we have evaluated PICOJSON to parse JSON and Pugixml to generate the XML document.
I know this is way easy in .Net and JAVA. My JSON is dynamic and based on the dynamic JSON I have to convert to XML.
I need some starting help on how to achieve this. Below code is sample to Parse JSON
#include <iostream>
#include "include/picojson.h";
#include "include/pugixml.hpp";
using namespace std;
int main() {
const char* json =
"{\"menu\": {"
"\"id\": \"f\","
"\"popup\": {"
" \"menuitem\": ["
" {\"v\": \"0\"},"
" {\"v\": \"1\"},"
" {\"v\": \"2\"}"
" ]"
" }"
"}"
"}";
picojson::value v;
std::string err;
const char* json_end = picojson::parse(v, json, json + strlen(json), &err);
}
I think the initial approach would be to covert JSON String to JSON object(Not sure how to do that) and then recursively construct XML
Will the below code convert JSON string to Object ?
picojson::parse(v, json, json + strlen(json), &err);
if (!err.empty()) {
std::cerr << err << std::endl;
}
Can someone guide me with initial code on how to do it, how to construct XML from JSON ?

If you're willing to use RapidJSON instead, you can make a SAX parser based on this example and map each JSON read event to an homologous XML write operation.
Hint: this probably means keeping a pugi::xml_node currentNode somewhere to keep track of the current node being worked on.
Edit
It seems POCO has SAX-like handlers after all, so you won't even need RapidJSON for this.
And if you want to minimize your dependencies, you can also use POCO.XML instead of pugixml.

Related

CPPRestSDK (casablanca) Extract JSON From Incoming WebSocket Messages (malformed token)

I'm connecting to a WebSocket whom always replies in JSON.
I see there is an extract_string method for websocket_incoming_message however after trying numerous things with json:value it seems as though you can only construct JSON arrays on-the-fly by inserting key-value pairs one-by-one.
Am I missing something here or is there a way to take the output from websocket_incoming_message and directly convert it into a json:value array?
wsClient.set_message_handler([=](websocket_incoming_message msg)
{
// handle message from server...
printf("[WebSocket INBOUND]: %s", msg.extract_string().get().c_str());
printJSON(json::value::parse(conversions::to_string_t(msg.extract_string().get())));
});
printJSON runs through the json::value and prints each key-value-pair.
Unhandled exception at 0x00007FF866923FB8 in RestAPI.exe: Microsoft
C++ exception: web::json::json_exception at memory location
0x0000003E553FDDC0. occurred
Console Output:
[WebSocket INBOUND]:
{"t":null,"s":null,"op":10,"d":{"heartbeat_interval":41250,"_trace":["gateway-prd-main-cr3x"]}}
Even though we can compile and run the application, I figure the exception is being caused due to the fact that were passing a string containing a JSON Table and not a single element? Does this mean I need to manually parse the string and pull out each key-value-pair while simultaneously building the json array?
There must be a way to do this, it seems like basic needed functionality..
A similar unresolved question
Any help here would be greatly appreciated!
Thank you for your time.
Try catching web::json::json_exception and print the message, it may give you a hint about what's wrong
I got the complete solution .please try to use boost pacakges from nuget. The documentation will help you to parse the json data from string. I think jsoncpp is not an updated packages available in the nuget.so please try boost packages available in the nuget.
MYJSON STRING
{"action":"refresh_dashboard","data":{"users_list":[{"user_id":"901e6076ff351cfc2195fb86f8438a26","extensions":["1002"],"name":"Karthik M"},{"user_id":"7d617ef5b2390d081d901b0d5cd108eb","extensions":["1015"],"name":"Synway User2"},{"user_id":"c8f667f7d663e81f6e7fa34b9296f067","extensions":["1012"],"name":"Rahib Video"},{"user_id":"cc3f94ecc14ee9c55670dcde9adc1887","extensions":["1006"],"name":"Rounak S Kiran"},{"user_id":"6c29ebdb34e1761fdf9423c573087979","extensions":["1003"],"name":"Amar Nath"},{"user_id":"8e15c2d95d4325cb07f0750846966be8","extensions":["1011"],"name":"TLS User"},{"user_id":"2fc4142bdacf83c1957bda0ad9d50e3d","extensions":["1014"],"name":"Synway User1"},{"user_id":"74d5b5a9aca1faa4c2f217ce87b621d8","extensions":["1008"],"name":"Robin Raju"},{"user_id":"a7ad7e73bf93ea83c8efdc1723cba198","extensions":["1007"],"name":"Arshad Arif"},{"user_id":"b55146df593ec8d09e5fe12a8a4c1108","extensions":["1001"],"name":"Rahib Rasheed"},{"user_id":"391391de005a8f5403c7b5591f462ea1","extensions":["1013"],"name":"Sangeeth J"},{"user_id":"3258f7ae4ae1db60435cbcf583f64a89","extensions":["1009"],"name":"Aby TL"},{"user_id":"90bc84e5e8a3427fe35e99bd4386de95","extensions":["1010"],"name":"Prince T"},{"user_id":"b501ef5b270a196afc0eed557ca74237","extensions":["1005"],"name":"Jineed AJ"},{"user_id":"1422af351e06adeab2de92f5a633a444","extensions":["1004"],"name":"Ashok PA"}],"busy_users":[],"reg_users":[{"user_id":"901e6076ff351cfc2195fb86f8438a26","status":"registered"},{"user_id":"6c29ebdb34e1761fdf9423c573087979","status":"registered"}],"contacts":[{"owner_id":"901e6076ff351cfc2195fb86f8438a26","status":"ready"},{"owner_id":"6c29ebdb34e1761fdf9423c573087979","status":"ready"}]}}
CODES
client.receive().then([](websocket_incoming_message msg) {
std::cout << "receiving data from socket";
// msg.message_type();
return msg.extract_string();
//1..i have one string
//cout<<"\n///////////test"<< msg.extract_string().get().c_str();
// // 2.convert to json array
//json::value::parse( ::to_string_t(msg.extract_string().get()))
//
}).then([](std::string body) {
//std::cout << "displaying the data";
std::cout << body << std::endl;
std::string ss = body;
ptree pt;
std::istringstream is(ss);
read_json(is, pt);
std::cout <<"\n 1st"<< "action: " << pt.get<std::string>("action") << "\n";
std::cout <<"\n 2nd"<< "data: " << pt.get<std::string>("data") << "\n";
std::cout << "--------------------------------------------------------------";
for (auto& e : pt.get_child("users_list")) {
std::cout << "\n" << "users list " << e.second.get<std::string>("user_id") << "\n";
}
});
useful resources
Parse JSON array as std::string with Boost ptree
C++ boost parse dynamically generated json string (not a file)

Accessing JSON values in C++

I am trying to write a program that navigates your local disc in Unreal Engine for a small application. I have put together a REST server using Gradle, and long story short, I am given a JSON with a machines directories. I want to pull out the specific directories names, to be returned as string (FText specifically, but that not too important here) array.
I found a library created by nLohmann on github (https://github.com/nlohmann/json) which seems to be the best way to handle a JSON in c++. For the life of me, however, I can't figure out how to pull the directory names out. I've tried an iterator and a straightforward .value() call.
The code and a JSON example are below, any insight would be greatly appreciated.
char buffer[1024];
FILE *lsofFile_p = _popen("py C:\\Users\\jinx5\\CWorkspace\\sysCalls\\PullRoots.py", "r");
fgets(buffer, sizeof(buffer), lsofFile_p);
_pclose(lsofFile_p);
std::string rootsJson(buffer);
string s = rootsJson.substr(1);
s = ReplaceAll(s, "'", "");
//here my string s will contain: [{"description":"Local Disk","name":"C:\\"},{"description":"Local Disk","name":"D:\\"},{"description":"CD Drive","name":"E:\\"}]
//These are two syntax examples I found un nlohmann's docs, neither seems to work
auto j = json::parse(s);
string descr = j.value("description", "err");
I think your problem comes from number of \ in your literal string. You need 5 \ for C:\\ : C:\\\\\.
Here is a working example :
#include "json.hpp"
#include <string>
using namespace std;
using json = nlohmann::json;
int main(){
json j = json::parse("[{\"description\":\"Local Disk\",\"name\":\"C:\\\\\"},{\"description\":\"Local Disk\",\"name\":\"D:\\\\\"},{\"description\":\"CD Drive\",\"name\":\"E:\\\\\"}]");
cout << j.is_array() << endl;
for (auto& element : j) {
std::cout << "description : " << element["description"] << " | " << " name : " << element["name"] << '\n';
}
return 0;
}

boost property tree cannot read multiple json data in one file

I really need to get help to decide my problem. I am using boost property tree to parse twitter messages that is stored in json file. All messages are saved in one json file and I need to parse all one by one.
Here is the twitter json data saved in a file. it has 3 different messages. (Below is deducted message only for test)
{"id":593393012970926082,"in_reply_to_status_id":1,"user":{"id":2292380240,"followers_count":2},"retweet_count":0}
{"id":654878454684687878,"in_reply_to_status_id":7,"user":{"id":2292380241,"followers_count":4},"retweet_count":5}
{"id":123487894154878414,"in_reply_to_status_id":343,"user":{"id":2292380242,"followers_count":773},"retweet_count":654}
And here is my C++ code for parsing the message, using property tree.
#include <boost/property_tree/json_parser.hpp>
using namespace std;
using namespace boost::property_tree;
string jsonfile = "./twitter.json";
int main()
{
ptree pt;
read_json( jsonfile, pt );
cout<<"in_reply_to_status_id: "<<pt.get("in_reply_to_status_id",0)<<"\n";
}
I want to get all in_reply_to_status_id values from the file. Now it is printing only the first line value. The result is printing follow.
in_reply_to_status_id: 1
I would like to get all values like below.
in_reply_to_status_id: 1
in_reply_to_status_id: 7
in_reply_to_status_id: 343
How can I get all values from the file.
Please help me. Thank you very much.
You should have right json file, for example like this
[
{"id":593393012970926082,"in_reply_to_status_id":1,"user":{"id":2292380240,"followers_count":2},"retweet_count":0},
{"id":654878454684687878,"in_reply_to_status_id":7,"user":{"id":2292380241,"followers_count":4},"retweet_count":5},
{"id":123487894154878414,"in_reply_to_status_id":343,"user":{"id":2292380242,"followers_count":773},"retweet_count":654}
]
And code should be like this
for (const auto& p : pt)
{
cout << p.second.get("in_reply_to_status_id",0) << endl;
}
Instead of range-based for, you can use BOOST_FOREACH for example.
BOOST_FOREACH(const ptree::value_type& p, pt)
You can see my example, first you should get the child tree, and then parse it. My code:
string str = "{\"key\":[{\"id\":1}, {\"id\":2}]}";
stringstream ss(str);
boost::property_tree::ptree parser, child;
boost::property_tree::json_parser::read_json(ss, parser);
child = parser.get_child("key");
for(auto& p : child)
cout << p.second.get<uint32_t>("id") << endl;
I hope this can help you.

Getting raw string (or bytes) for a double value in rapidjson parsing?

Is there a way to get underlying bytes for a double value while parsing json using rapidjson.
Look at below code:
string temp_json2 = "{\"byte_size\":1000.3}";
rapidjson::Document doc;
doc.Parse<0>(temp_json2.c_str());
rapidjson::Value::ConstMemberIterator iter = doc.MemberBegin();
const rapidjson::Value& key = iter->name;
std::cout << key.GetString() << " = ";
const rapidjson::Value& val = iter->value;
std::cout << val.GetDouble();
I want to get something like
val.GetRawString(); instead of val.GetDouble();
Reason I need this is that I don't want any precision to be lost during conversion. Note that I don't have a choice to modifying json to put quotes around double value.
Looks like it is possible:
{
"hash": "00000000206d413bdd4d020a7df959176440e7b52f120f3416db11cb26aaaa8f",
"bigint": 13671375398414879143589706241811147679151753447299444772946167816777,
"time": "1551597576",
"special": false
}
rapidjson::Document document;
document.Parse<rapidjson::kParseNumbersAsStringsFlag>( JSONmessage );
std::cout << document["hash"].GetString() << std::endl;
std::cout << document["bigint"].GetString() << std::endl;
Source: https://github.com/Tencent/rapidjson/issues/1458
Currently no.
I am working on a "full-precision" parsing option (for quite long time) which can be precisely parse string into double. The double-to-string conversion is already exact using grisu2 algorithm. But if a string cannot be represented by double precisely, it will still lose some precision.
To support your requirement, it may need to add an parsing option, and changing the SAX and DOM interface. If you would like this feature to be implement, please report here for further discussion.

C++: How to extract a string from RapidXml

In my C++ program I want to parse a small piece of XML, insert some nodes, then extract the new XML (preferably as a std::string).
RapidXml has been recommended to me, but I can't see how to retrieve the XML back as a text string.
(I could iterate over the nodes and attributes and build it myself, but surely there's a build in function that I am missing.)
Thank you.
Althoug the documentation is poor on this topic, I managed to get some working code by looking at the source. Although it is missing the xml header which normally contains important information. Here is a small example program that does what you are looking for using rapidxml:
#include <iostream>
#include <sstream>
#include "rapidxml/rapidxml.hpp"
#include "rapidxml/rapidxml_print.hpp"
int main(int argc, char* argv[]) {
char xml[] = "<?xml version=\"1.0\" encoding=\"latin-1\"?>"
"<book>"
"</book>";
//Parse the original document
rapidxml::xml_document<> doc;
doc.parse<0>(xml);
std::cout << "Name of my first node is: " << doc.first_node()->name() << "\n";
//Insert something
rapidxml::xml_node<> *node = doc.allocate_node(rapidxml::node_element, "author", "John Doe");
doc.first_node()->append_node(node);
std::stringstream ss;
ss <<*doc.first_node();
std::string result_xml = ss.str();
std::cout <<result_xml<<std::endl;
return 0;
}
Use print function (found in rapidxml_print.hpp utility header) to print the XML node contents to a stringstream.
rapidxml::print reuqires an output iterator to generate the output, so a character string works with it. But this is risky because I can not know whether an array with fixed length (like 2048 bytes) is long enough to hold all the content of the XML.
The right way to do this is to pass in an output iterator of a string stream so allow the buffer to be expanded when the XML is being dumped into it.
My code is like below:
std::stringstream stream;
std::ostream_iterator<char> iter(stream);
rapidxml::print(iter, doc, rapidxml::print_no_indenting);
printf("%s\n", stream.str().c_str());
printf("len = %d\n", stream.str().size());
If you do build XML yourself, don't forget to escape the special characters. This tends to be overlooked, but can cause some serious headaches if it is not implemented:
< <
> >
& &
" "
&apos; &apos;
Here's how to print a node to a string straight from the RapidXML Manual:
xml_document<> doc; // character type defaults to char
// ... some code to fill the document
// Print to stream using operator <<
std::cout << doc;
// Print to stream using print function, specifying printing flags
print(std::cout, doc, 0); // 0 means default printing flags
// Print to string using output iterator
std::string s;
print(std::back_inserter(s), doc, 0);
// Print to memory buffer using output iterator
char buffer[4096]; // You are responsible for making the buffer large enough!
char *end = print(buffer, doc, 0); // end contains pointer to character after last printed character
*end = 0; // Add string terminator after XML
If you aren't yet committed to Rapid XML, I can recommend some alternative libraries:
Xerces - This is probably the defacto C++ implementation.
XMLite - I've had some luck with this minimal XML implementation. See the article at http://www.codeproject.com/KB/recipes/xmlite.aspx
Use static_cast<>
Ex:
rapidxml::xml_document<> doc;
rapidxml::xml_node <> * root_node = doc.first_node();
std::string strBuff;
doc.parse<0>(xml);
.
.
.
strBuff = static_cast<std::string>(root_node->first_attribute("attribute_name")->value());
Following is very easy,
std::string s;
print(back_inserter(s), doc, 0);
cout << s;
You only need to include "rapidxml_print.hpp" header in your source code.