sscanf with double quotes - c

I'm using an Arduino and Open Weather Map API to create a weather station, but I'm having serious trouble to parse the response into something useful with sscanf.
Here is one response example:
{"coord":{"lon":-0.13,"lat":51.51},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],"base":"cmc stations","main":{"temp":14.17,"pressure":1012,"humidity":74,"temp_min":13,"temp_max":15.8},"wind":{"speed":4.6,"deg":150},"clouds":{"all":0},"dt":1459602835,"sys":{"type":1,"id":5091,"message":0.0059,"country":"GB","sunrise":1459575095,"sunset":1459622222},"id":2643743,"name":"London","cod":200}
I would like to parse the weather info (Clear) from:
"weather":[{"id":800,"main":"Clear",
And the temp info (14) from:
"main":{"temp":14.17,
This is the code, I'm using:
if (character == '}') { // Just a delimiter
if (strstr(response, "\"weather\":[{")) { // to confirm that the string was found
sscanf(response, ",main\":%s,", weather);
Serial.printfn("\r\nfound weather = %s"), weather;
}
else if (strstr(response, "\"main\":{\"temp\":")) { // to confirm that the string was found
sscanf(response, "temp\":%2s,", temp);
Serial.printfn("\r\nfound temp = %s"), temp;
}
memset(response, 0, sizeof(response));
idx = 0;
}
But the sscanf seens to not even beeing working, since it always print the whole weather / temp strings 32 bytes long.
found weather = ,"weather":[{"id":800,"main":"Clear","description":
found temp = ],"base":"cmc stations","main":{"temp":14.17,"pressure":1011,"humi
Anyone have any clue how to parse these string using sscanf?

Here is an example. Translate it to any C-Dialect you need.
#include <cstdio>
#include <cstring>
#include <iostream>
const char* haystack = "\"weather\":[{\"id\":800,\"main\":\"Clear\",";
const char* needle = "\"main\":";
int main()
{
std::cout << "Parsing string: '" << haystack << "'\n";
if (const char* cursor = strstr(haystack, needle)) {
char buffer[100];
if (sscanf(cursor, "\"main\":\"%99[^\"]\",", buffer))
std::cout << "Parsed string: '" << buffer << "'\n";
else
std::cout << "Parsing error!\n";
} else {
std::cout << "Could not find '" << needle << "' in '" << haystack << "'\n";
}
}

if Serial.printfn is a pointer to a function which work like printf(), then
Serial.printfn("\r\nfound weather = %s"), weather;
is undefined Behavior, and may print what you see.
you should use
Serial.printfn("\r\nfound weather = %s", weather);

Related

Writing c-style string to text file and returning information from text file

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

XML CharacterDataHandler callback unpextedly called multiple times

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.

Recover location information from trace using bfd

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.

SQLite in C and supporting REGEXP

I'm using sqlite3 in C and I'd like to add support for the REGEXP operator. By default, a user defined function regexp() is not present and calling REGEXP will usually result in an error (according to the SQLite pages).
How do I add a regexp function to support REGEXP? Presumably I will do this via the sqlite3_create_function call, but I don't know what the application-defined regexp() will look like.
Can I use a function from regex.h with sqlite3_create_function and how? Any function I pass to SQLite has to take three arguments of type sqlite3_context*, int, sqlite3_value**. However, the SQLite documents don't seem to explain the meaning of these parameters.
Is there sample code for a C regexp() function?
I've not been able to find much on this using Google or the SQLite pages.
You can also try this:
#include <regex.h>
...
void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
int ret;
regex_t regex;
char* reg = (char*)sqlite3_value_text(values[0]);
char* text = (char*)sqlite3_value_text(values[1]);
if ( argc != 2 || reg == 0 || text == 0) {
sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
return;
}
ret = regcomp(&regex, reg, REG_EXTENDED | REG_NOSUB);
if ( ret != 0 ) {
sqlite3_result_error(context, "error compiling regular expression", -1);
return;
}
ret = regexec(&regex, text , 0, NULL, 0);
regfree(&regex);
sqlite3_result_int(context, (ret != REG_NOMATCH));
}
...
sqlite3_create_function(*db, "regexp", 2, SQLITE_ANY,0, &sqlite_regexp,0,0)
It would look something like this:
static void user_regexp(sqlite3_context *context, int argc, sqlite3_value **argv)
{
struct re_pattern_buffer buffer;
const char *out;
char *pattern;
char *input_string;
char *result;
struct re_registers regs;
if ((sqlite3_value_type(argv[0]) != SQLITE_TEXT )
|| ((sqlite3_value_type(argv[1]) != SQLITE_TEXT ))
{
sqlite3_result_err("Improper argument types");
return;
}
re_set_syntax(RE_SYNTAX_POSIX_EGREP);
memset(&buffer, 0, sizeof (buffer));
if (!(pattern = strdupa(sqlite3_value_text(argv[0])))
|| !(input_string = strdupa(sqlite3_value_text(argv[1]))))
{
sqlite3_result_err_nomem("Could not allocate memory for strings");
return;
}
if ((out = re_compile_pattern(pattern, strlen(pattern), &buffer))
{
sqlite3_result_err("Could not compile pattern!");
return;
}
if (re_match(&buffer, input_string, strlen(input_string), 0, &regs) < 0)
sqlite3_result_int64(context, 0);
else
{
result = strndupa(input_string + regs.start[0], regs.end[0] - regs.start[0]);
sqlite3_result_text(context, result, NULL, SQLITE_TRANSIENT);
}
}
Okay, a bit too late for this but I'm tempted to post this for all people who are using a C++ Wrapper for the C SQLITE API like the [ SQLiteCpp ] which I am using. This answer assumes that you use SQLiteCpp.
Install Regex for windows binaries from [ here ]. This gives you just enough files ie the regex.h include file and regex2.dll. Do remember to add the path regex.h in your project and have a copy of the dll in the folder containing client executables.
Before building the [ SQLiteCpp ], we need to make some changes to add the regex capabilities to SELECT queries. For this open the Database.cpp file from the [ SQLiteCpp ] project and
Include the regex.h header from the Regex for windows
After all the includes, add below ( of course you can customize to custom fit your needs!) piece of code just below it.
extern "C" {
void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
int ret;
regex_t regex;
char regtext[100];
char* reg = (char*)sqlite3_value_text(values[0]);
sprintf(regtext, ".*%s.*", reg);
//printf("Regtext : %s", regtext);
char* text = (char*)sqlite3_value_text(values[1]);
/* printf("Text : %s\n", text);
printf("Reg : %s\n", reg); */
if (argc != 2 || reg == 0 || text == 0) {
sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
return;
}
ret = regcomp(&regex, regtext, REG_EXTENDED | REG_NOSUB | REG_ICASE);
if (ret != 0) {
sqlite3_result_error(context, "error compiling regular expression", -1);
return;
}
ret = regexec(&regex, text, 0, NULL, 0);
/* if (ret == 0) {
printf("Found a match. Press any key to continue");
getc(stdin);
}*/
regfree(&regex);
sqlite3_result_int(context, (ret != REG_NOMATCH));
}
}
Now it is time to change the constructors defined in the file. Change those like shown below.
// Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
Database::Database(const char* apFilename,
const int aFlags /*= SQLite::OPEN_READONLY*/,
const int aBusyTimeoutMs/* = 0 */,
const char* apVfs/*= NULL*/) :
mpSQLite(NULL),
mFilename(apFilename)
{
const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs);
//std::cout << "Reached here";
//sqlite3_create_function_v2(mpSQLite, "REGEXP", 2, SQLITE_ANY,&sqlite_regexp, NULL, NULL, NULL,NULL);
sqlite3_create_function(mpSQLite, "regexp", 2, SQLITE_ANY, 0, &sqlite_regexp, 0, 0);
if (SQLITE_OK != ret)
{
const SQLite::Exception exception(mpSQLite, ret); // must create before closing
sqlite3_close(mpSQLite); // close is required even in case of error on opening
throw exception;
}
else {
}
if (aBusyTimeoutMs > 0)
{
setBusyTimeout(aBusyTimeoutMs);
}
}
// Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
Database::Database(const std::string& aFilename,
const int aFlags /* = SQLite::OPEN_READONLY*/,
const int aBusyTimeoutMs/* = 0*/,
const std::string& aVfs/* = "" */) :
mpSQLite(NULL),
mFilename(aFilename)
{
const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str());
sqlite3_create_function(mpSQLite, "regexp", 2, SQLITE_ANY, 0, &sqlite_regexp, 0, 0);
if (SQLITE_OK != ret)
{
const SQLite::Exception exception(mpSQLite, ret); // must create before closing
sqlite3_close(mpSQLite); // close is required even in case of error on opening
throw exception;
}
if (aBusyTimeoutMs > 0)
{
setBusyTimeout(aBusyTimeoutMs);
}
}
By now, you've some serious regex capabilities with your sqlite. Just build the project.
Write a client program to test the functionality. It can be something like below ( borrowed without shame from SQLiteCpp Example ).
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <SQLiteCpp/SQLiteCpp.h>
#include <SQLiteCpp/VariadicBind.h>
// Notice no sqlite3.h huh?
// Well, this is a C++ wrapper for the SQLITE CAPI afterall.
#ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
namespace SQLite
{
/// definition of the assertion handler enabled when SQLITECPP_ENABLE_ASSERT_HANDLER is defined in the project (CMakeList.txt)
void assertion_failed(const char* apFile, const long apLine, const char* apFunc, const char* apExpr, const char* apMsg)
{
// Print a message to the standard error output stream, and abort the program.
std::cerr << apFile << ":" << apLine << ":" << " error: assertion failed (" << apExpr << ") in " << apFunc << "() with message \"" << apMsg << "\"\n";
std::abort();
}
}
#endif
/// Get example path
static inline std::string getExamplePath()
{
std::string filePath(__FILE__);
return filePath.substr(0, filePath.length() - std::string("Client.cpp").length());
}
/// Example Database
static const std::string filename_example_db3 = getExamplePath() + "/example.db3";
/// Image
static const std::string filename_logo_png = getExamplePath() + "/logo.png";
/// Object Oriented Basic example
class Example
{
public:
//Constructor
Example() :
mDb(filename_example_db3),
// User change the db and tables accordingly
mQuery(mDb, "SELECT id,name FROM lookup WHERE name REGEXP :keyword")
// Open a database file in readonly mode
{
}
virtual ~Example()
{
}
/// List the rows where the "weight" column is greater than the provided aParamValue
void namehaskeyword(const std::string searchfor)
{
std::cout << "Matching results for " << searchfor << "\n";
// Bind the integer value provided to the first parameter of the SQL query
mQuery.bind(1,searchfor); // same as mQuery.bind(1, aParamValue);
// Loop to execute the query step by step, to get one a row of results at a time
while (mQuery.executeStep())
{
std::cout<<mQuery.getColumn(0) << "\t" << mQuery.getColumn(1) << "\n";
}
// Reset the query to be able to use it again later
mQuery.reset();
}
private:
SQLite::Database mDb; ///< Database connection
SQLite::Statement mQuery; ///< Database prepared SQL query
};
int main()
{
// Using SQLITE_VERSION would require #include <sqlite3.h> which we want to avoid: use SQLite::VERSION if possible.
// std::cout << "SQlite3 version " << SQLITE_VERSION << std::endl;
std::cout << "SQlite3 version " << SQLite::VERSION << " (" << SQLite::getLibVersion() << ")" << std::endl;
std::cout << "SQliteC++ version " << SQLITECPP_VERSION << std::endl;
try
{
// Doing a regex query.
Example example;
char wannaquit = 'n';
std::string keyword;
// Deliberate unlimited loop. You implement something sensible here.
while (wannaquit != 'y') {
// Demonstrates the way to use the same query with different parameter values
std::cout << "Enter the keyword to search for : ";
std::getline(std::cin, keyword);
example.namehaskeyword(keyword);
}
}
catch (std::exception& e)
{
std::cout << "SQLite exception : " << e.what() << std::endl;
return EXIT_FAILURE; // unexpected error : exit the example program
}
return EXIT_SUCCESS;
}
Note : This assumes that the database is in the same folder as your cpp

boost : Just iterate over elements of a ptree

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;
}

Resources