Read from text doc and display conditional records

Goal is to read from a list of contacts denoted like the following:
1
2
3
4
5
6
7
<contact>
		<name>George Clooney</name>
		<street>1042 El Camino Real</street>
		<city>Beverly Hills</city>
		<state>CA</state>
		<zip>90214</zip>
</contact>

and then print the contacts in the city "Palmdale," which I have done. Then, I need to print the contacts in the zip codes 90210-90214. I'm able to print them all, but they are not separated (I'm assuming because they are in the same loop).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  void temp1() {
	ifstream fin;
	string row, name, street, city, state, zip;
	int start, end, zipCode;

	fin.open("address.xml");
	if (fin.fail()) {
		cout << "There was an error opening the file...";
		exit(1);
	}

	cout << "\nHere are your contacts who live in Palmdale:\n\n";

	while (getline(fin, row)) {

		if ((start = row.find("<name>")) != string::npos) {
			start = row.find(">");
			end = row.find("</name>");
			name = row.substr(start + 1, end - start - 1);
		}
		if ((start = row.find("<street>")) != string::npos) {
			start = row.find(">");
			end = row.find("</street>");
			street = row.substr(start + 1, end - start - 1);
		}
		if ((start = row.find("<city>")) != string::npos) {
			start = row.find(">");
			end = row.find("</city>");
			city = row.substr(start + 1, end - start - 1);
		}
		if ((start = row.find("<state>")) != string::npos) {
			start = row.find(">");
			end = row.find("</state>");
			state = row.substr(start + 1, end - start - 1);
		}
		if ((start = row.find("<zip>")) != string::npos) {
			start = row.find(">");
			end = row.find("</zip>");
			zip = row.substr(start + 1, end - start - 1);
			zipCode = stoi(zip);
		}
		if ((row.find("</contact>")) != string::npos) {
			if (city == "Palmdale") {
				cout << name << endl << street << endl
					<< city << endl << state << endl << zip << endl << endl;
			}
		}
		if ((row.find("</contact>")) != string::npos) {
			if (zipCode >= 90210 && zipCode <= 90214) {
				cout << "\nHere are your contacts who live in zip codes 90210-90214:\n\n";
				cout << name << endl << street << endl
					<< city << endl << state << endl << zip << endl << endl;
			}
		}
	}

	fin.close();

}

Appreciate any pointers in the right direction
Last edited on
How complicated is your contact files (really)?

Because if you have more stuff to consider, or your XML format varies "at all", then your current approach is flawed.

