This should be simple (I'm just learning boost so I'm missing something)
I have read in some simple JSON using json_read and now have a ptree. All the examples on the web show using ptree.get("entry_name") to obtain an entry. All I want to do is something like:
ptree pt;
read_json(ss,pt);
BOOST_FOREACH(ptree::value_type &v, pt)
{
std::cout << v.{entry_name} << v.{value}
}
i.e. loop through the ptree and write out each name (i.e. what you put into pt.get()) and it's corresponding value.
Sorry if this is simple
Ross
I was searching the same thing, and couldn't find the answer anywhere. It turned out to be pretty simple indeed:
ptree pt;
/* load/fill pt */
for(iterator iter = pt.begin(); iter != pt.end(); iter++)
{
std::cout << iter->first << "," << iter->second.data() << std::endl;
}
iter->first is the entry name, and iter->second.data() is the entry value of the first level. (You can then re-iterate with iter->second.begin()/end() for deeper levels.)
Further, if one such node in this iteration is not a terminal node and is itself a ptree, you can get that as ptree from this iterator itself :
ptree subPt = iter->second.get_child("nodeName");
I'm having troubles with ptree as well, but perhaps this can help:
Check out boost's ptree quick tutorial
v.{entry_name}
would be
v.first
and
v.{value}
v.second.data()
Would that work?
Here's a great example of how to iterate a ptree using BOOST_FOREACH
http://akrzemi1.wordpress.com/2011/07/13/parsing-xml-with-boost/
for direct access using the normal "get" functions look at the example from boost:
http://www.boost.org/doc/libs/1_51_0/doc/html/boost_propertytree/tutorial.html
the documentation page is located here:
http://www.boost.org/doc/libs/1_51_0/doc/html/boost/property_tree/basic_ptree.html
I know its not very well documented but it is helpful.
Old thread, but here's a C++11 version of mr_georg's answer with range-based for loops:
ptree pt;
/* load/fill pt */
for(auto pair : pt)
{
std::cout << pair.first << "," << pair.second.data() << std::endl;
}
For this json:
{
"key1":"value1",
"key2":"value2"
}
It outputs:
key1,value1
key2,value2
This example iterates over a simple JSON object and puts its values into a vector.
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
int main (void)
{
try
{
std::stringstream ss;
std::string json_obj_str = "{ \"unit_1\": 1, \"unit_2\": 2, \"unit_3\": 3 }";
std::vector <float> fvec;
ss << json_obj_str; // put string into stringstream
boost::property_tree::ptree pt;
boost::property_tree::read_json(ss, pt); // put stringstream into property tree
// iterate over JSON properties
for (boost::property_tree::ptree::iterator iter = pt.begin(); iter != pt.end(); iter++)
{
std::cout << iter->first << ": " << iter->second.data() << std::endl;
fvec.push_back(boost::lexical_cast<float>(iter->second.data()));
}
for (size_t i = 0; i < fvec.size(); i++)
{
std::cout << "fvec.at(" << i << ") = " << fvec.at(i) << std::endl;
}
}
catch (const boost::property_tree::ptree_error &e)
{
std::cerr << "property_tree error = " << e.what() << std::endl;
return -2;
}
catch (std::exception const& e)
{
std::cerr << "exception = " << e.what() << std::endl;
return -1;
}
return 0;
}
Related
I'm trying to write a program that creates a structure for student info, has an array with 4 students info, writes the info to a text file, and returns the information back from the text file. I'm also supposed to do the same process with binary I/O, but that part works well so I took it out of the code. My issue is with the text file. I believe the issue is with the name part of the array. I also have the guideline to follow: "Do not use the string class in your struct definition. Instead, use the old c-style string (i.e. array of char)" I can't figure out how to get the program to step over the space between first/last names. This is the code I have written:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstring>
using namespace std;
/* structure */
struct studentInfo
{
char name[40];
int age;
float gpa;
char grade;
};
int main(int argc, const char * argv[])
{
const int SIZE = 4;
int i;
/* array */
studentInfo student[SIZE]{ {"Ann Annson\0", 10, 1.10, 'D'},
{"Bill Billson\0", 20, 2.20, 'C'},
{"Carl Carlson\0", 30, 3.30, 'B'},
{"Don Donson\0", 40, 4.00, 'A'} };
/* open & write to file in text mode i/o */
fstream fFile;
fFile.open("students.txt", ios::out);
for(i = 0; i < SIZE; i++)
{
fFile << student[i].name << endl;
fFile << student[i].age << endl;
fFile << student[i].gpa << endl;
fFile << student[i].grade << endl;
}
fFile.close();
/* open and read information from files to new arrays */
studentInfo studentsText[4];
fFile.open("students.txt", ios::in);
for(i = 0; i < SIZE; i++)
{
fFile >> studentsText[i].name;
fFile >> studentsText[i].age;
fFile >> studentsText[i].gpa;
fFile >> studentsText[i].grade;
}
fFile.close();
/* display the information from students.txt */
cout << "This is the data contained in students.txt: " << endl;
for (i = 0; i < SIZE; i++)
{
cout << studentsText[i].name << "\t" << studentsText[i].age;
cout << "\t" << studentsText[i].gpa << "\t" << studentsText[i].grade << endl;
}
return 0;
}
this is the output that I receive when I run the program:
screenshot
and this is the output I'm trying to get:
screenshot
I do know that it is an issue regarding the space, because if I run the program with the spaces between the names in the array removed it returns this output: screenshot
Forgive me if this is a poor question, I'm in my first semester of c++ and I hope that I worded this well for anyone that attempts to help. Thank you to everyone who looks at this and tries to help!
side note
this is the full code I have written
and this is the output I receive when running that code
// created a copy of CNode and added the new value
CNode *copyCNode = new CNode;
//memcpy(c, iNode->mainNode->cNode, sizeof(*(iNode->mainNode->cNode)) );
memcpy(copyCNode, iNode->mainNode->cNode, sizeof(CNode) );
CNode *updated_cnode = inserted(copyCNode, b, index);
std::cout << "temporay CNode created : " << updated_cnode->branch[index]->sNode->value << std::endl;
if(memcmp(copyCNode, iNode->mainNode->cNode, sizeof(CNode)) == 0){
std::cout << "mainNode is not changed " << std::endl ;
}else{
std::cout << "mainNode is changed" << std::endl;
}
bool cas_ret = __sync_bool_compare_and_swap(&iNode->mainNode->cNode, copyCNode, updated_cnode);
std::cout << "return cas_ret : " << cas_ret << std::endl;
if(cas_ret){
std::cout << "New added value " << iNode->mainNode->cNode->branch[index]->sNode->value << std::endl;
return 0; // successfully attached the node
}
else{
return 1;
}
The above code is part of my code base.
There is no compilation error and the code is running fine.
But __sync_bool_compare_and_swap function always return false in my code. Even before the CAS function call I did the memory comparison (memcpy) and its showing that both the arguments are equal, in that case CAS should swap the value with third argument, but it is not.
copyCNode -> Holds the copy value of iNode->mainNode->cNode
updated_cnode -> Holds the updated value of iNode->mainNode->cNode (New branch added)
Please suggest any solution.
Thanks
The CAS operation failed because: iNode->mainNode->cNode ≠ copyCNode. It doesn't matter that their contents are both the same. The CAS operation is trying to do:
if (iNode->mainNode->cNode == copyCNode) {
iNode->mainNode->cNode = updated_cnode;
return true;
}
return false;
All you verified is that *copyCnode = *iNode->mainNode->cNode, which is not what the CAS operation is interested in.
I got the solution.
I think I should not create the memory for copyNode. Instead, I should just copyNode = iNode->mainNode->cNode and the rest code is working good.
Thanks #jxh
I'm learning about libexpat. I cobbled together this example for basic familiarity using the API:
The Code:
#include <stdio.h>
#include <expat.h>
#include <string.h>
#include <iostream>
void start(void* userData, const char* name, const char* argv[])
{
std::cout << "name: " << name << std::endl;
int i = 0;
while (argv[i])
{
std::cout << "argv[" << i << "] == " << argv[i++] << std::endl;
}
}
void end(void* userData, const char* name)
{
}
void value(void* userData, const char* val, int len)
{
char str[len+1];
strncpy(str, val, len);
str[len] = '\0';
std::cout << "value: " << str << std::endl;
}
int main(int argc, char* argv[], char* envz[])
{
XML_Parser parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, start, end);
XML_SetCharacterDataHandler(parser, value);
int bytesRead = 0;
char val[1024] = {};
FILE* fp = fopen("./catalog.xml", "r");
std::cout << "fp == 0x" << (void*)fp << std::endl;
do
{
bytesRead = fread(val, 1, sizeof(val), fp);
std::cout << "In while loop bytesRead==" << bytesRead << std::endl;
if (0 == XML_Parse(parser, val, bytesRead, (bytesRead < sizeof(val))))
{
break;
}
}
while (1);
XML_ParserFree(parser);
std::cout << __FUNCTION__ << " end" << std::endl;
return 0;
}
catalog.xml:
<CATALOG>
<CD key1="value1" key2="value2">
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<YEAR>1995</YEAR>
</CD>
</CATALOG>
Makefile:
xml: xml.o
g++ xml.o -lexpat -o xml
xml.o: main.cpp Makefile
g++ -g -c main.cpp -o xml.o
Output:
fp == 0x0x22beb50
In while loop bytesRead==148
name: CATALOG
value:
value:
name: CD
argv[1] == key1
argv[2] == value1
argv[3] == key2
argv[4] == value2
value:
value:
name: TITLE
value: Empire Burlesque
value:
value:
name: ARTIST
value: Bob Dylan
value:
value:
name: YEAR
value: 1995
value:
value:
value:
In while loop bytesRead==0
main end
Question:
From the output, it appears that the callback I installed with XML_SetCharacterDataHandler() gets called twice for the CATALOG,, CD, TITLE, and ARTIST xml tags, and then multiple times for the YEAR tag - can someone explain this behavior? From the noted catalog.xml, it's not clear to me why there are (or would ever be) multiple values associated with any XML tags.
Thank you.
Citation:
Credit to this site for the basis of the above sample code.
The expat parser may split text nodes into multiple calls to the character data handler. To properly handle text nodes you must accumulate text over multiple calls and process it when receiving the "end" event for the containing tag.
This is true in general, even across different parsers and different languages -- i.e. the same thing is true in Java.
See for instance http://marcomaggi.github.io/docs/expat.html#using-comm
A common first–time mistake with any of the event–oriented interfaces to an XML parser is to expect all the text contained in an element to be reported by a single call to the character data handler. Expat, like many other XML parsers, reports such data as a sequence of calls; there's no way to know when the end of the sequence is reached until a different callback is made.
Also from the expat documentation
A single block of contiguous text free of markup may still result in a sequence of calls to this handler. In other words, if you're searching for a pattern in the text, it may be split across calls to this handler.
I am using the dladdr from libld (http://linux.die.net/man/3/dladdr) to get a trace of the function calls. Here it is minimal example with a single traced element:
#include<iostream>
#include <dlfcn.h> // link with -ldl -rdynamic a
void f(){
void **frame = static_cast<void **>(__builtin_frame_address(0));
void **bp = static_cast<void **>(*frame);
void *ip = frame[1];
Dl_info info;
dladdr(ip, &info);
std::cout << info.dli_sname << " " << info.dli_fname << " " << info.dli_saddr << std::endl;
ip = bp[1];
bp = static_cast<void**>(bp[0]);
dladdr(ip, &info);
std::cout << info.dli_sname << " " << info.dli_fname << " " << info.dli_saddr << std::endl;
}
int main(){
f();
}
which outputs:
main ./a.out 0x402800
__libc_start_main /lib64/libc.so.6 0x7febf6bf2610
that is, Dl_info has the traced function name, the compiled file where it belongs and some address (0x7f...) described in the man page as "Exact address of symbol named".
This address has information of the source file location (from where the function has been called). In fact with the help of some utility I can get that information:
$ addr2line -e a.out
/home/user/test.cpp:34
(give the exact line where main is defined in source file). And this works as long as the program was compiled with the -g option.
Now what I want is to extract this information programmaticaly. Supposedly, this is possible with the BFD library.
This is my attempt, based on BFD examples found for example here: http://opensource.apple.com/source/X11libs/X11libs-40.2/cairo/cairo-1.8.6/util/backtrace-symbols.c
1) first I have to define a function find_addr_sect that will be called by bfd_map_over_sections (through a pointer) later.
static void find_addr_sect(bfd *abfd, asection *section, void *obj){
bfd_data *data = (bfd_data *)obj;
bfd_vma vma;
bfd_size_type size;
if (data->found)
return;
if (!(bfd_get_section_vma(abfd, section)))
return;
vma = bfd_get_section_vma(abfd, section);
if (data->pc < vma)
return;
size = bfd_get_section_size(section);
if (data->pc >= vma + size)
return;
data->found = bfd_find_nearest_line(abfd, section, syms,
data->pc - vma,
&data->filename,
&data->function,
&data->line);
}
2) I put the code directing inside the function (this replaces the function void f() above.
void f(){
void **frame = static_cast<void **>(__builtin_frame_address(0));
void **bp = static_cast<void **>(*frame);
void *ip = frame[1];
Dl_info info;
dladdr(ip, &info);
std::cout << info.dli_sname << " " << info.dli_fname << " " << info.dli_saddr << std::endl;
////////////////////
// this will try to find the location of main (first in the stack)
bfd *abfd = bfd_openr(info.dli_fname, NULL); assert(abfd); // the executable file is opened successfully
// bfd_data data;
bfd_map_over_sections(abfd, find_addr_sect, nullptr); // !! doesn't call `find_addr_sect` at all.
///////////////////
ip = bp[1];
bp = static_cast<void**>(bp[0]);
dladdr(ip, &info);
std::cout << info.dli_sname << " " << info.dli_fname << " " << info.dli_saddr << std::endl;
}
Sadly, I am stuck here because the bfd_map_over_sections call doesn't do anything. I am using bfd_map_over_sections in the wrong way, why?
Sorry for using C++, in this is a C question. It shortens most of my code and I am more used to it.
EDIT: I added this lines and I can confirm that one clue of the problem is that the number of sections is zero.
unsigned int numSections = -1;
numSections = bfd_count_sections(abfd);
std::cout << "num sections " << numSections << std::endl; // gives "0"
I looked for more examples, it seems that I was missing two things, calling the function bfd_check_format after opening and also populating and passing the address information in the bfd_data structure.
...
bfd *abfd = bfd_openr(info.dli_fname, NULL); assert(abfd);
// char **matching;
// bfd_data data;// = (bfd_data *)obj;
if (!bfd_check_format (abfd, bfd_object)){
bfd_close (abfd); assert(0);
}
...
later bfd_data variable is used as input and output of the find_addr_sect. Therefore
...
bfd_data data;// = (bfd_data *)obj;
data.pc = (bfd_hostptr_t)info.dli_saddr;
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
...
And now it works.
Good day. I could really use your help on this one. I have a stats text file in the following format.
ID=1000000
Name=Name1
Field1=Value1
...(Fields 2 to 25)
Field26=Value26
ID=1000001
Name=Name2
Field1=Value1
...(Fields 2 to 25)
Field26=Value26
ID=1000002
Name=Name2
Field1=Value1
...(Fields 2 to 25)
Field26=Value26
...goes up to 15000
I have an active people text file separated by line breaks.
Name2
Name5
Name11
Name12
...goes up to 1400 Random Names
I need to be able to delete records from the stats text file (ID, Name, Fields1 to 26) if the name is not found in the active people text file. In the example above, the associated record for Name1(ID, Name, Fields1 to 26) should be deleted since it's not in the active people text file.
I've tried reformatting the stats file through notepad++ using TextFX->Quick->Find/Replace to convert it to a comma separated file with each record separated by a line break. I had it rearranged to
ID Name Field1 ...Fields2 to Fields 25... Field26
1000000 Name1 Value1 ...Value2 to Value 25... Value26
1000001 Name2 Value1 ...Value2 to Value 25... Value26
1000002 Name2 Value1 ...Value2 to Value 25... Value26
I've opened it with excel and I've created two tables (stats table and a active names table) in mysql using the csv file file. I'm not sure how to process this in an automatic function. Besides removing inactive records, the other problem I have is rewriting it back to its old format.
I've been trying my best to figure this out for a hours on end. Is there a solution that won't require me to use find, copy, paste and switch between the two files 1400 times? Unfortunately, I have to keep the stats file in this format.
Please help. Thank you.
Here's a C++ program that will process the files for you:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <locale>
#include <set>
#include <string>
#include <vector>
//trim functions taken:
//http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring/217605#217605
//with a slight change because of trouble with ambiguity
static int myIsSpace(int test)
{
static std::locale loc;
return std::isspace(test,loc);
}
static std::string &rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(myIsSpace))).base(), s.end());
return s;
}
static std::string <rim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(myIsSpace))));
return s;
}
static std::string &trim(std::string &s) {return ltrim(rtrim(s));}
int main(int argc,char * argv[])
{
std::ifstream peopleFile;
peopleFile.open("people.txt");
if (!peopleFile.is_open()) {
std::cout << "Could not open people.txt" << std::endl;
return -1;
}
std::set<std::string> people;
while (!peopleFile.eof()) {
std::string somePerson;
std::getline(peopleFile,somePerson);
trim(somePerson);
if (!somePerson.empty()) {
people.insert(somePerson);
}
}
peopleFile.close();
std::ifstream statsFile;
statsFile.open("stats.txt");
if (!statsFile.is_open()) {
std::cout << "could not open stats.txt" << std::endl;
return -2;
}
std::ofstream newStats;
newStats.open("new_stats.txt");
if (!newStats.is_open()) {
std::cout << "could not open new_stats.txt" << std::endl;
statsFile.close();
return -3;
}
size_t totalRecords=0;
size_t includedRecords=0;
bool firstRecord=true;
bool included=false;
std::vector<std::string> record;
while (!statsFile.eof()) {
std::string recordLine;
getline(statsFile,recordLine);
std::string trimmedRecordLine(recordLine);
trim(trimmedRecordLine);
if (trimmedRecordLine.empty()) {
if (!record.empty()) {
++totalRecords;
if (included) {
++includedRecords;
if (firstRecord) {
firstRecord=false;
} else {
newStats << std::endl;
}
for (std::vector<std::string>::iterator i=record.begin();i!=record.end();++i) {
newStats << *i << std::endl;
}
included=false;
}
record.clear();
}
} else {
record.push_back(recordLine);
if (!included) {
if (0==trimmedRecordLine.compare(0,4,"Name")) {
trimmedRecordLine=trimmedRecordLine.substr(4);
ltrim(trimmedRecordLine);
if (!trimmedRecordLine.empty() && '='==trimmedRecordLine[0]) {
trimmedRecordLine=trimmedRecordLine.substr(1);
ltrim(trimmedRecordLine);
included=people.end()!=people.find(trimmedRecordLine);
}
}
}
}
}
if (!record.empty()) {
++totalRecords;
if (included) {
++includedRecords;
if (firstRecord) {
firstRecord=false;
} else {
newStats << std::endl;
}
for (std::vector<std::string>::iterator i=record.begin();i!=record.end();++i) {
newStats << *i << std::endl;
}
included=false;
}
record.clear();
}
statsFile.close();
newStats.close();
std::cout << "Wrote new_stats.txt with " << includedRecords << " of the " << totalRecords << ((1==totalRecords)?" record":" records") << "found in stats.txt after filtering against the " << people.size() << ((1==people.size())?" person":" people") << " found in people.txt" << std::endl;
return 0;
}