XML Parsing using Structures in C++ - c++

I have tried to parse an xml file using tinyxml API in C++ through structure implementation, but my below code does not produce the result which i am expected. Below is the My code.
#include<iostream>
#include<list>
#include<string>
#include"tinyxml.h"
using namespace std;
struct accsys
{
string name;
string type;
float rate;
};
void parser(struct accsys acc)
{
list<accsys> l;
TiXmlDocument* doc= new TiXmlDocument();
doc->LoadFile("accountsys.xml");
TiXmlElement* root=doc->RootElement();
TiXmlElement* accountElement=root->FirstChildElement();
while(accountElement)
{
TiXmlElement* nameElement=accountElement->FirstChildElement();
acc.name=nameElement->GetText();
TiXmlElement* typeElement=nameElement->NextSiblingElement();
acc.type=typeElement->GetText();
TiXmlElement* rateElement=typeElement->NextSiblingElement();
acc.rate=atof(rateElement->GetText());
l.push_back(acc);
accountElement=accountElement->NextSiblingElement();
}
}
void display(struct accsys acc)
{
list<accsys> l;
list<accsys>::iterator i;
i=l.begin();
while(i!=l.end())
{
cout<<"name:"<<i->name<<endl;
cout<<"type:"<<i->type<<endl;
cout<<"rate:"<<i->rate<<endl;
i++;
}
}
int main()
{
struct accsys acc;
parser(acc);
display(acc);
return 0;
}
Can any one answer please!

Firstly, pass a reference to the std::list, not a empty struct, which won't live longer than in the function you make it. Neither can you make a list in one function and expect it to be there in another.
Fixed formatting, removed this ugly using namespace std;, and corrected your code. I assume this is what you want.
#include <iostream>
#include <list>
#include <string>
#include "tinyxml.h"
struct accsys
{
std::string name;
std::string type;
float rate;
};
void parser(std::list<accsys> &acc)
{
TiXmlDocument *doc = new TiXmlDocument();
doc->LoadFile("accountsys.xml");
TiXmlElement *root = doc->RootElement();
TiXmlElement *accountElement = root->FirstChildElement();
while (accountElement)
{
struct accsys structAcc;
TiXmlElement *nameElement = accountElement->FirstChildElement();
structAcc.name = nameElement->GetText();
TiXmlElement *typeElement = nameElement->NextSiblingElement();
structAcc.type = typeElement->GetText();
TiXmlElement *rateElement = typeElement->NextSiblingElement();
structAcc.rate = atof(rateElement->GetText());
acc.push_back(structAcc);
accountElement = accountElement->NextSiblingElement();
}
}
void display(std::list<accsys> &acc)
{
for (std::list<accsys>::iterator itr = acc.begin(); itr != acc.end(); ++itr)
{
std::cout << "name: " << itr->name << std::endl;
std::cout << "type: " << itr->type << std::endl;
std::cout << "rate: " << itr->rate << std::endl;
}
}
int main()
{
std::list<accsys> acc;
parser(acc);
display(acc);
return 0;
}

I can see at least 3 big errors in your code:
1) As marcinj has alrteady pointed out you are passing to your parser() function a copy of the struct accsys and whatever you fill in that structure you will never find it outside the function.
2) Again in parser you declare a list of your accsys struct which is local to the function, whatever you put in the list you will never see it outside the function, moreover in the while loop you keep overwriting values in your acc struct so even in the best case you would only see the last line of you xml file.
3) In the display function you pass an accsys struct to the function and the you forget it and try to print the content of a list of struct just created which is obviously empty.
So supposing the xml parser is correct your code would have to be more or less like this:
#include<iostream>
#include<list>
#include<string>
#include"tinyxml.h"
using namespace std;
struct accsys
{
string name;
string type;
float rate;
};
void parser(list<struct accsys *> &accList)
{
TiXmlDocument* doc= new TiXmlDocument();
doc->LoadFile("accountsys.xml");
TiXmlElement* root=doc->RootElement();
TiXmlElement* accountElement=root->FirstChildElement();
while(accountElement)
{
struct accsys *acc = new struct accsys;
TiXmlElement* nameElement=accountElement->FirstChildElement();
acc->name=nameElement->GetText();
TiXmlElement* typeElement=nameElement->NextSiblingElement();
acc->type=typeElement->GetText();
TiXmlElement* rateElement=typeElement->NextSiblingElement();
acc->rate=atof(rateElement->GetText());
l.push_back(acc);
accountElement=accountElement->NextSiblingElement();
}
}
void display(list<struct accsys *> &l)
{
list<struct accsys *>::iterator i;
i=l.begin();
while(i!=l.end())
{
cout<<"name:"<<i->name<<endl;
cout<<"type:"<<i->type<<endl;
cout<<"rate:"<<i->rate<<endl;
i++;
}
}
int main()
{
list <struct accsys *> acc;
parser(acc);
display(acc);
return 0;
}

