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.
Related
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.
I need to parse ini file using C++ with boost library. This file contains the multi keys. For example,
[section_1]
key_1=value_1
key_1=value_2
...
key_n=value_n
[section_2]
key1=value_1
key1=value_2
...
key_n=value_1
key_n=value_2
[]
...
[section_n]
...
I tried use the functional of boost library: the function boost::property_tree::ini_parser::read_ini(), but it can't contain the multikey in ini file and return the exception. So I tried use the function boost::program_options::parse_config_file(), but it's not what I need.
What functionality should I use to parse the ini file and for each section I can to get own structure with relevant key values?
Your input is simply not an INI file, as INI files do not permit duplicate values. You can write your own parser, e.g. using the code I wrote here:¹
Cross-platform way to get line number of an INI file where given option was found
If you replace the section_t map
typedef std::map<textnode_t, textnode_t> section_t;
with multimap:
typedef std::multimap<textnode_t, textnode_t> section_t;
you can parse repeated keys:
[section_1]
key_1=value_1
key_1=value_2
key_n=value_n
[section_2]
key1=value_1
key2=value_2
key_n=value_1
key_n=value_2
[section_n]
See full code here: https://gist.github.com/sehe/068b1ae81547b98a3cec02a530f220df
¹ or Learning Boost.Spirit: parsing INI and http://coliru.stacked-crooked.com/view?id=cd1d516ae0b19bd6f9af1e3f1b132211-0d2159870a1c6cb0cd1457b292b97230 and possibly others
A SSCCE that might help you
Live On Coliru
#include <boost/property_tree/ini_parser.hpp>
#include <iostream>
using boost::property_tree::ptree;
int main() {
std::istringstream iss(R"([section_1]
key_1=value_1
key_2=value_2
key_n=value_n
[section_2]
key1=value_1
key2=value_2
key_n=value_n
key_m=value_m
[]
[section_n])");
ptree pt;
read_ini(iss, pt);
for (auto& section : pt) {
std::cout << "[" << section.first << "]\n";
for (auto& key : section.second) {
std::cout << key.first << "=" << key.second.get_value("") << "\n";
}
}
}
Prints
[section_1]
key_1=value_1
key_2=value_2
key_n=value_n
[section_2]
key1=value_1
key2=value_2
key_n=value_n
key_m=value_m
My task is trivial - i just need to parse such file:
Apple = 1
Orange = 2
XYZ = 3950
But i do not know the set of available keys. I was parsing this file relatively easy using C#, let me demonstrate source code:
public static Dictionary<string, string> ReadParametersFromFile(string path)
{
string[] linesDirty = File.ReadAllLines(path);
string[] lines = linesDirty.Where(
str => !String.IsNullOrWhiteSpace(str) && !str.StartsWith("//")).ToArray();
var dict = lines.Select(s => s.Split(new char[] { '=' }))
.ToDictionary(s => s[0].Trim(), s => s[1].Trim());
return dict;
}
Now I just need to do the same thing using c++. I was thinking to use boost::property_tree::ptree however it seems I just can not iterate over ini file. It's easy to read ini file:
boost::property_tree::ptree pt;
boost::property_tree::ini_parser::read_ini(path, pt);
But it is not possible to iterate over it, refer to this question Boost program options - get all entries in section
The question is - what is the easiest way to write analog of C# code above on C++ ?
To answer your question directly: of course iterating a property tree is possible. In fact it's trivial:
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
int main()
{
using boost::property_tree::ptree;
ptree pt;
read_ini("input.txt", pt);
for (auto& section : pt)
{
std::cout << '[' << section.first << "]\n";
for (auto& key : section.second)
std::cout << key.first << "=" << key.second.get_value<std::string>() << "\n";
}
}
This results in output like:
[Cat1]
name1=100 #skipped
name2=200 \#not \\skipped
name3=dhfj dhjgfd
[Cat_2]
UsagePage=9
Usage=19
Offset=0x1204
[Cat_3]
UsagePage=12
Usage=39
Offset=0x12304
I've written a very full-featured Inifile parser using boost-spirit before:
Cross-platform way to get line number of an INI file where given option was found
It supports comments (single line and block), quotes, escapes etc.
(as a bonus, it optionally records the exact source locations of all the parsed elements, which was the subject of that question).
For your purpose, though, I think I'd recomment Boost Property Tree.
For the moment, I've simplified the problem a bit, leaving out the logic for comments (which looks broken to me anyway).
#include <map>
#include <fstream>
#include <iostream>
#include <string>
typedef std::pair<std::string, std::string> entry;
// This isn't officially allowed (it's an overload, not a specialization) but is
// fine with every compiler of which I'm aware.
namespace std {
std::istream &operator>>(std::istream &is, entry &d) {
std::getline(is, d.first, '=');
std::getline(is, d.second);
return is;
}
}
int main() {
// open an input file.
std::ifstream in("myfile.ini");
// read the file into our map:
std::map<std::string, std::string> dict((std::istream_iterator<entry>(in)),
std::istream_iterator<entry>());
// Show what we read:
for (entry const &e : dict)
std::cout << "Key: " << e.first << "\tvalue: " << e.second << "\n";
}
Personally, I think I'd write the comment skipping as a filtering stream buffer, but for those unfamiliar with the C++ standard library, it's open to argument that would be a somewhat roundabout solution. Another possibility would be a comment_iterator that skips the remainder of a line, starting from a designated comment delimiter. I don't like that as well, but it's probably simpler in some ways.
Note that the only code we really write here is to read one, single entry from the file into a pair. The istream_iterator handles pretty much everything from there. As such, there's little real point in writing a direct analog of your function -- we just initialize the map from the iterators, and we're done.
I am trying to parse this XML Yahoo feed.
How do i like get each record into an array in C++
like create a structure
then got those variable
and record each element inside the structure.
In the first place, how do i get the value out
Thanks
You may want to see if the given page offers output in a JSON format. Then you can simply request the value instead of messing around with HTML. The Yahoo! Finance site may even offer an API that you can use to easily request the value.
If you want to mess with html code:
#include <iostream>
#include <fstream>
int main() {
std::ifstream ifile("in.html");
std::string line;
std::string ndl("<span id=\"yfs_l10_sgdmyr=x\">");
while(ifile.good()){
getline(ifile, line);
if (line.size()) {
size_t spos, epos;
if ((spos = line.find(ndl)) != std::string::npos) {
spos += ndl.size();
if ((epos = line.find(std::string("</span>"), spos)) != std::string::npos) {
std::cout << line.substr(spos, epos-spos) << std::endl;
}
}
}
}
return 0;
}
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:
< <
> >
& &
" "
' '
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.