Reading the end of an XML file

This program reads a contact list from an xml file. It prints the names and addresses of every contact who lives in the city of Palmdale. I have everything working but when it reaches the end, the program doesn't end. I think its a problem with line 20 while (!fin.eof()) How do I get the program to end when it reaches the end of the xml file?

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
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;

int main()
{
	string next, name, street, city, state, zip;
	int loc_name, loc_street, loc_city, loc_state, loc_zip, loc_end_contact;
	ifstream fin;

	fin.open("address.xml");
	if (fin.fail())
	{
		cout << "Input file opening failed.\n";
		system("pause");
		exit(1);
	}
	while (!fin.eof())
	{
		getline(fin, next);
		loc_end_contact = next.find("</contact>");
		while ((loc_end_contact < 0) || (loc_end_contact >= next.length()))
		{
			loc_name = next.find("<name>");
			loc_street = next.find("<street>");
			loc_city = next.find("<city>");
			loc_state = next.find("<state>");
			loc_zip = next.find("<zip>");

			if ((loc_name >= 0) && (loc_name < next.length()))
				name = next.substr(10, next.length() - 17);
			if ((loc_street >= 0) && (loc_street < next.length()))
				street = next.substr(12, next.length() - 21);
			if ((loc_city >= 0) && (loc_city < next.length()))
				city = next.substr(10, next.length() - 17);
			if ((loc_state >= 0) && (loc_state < next.length()))
				state = next.substr(11, next.length() - 19);
			if ((loc_zip >= 0) && (loc_zip < next.length()))
				zip = next.substr(9, next.length() - 15);
			getline(fin, next);
			loc_end_contact = next.find("</contact>");
		}
		if (city == "Palmdale")
		{
			cout << name << endl
				<< street << endl
				<< city << endl
				<< state << endl
				<< zip << endl << endl;
		}
		name.erase(0, name.length());
		street.erase(0, street.length());
		city.erase(0, city.length());
		state.erase(0, state.length());
		zip.erase(0, zip.length());
	}
	fin.close();
	return 0;
}


I have the content of the xml file "address.xml" below.

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
<?xml version="1.0"?>
<address_book>
  <contact>
    <name>George Clooney</name>
    <street>1042 El Camino Real</street>
    <city>Beverly Hills</city>
    <state>CA</state>
    <zip>90214</zip>
  </contact>
  <contact>
    <name>Cathy Pearl</name>
    <street>405 A St.</street>
    <city>Palmdale</city>
    <state>CA</state>
    <zip>93352</zip>
  </contact>
  <contact>
    <name>Paris Hilton</name>
    <street>200 S. Elm St.</street>
    <city>Beverly Hills</city>
    <state>CA</state>
    <zip>90212</zip>
  </contact>
  <contact>
    <name>Wendy Jones</name>
    <street>982 Boundary Ave.</street>
    <city>Palmdale</city>
    <state>CA</state>
    <zip>93354</zip>
  </contact>
</address_book>


The output when the program is run is:

Cathy Pearl
405 A St.
Palmdale
CA
93352

Wendy Jones
982 Boundary Ave.
Palmdale
CA
93354




The cursor just sits there blinking a line or two below Wendy Jones' zipcode.
Last edited on
Line 20: Do not loop on !eof(). This does not work the way you expect. The eof bit is set true only after you make a read attempt on the file. This means after you read the last record of the file, eof is still false. Your attempt to read past the last record sets eof, but you're not checking it there. You proceed as if you had read a good record. This will result in reading an extra (bad) record. The correct way to deal with this is to put the >> operation as the condition in the while statement.
1
2
3
  while (cin >> var)   // or getline
  {  //  Good cin operation
  }
There are two while loops, and two uses of getline().

You need to detect when either of these fails.


The first, as already suggested can be handled by replacing these lines:
20
21
22
	while (!fin.eof())
	{
		getline(fin, next);

with this:
20
21
	while (getline(fin, next))
	{


The second is a bit different, since the getline is near the end of the loop.
You could test whether it was ok using an if statement, and breaking out of the loop, or perhaps better practice, add an extra condition while (fin && to the loop at line 24. Be careful, make sure to add an extra set of parentheses around the existing conditions.
Thank you for all your help. I got the program working properly using your advice. The program up until line 20 remains the same. Here is the rest of the new program starting at line 20.

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
while (getline(fin, next))
	{

		do
		{
			loc_end_contact = next.find("</contact>");
			loc_name = next.find("<name>");
			loc_street = next.find("<street>");
			loc_city = next.find("<city>");
			loc_state = next.find("<state>");
			loc_zip = next.find("<zip>");

			if ((loc_name >= 0) && (loc_name < next.length()))
				name = next.substr(10, next.length() - 17);
			if ((loc_street >= 0) && (loc_street < next.length()))
				street = next.substr(12, next.length() - 21);
			if ((loc_city >= 0) && (loc_city < next.length()))
				city = next.substr(10, next.length() - 17);
			if ((loc_state >= 0) && (loc_state < next.length()))
				state = next.substr(11, next.length() - 19);
			if ((loc_zip >= 0) && (loc_zip < next.length()))
				zip = next.substr(9, next.length() - 15);
		} while (((loc_end_contact < 0) || (loc_end_contact >= next.length())) && (getline(fin, next)));
		if (city == "Palmdale")
		{
			cout << name << endl
				<< street << endl
				<< city << endl
				<< state << endl
				<< zip << endl << endl;
		}
		name.erase(0, name.length());
		street.erase(0, street.length());
		city.erase(0, city.length());
		state.erase(0, state.length());
		zip.erase(0, zip.length());
	}
Topic archived. No new replies allowed.