Related

Add structure(s) to QList in for-loop

I fill a structure in a loop and per loop i want to have a new instance (copy) in a Qlist of this instance.
I read data out of a (xml)file and will store the data in that QList.
After eg. 4 loops, the QList contains only one structure ...
typedef struct structure_Anf
{
public:
typedef struct structure_Art
{
public:
QString Art = "";
}
structure_Art_t;
QString Num = "";
QList <structure_Art_t> ArtList;
}
structure_Anf_t;
QList <structure_Anf_t> FullAnfList; // holds the full list of structures
structure_Anf_t struc_act_Anf; // holding actual used instance of structure
void test
{
for ( int i=0; i < 5; i++) // add some data
{
struc_act_Anf = {};
struc_act_Anf.Num = "foo" + i;
structure_Anf_t::structure_Art_t struc_new_Art;
for (int x = 0; x < 3; x++) // add some data to Art
{
struc_new_Art.Art = "bar" + x;
ArtList.append (struc_new_Art);
}
FullAnfList.append (struc_act_Anf);
}
}
Edit: Some minor changes on the code.
As i wrote above, after i-times-loop, FullAnfList.count() = 1 and not 5 as expected.
I do not have Qt , I convert it to Std c++ it works properly:
#include <iostream>
#include <list>
using namespace std;
using QString = std::string;
template <typename T>
using QList = std::list<T, std::allocator<T>>;
typedef struct structure_Anf
{
public:
typedef struct structure_Art
{
public:
QString Art = "";
}
structure_Art_t;
QString Num = "";
QList<structure_Art_t> ArtList;
}
structure_Anf_t;
QList <structure_Anf_t> FullAnfList;
structure_Anf_t struc_act_Anf; // holding actual used instance of structure
void test()
{
for (auto i : { 1,2,3,4,5,6 })
{
struc_act_Anf = {};
struc_act_Anf.Num = "foo";
structure_Anf_t::structure_Art_t struc_new_Art;
for (auto i : { 1,2,3,4,5,6})
{
struc_new_Art.Art = "bar";
struc_act_Anf.ArtList.push_back(struc_new_Art);
}
FullAnfList.push_back(struc_act_Anf);
}
}
int main()
{
test();
std::cin.get();
}

Iterating a vectors that are contained in a struct

Struct that has multiple vectors within
struct data {
//char array1[20];
//char array2[20];
//char array3[20];
vector<string> playerID1;
vector<string> playerID2;
vector<string> overall;
}P1;
struct data P(string b) {
int i = 0;
player_attributes *tmp = new player_attributes;
tmp = head;
while (tmp != NULL) {
if (tmp->potential == b)
{
tmp->Id1 = P1.playerID1[i];
tmp->Id2 = P1.playerID2[i];
tmp->overrall_rating = P1.overall[i];
i++;
tmp = tmp->next;
}
return P1;
}
}
I used i++ initially but I kept getting a vector subscript error.
I really don't know how to iterator this to store values and access them later on.
You get error when i reaches end of vector. std::vector< >::operator[] does not do bound checking and does not create new elements. You have to make sure that you stop when end of vector reached.
Also, why struct of vectors? Why not a vector of structs? Organize it in this way:
#include <string>
#include <iostream>
#include <vector>
using std::string;
using std::vector;
struct data {
string playerID1;
string playerID2;
string overall;
data(const string &i1, const string &i2, const string &ov):
playerID1(i1),playerID2(i2),overall(ov) {}
};
vector<data> P1;
// a little demonsration
int main(int argc, const char *argv[])
{
P1.emplace_back("", "","test1");
P1.emplace_back("", "","test2");
for(auto it = P1.begin(); it != P1.end(); it++ )
{
std::cout << it->overall << std::endl;
}
}