It's a bit of a hump to use a library, but once you get over it, you have a lot less XML trivia to worry about.
https://stackoverflow.com/questions/170686/what-is-the-best-open-xml-parser-for-c
I'm able to print them all, but they are not separated
What do you mean by 'separated'?
they are not separated (I'm assuming because they are in the same loop).

That's correct. If you want to print two separate lists, then you're going to need to store the contacts in an array (or better yet a std::vector). Then after you're read in all the contacts, iterate through the array twice printing those entries that match your criteria for each pass.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <fstream>
#include <string>  
#include <vector>
using namespace std;

struct Contact
{
    string name, street, city, state, zip;
};

vector<Contact>     contacts;

void parse_tags(const string & row, const string & begintag, const string &endtag, string & dest)
{
    int start, end;

    dest.clear();
    start = row.find(begintag);
    if (start != string::npos)
    {
        start = row.find(">");
        end = row.find(endtag);
        dest = row.substr(start + 1, end - start - 1);
    }
}

void print_contact(const Contact & contact)
{
    cout << contact.name << endl << contact.street << endl
        << contact.city << endl << contact.state << endl << contact.zip << endl << endl;
}

int main () {
    ifstream fin;
    Contact temp;
    string row;

    fin.open("address.xml");
    if (fin.fail()) {
        cout << "There was an error opening the file...";
        exit(1);
    }

    while (getline(fin, row))
    {
        parse_tags(row, "<name>", "</name>", temp.name);
        parse_tags(row, "<street>", "</street>", temp.street);
        parse_tags(row, "<city>", "</city>", temp.city);
        parse_tags(row, "<state>", "</state>", temp.state);
        parse_tags(row, "<zip>", "</zip>", temp.zip);
        if ((row.find("</contact>")) != string::npos)
            contacts.push_back(temp);
    }
    fin.close();

    cout << "\nHere are your contacts who live in Palmdale:\n\n";
    for (size_t i = 0; i < contacts.size(); i++)
        if (contacts[i].city == "Palmdale")
            print_contact(contacts[i]);

    cout << "\nHere are your contacts who live in zip codes 90210-90214:\n\n";
    for (size_t i = 0; i < contacts.size(); i++)
        if (contacts[i].zip >= "90210" && contacts[i].zip <= "90214")
            print_contact(contacts[i]);
    return 0; 
}


An example using boost::property_tree:

address.xml - random data generated here:
https://www.fakenamegenerator.com/gen-random-us-us.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<contacts>
  <contact>
    <name>George Clooney</name>
    <street>1042 El Camino Real</street>
    <city>Beverly Hills</city>
    <state>CA</state>
    <zip>90214</zip>
  </contact>
  <contact>
    <name>Yung W. Neal</name>
    <street>3861 Mutton Town Road</street>
    <city>Redmond</city>
    <state>WA</state>
    <zip>98052</zip>
  </contact>
  <contact>
    <name>Shawn C. Carter</name>
    <street>3281 Star Trek Drive</street>
    <city>Fort Walton Beach</city>
    <state>FL</state>
    <zip>32548</zip>
  </contact>
</contacts>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

#include <boost/property_tree/exceptions.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>


// File example:
// <contact>
//     <name>George Clooney</name>
//     <street>1042 El Camino Real</street>
//     <city>Beverly Hills</city>
//     <state>CA</state>
//     <zip>90214</zip>
// </contact>
struct Contact {
    std::string name;
    std::string street;
    std::string city;
    std::string state;
    int zip {};

    Contact() = default;
    explicit Contact(std::istream& is);

// friends:
    // Declared friends in case of further development:
    friend std::istream& operator >> (std::istream& is, Contact& rhs);
    friend std::ostream& operator << (std::ostream& os, const Contact& rhs);
};


Contact::Contact(std::istream& is)
{
    is >> *this;
}


std::istream& operator >> (std::istream& is, Contact& rhs)
{
    std::getline(is, rhs.name);
    std::getline(is, rhs.street);
    std::getline(is, rhs.city);
    std::getline(is, rhs.state);
    is >> rhs.zip;
    return is;
}


std::ostream& operator << (std::ostream& os, const Contact& rhs)
{
    os << "Contact details:\n - name: " << rhs.name
       << "\n - street: " << rhs.street
       << "\n - city: " << rhs.city
       << "\n - state: " << rhs.state
       << "\n - ZIP: " << rhs.zip;
    return os;
}


std::vector<Contact> readFromXMLFile(std::string xml_file_name_arg);
template<typename T> void printStdVector(const std::vector<T>& v);


int main()
{
    const std::string xml_file_name { "address.xml" };
    const auto contacts { readFromXMLFile(xml_file_name) };
    printStdVector(contacts);

    // Find 'contacts' who live in XYZ town:
    const std::string city { "Redmond" };
    std::cout << "\nContacts who live in " << city << ":\n";
    for(auto ite { contacts.begin() }; ite != contacts.end(); /**/) {
        ite = std::find_if(ite,
                           contacts.end(),
                           [&city](const Contact& c) {
            return c.city == city;
        } );
        if(ite != contacts.end()) {
            std::cout << *ite << '\n';
            ++ite;
        }
    }

    // Find 'contacts' whose 'zip' ranges from 90210 to 90214:
    constexpr int min_zip { 90210 };
    constexpr int max_zip { 90214 };
    std::cout << "\nContacts whose zip is between " << min_zip
              << " and " << max_zip << ":\n";
    for(auto ite { contacts.begin() }; ite != contacts.end(); /**/) {
        ite = std::find_if(ite,
                           contacts.end(),
                           [min_zip, max_zip](const Contact& c) {
            if(c.zip < min_zip || max_zip < c.zip) { return false; }
            return true;
        } );
        if(ite != contacts.end()) {
            std::cout << *ite << '\n';
            ++ite;
        }
    }
}


std::vector<Contact> readFromXMLFile(std::string xml_file_name_arg)
{
    boost::property_tree::ptree boost_tree;
    boost::property_tree::read_xml(xml_file_name_arg, boost_tree);
    std::vector<Contact> contacts;
    try {
        for ( const auto& arr : boost_tree.get_child("contacts") ) {
            std::stringstream ss;
            ss << arr.second.get<std::string>("name") << '\n';
            ss << arr.second.get<std::string>("street") << '\n';
            ss << arr.second.get<std::string>("city") << '\n';
            ss << arr.second.get<std::string>("state") << '\n';
            ss << arr.second.get<int>("zip");
            contacts.emplace_back(ss);
        }
    } catch (boost::property_tree::ptree_bad_path& e) {
        std::cout << "Cannot find (nested?) path: " << e.what() << '\n';
    } catch (boost::property_tree::ptree_bad_data& e) {
        std::cout << "Cannot find such element: " << e.what() << '\n';
    }
    return contacts;
}


template<typename T> void printStdVector(const std::vector<T>& v)
{
    for(const auto& e : v) {
        std::cout << e << '\n';
    }
}


Output:
Contact details:
 - name: George Clooney
 - street: 1042 El Camino Real
 - city: Beverly Hills
 - state: CA
 - ZIP: 90214
Contact details:
 - name: Yung W. Neal
 - street: 3861 Mutton Town Road
 - city: Redmond
 - state: WA
 - ZIP: 98052
Contact details:
 - name: Shawn C. Carter
 - street: 3281 Star Trek Drive
 - city: Fort Walton Beach
 - state: FL
 - ZIP: 32548

Contacts who live in Redmond:
Contact details:
 - name: Yung W. Neal
 - street: 3861 Mutton Town Road
 - city: Redmond
 - state: WA
 - ZIP: 98052

Contacts whose zip is between 90210 and 90214:
Contact details:
 - name: George Clooney
 - street: 1042 El Camino Real
 - city: Beverly Hills
 - state: CA
 - ZIP: 90214

Last edited on
Topic archived. No new replies allowed.