Return struct array from function c++

i am trying pass a struct array from a function. i searched a lot but was unable to find a way to this. below is the code i am tring.
struct menuItemType
{
int itemNo;
string menuItem;
double price;
};
void getData(menuItemType *menuList[10])
{
menuList[0]->itemNo = 111;
menuList[0]->menuItem = "Apple";
menuList[0]->price = 2.00;
....
menuList[0]->itemNo = 120;
menuList[0]->menuItem = "Chocolate";
menuList[0]->price = 5.00;
}
int main()
{
/* i know that i can't return a array. but i want to get the menuList[10] values here.
not sure which code i have to use..*/
}
Your void getData(menuItemType *menuList[10]) does not return anything. Instead, it fills the data in the memory pointed by input parameter.
int main()
{
menuItemType data[10];
getData(&data);
std::cout << data[9].menuItem << std::endl; // Chocolate
}
However, why are you insisting on using low level arrays? Use std::vector instead.
std::vector<menuItemType> getData()
{
std::vector<menuItemType> data;
data.push_back({111, "Apple", 2.00});
...
data.push_back({120, "Chocolate", 5.00});
return std::move(data);
}
int main()
{
std::vector<menuItemType> data = getData();
std::cout << data[9].menuItem << std::endl; // Chocolate
}
It will print Chocolate, because I assume there is a typo in your code.

Outputting a vector of of lists in C++

I'm having trouble outputting my vector of lists:
class index_table {
public:
index_table() { table.resize(128);}
void insert(string &, int );
private:
class entry
{
public:
string word;
vector <int> line;
};
vector< list <entry> > table;
};
I've got it so that it will fill up:
int main ()
{
index_table table;
string word,
int num = 5; //this is going to a random number. 5 is a temp. place holder.
while (cin >> word)
table.insert(word, num);
}
but how to output it? I've tried many different approaches, but a lot of them are giving me errors.
Do I have to overload the operator? I'm not entirely sure how I will be able to do it.
Assuming you really have a good reason to use std::vector< std::list<entry> >, then based on the given structure, printing of words might look like this:
class index_table {
public:
void print() {
for (size_t i = 0; i < table.size(); ++i) {
std::list<entry>::iterator li;
for (li = table[i].begin(); li != table[i].end(); ++li)
std::cout << li->word << " ";
}
}
...
private:
std::vector< std::list<entry> > table;
...
};
If your compiler supports C++11, you can use two range based nested for loops. Look in the function void index_table::dump().
// Output function
void index_table::dump() {
for (list<entry> &le : table) {
for (entry &e : le) {
e.dump();
}
}
}
I also created a function dump() in the entry class, which outputs the contents of two variables, which is now made private.
class index_table {
public:
index_table() {
table.resize(128);
}
void insert (int,string&,int);
void dump();
private:
class entry {
private:
string word;
int value;
public:
entry (string word, int value) {
this->word = word;
this->value = value;
}
void dump() {
cout << "Word/value is: " << word << "/" << value << endl;
}
};
vector< list <entry> > table;
};
void index_table::insert(int c, string &key, int value) {
//void index_table::insert(string &key, int value) {
entry obj(key, value);
table[c].push_back(obj);
}
// Output function
void index_table::dump() {
for (list<entry> &le : table) {
for (entry &e : le) {
e.dump();
}
}
}
int main (int argc, char **argv) {
index_table mytable;
string a = "String 0-A";
string b = "String 0-B";
string c = "String 1-A";
string d = "String 1-B";
string e = "String 6-A";
string f = "String 6-B";
mytable.insert(0, a, 1);
mytable.insert(0, b, 2);
mytable.insert(1, c, 3);
mytable.insert(1, d, 4);
mytable.insert(6, e, 3);
mytable.insert(6, f, 4);
mytable.dump();
}
Program outputs:
Word/value is: String 0-A/1
Word/value is: String 0-B/2
Word/value is: String 1-A/3
Word/value is: String 1-B/4
Word/value is: String 6-A/3
Word/value is: String 6-B/4
PS: I also changed your code a bit to make it run more easily for my test.
//This is the simple solution for outputting vector of lists.
#include <bits/stdc++.h>
using namespace std;
main()
{
vector<list<int>> my_vector; //creating vector of lists;
list<int> my_list;
for(int i = 0; i < 5; i++)
my_list.push_back(i);
my_vector.push_back(my_list); // pushing a list y to a vector
for (vector<list<int>>::iterator it = my_vector.begin(); it != my_vector.end(); ++it)
for (list<int>::iterator it2 = it->begin(); it2 != it->end(); ++it2)
cout << *it2 << ", ";
}

c++ reference to function pointer dynamically

I have one application in which following task are to be done
1.) UI application will send command code (integer value).
2.) DLL interface(in c++) will get that integer value and execute corresponding command function.
commands name and command code are maintained as
#define PING 50
there will be 500 commands and applying SWITCH CASE will not sound good. so i decided to implement function pointer in my code as below
#include "stdafx.h"
#include<iostream>
#define PING 20
using namespace std;
//extern const int PING = 10;
void ping()
{
cout<<"ping command executed";
}
void get_status(void)
{
cout<<"Get_status called"<<endl;
}
class ToDoCommands
{
public:
void getCommand( void (*CommandToCall)() );
};
void ToDoCommands::getCommand( void (*CommandToCall)())
{
void (*CommandToCall1)();
CommandToCall1 = CommandToCall;
CommandToCall1();
}
int main()
{
int code;
ToDoCommands obj;
cout<<"enter command code";
cin>>code; // if UI send 50 then Ping function get executed as #define PING 50
obj.getCommand(ping); // here m passing ping manually..
//obj.getCommand(get_status);
return 0;
}
how can i pass command name corresponding to command code in
obj.getCommand(ping);
You are almost there: make a std::map of std::string to function pointer, initialize it with data pairing a string name to a corresponding function pointer, and then use that map at runtime to pick the correct pointer based on the string parameter passed in.
#include <iostream>
#include <string>
#include <map>
using namespace std;
void ping() {
cout << "ping" << endl;
}
void test() {
cout << "test" << endl;
}
int main() {
map<string,void(*)()> m;
m["ping"] = ping;
m["test"] = test;
// I am using hard-coded constants below.
// In your case, strings will come from command line args
m["test"]();
m["ping"]();
return 0;
}
Link to a demo with std::map.
Here is how you can do it without a map (it will be slower because of the linear search, but you can fix it by ordering names alphabetically and using binary search).
#include <iostream>
#include <cstring>
using namespace std;
void ping() {
cout << "ping" << endl;
}
void test() {
cout << "test" << endl;
}
typedef void (*fptr_t)();
int main() {
const fptr_t fptrs[] = {test, ping};
const char *names[] = {"test", "ping"};
const char *fname = "test";
for (int i = 0 ; i != 2 ; i++) {
if (!strcmp(fname, names[i])) {
fptrs[i]();
break;
}
}
return 0;
}
Link to a demo with arrays.
Declare an array of function pointers. Where you treat the index as your "code". For example:
void foo(){
printf("foo\n");
}
void bar(){
printf("bar\n");
}
int main(void)
{
void (*code_to_function[100])();
int code;
code_to_function[0] = foo;
code_to_function[1] = bar;
printf("Enter code: ");
scanf("%d", &code);
code_to_function[code]();
return 0;
}
Please note that for this rudimentary example, inputting integer code other than 0 and 1 will result in a segfault.
I should say #dasblinkenlight is right but if you don't want to use std::map you should implement a map yourself. This can be buggy and not a optimized way, but if you don't want to use STL, it seems you should implement it yourself.
You can use 2 arrays with corresponding indices. One of them is a char * array and another one is function pointers. They are better to be encapsulated in a class named something like MyMap.
class MyMap {
public:
...
inline void add(char *name, (void (*ptr)(void)) ) {
names_[currIndex_] = name; // Or stcpy
ptrs_[currIndex_] = ptr;
currIndex_++;
}
inline (void(*)(void)) get(char *name) {
int foundIndex = -1;
for (int i = 0; i < currIndex_; i++) {
// Find matching index
}
if (foundIndex_ >= 0) {
return ptrs_[foundIndex_];
}
return NULL;
}
private:
int currIndex_;
char *names_[10];
(void (*ptrs_[10])(void));
};