While within while just hanging?

Hi Guys,

I'm trying to extract data from an XML file. I have multiple groups of data, with each group being between a PrimaryMarkerStart, and PrimaryMarkerEnd.

I can successfully get my while loop to go through the entire XML and output each sandwiched group of data one after the other fine. So I know my first while loop is doing it's job. My issue is with the while loop within the first.

I'm trying to extract the multiple pieces of data within the primary markers, which are themselves within secondary markers SecondaryStartMarker, SecondaryEndMarker.

Unfortunatelty my while loop within the first does not even get as far as displaying the cout at the top of it, suggesting I'm doing something very wrong with the syntax of the second While conditions. Any suggestions would be appreciated. Thanks.

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
  // Search for the substring in string in a loop until nothing is found
	while ((PosPrimaryStartMarker = XmlFileAsString.find(PrimaryStartMarker, PosPrimaryStartMarker)) != std::string::npos)

	{

		std::cout << "PrimaryStartMarker: "<<PosPrimaryStartMarker << std::endl;


		PosPrimaryEndMarker = XmlFileAsString.find(PrimaryEndMarker, PosPrimaryStartMarker);
		std::cout << "PrimaryEndMarker: " << PosPrimaryEndMarker << std::endl;


		/*

		while ((PosSecondaryStartMarker = XmlFileAsString.find(SecondaryStartMarker, PosPrimaryStartMarker)) != PosPrimaryEndMarker);
			   
		{
			std::cout << "Secondary Marker Loop: " << PosSecondaryStartMarker;
			//get each data ref

			
			PosSecondaryEndMarker = XmlFileAsString.find(SecondaryEndMarker, PosSecondaryStartMarker);

			std::string DataRef = XmlFileAsString.substr(PosSecondaryStartMarker, PosSecondaryEndMarker - PosSecondaryStartMarker);

			std::cout << "DataRef: " << DataRef;

			PosSecondaryStartMarker = (PosSecondaryEndMarker + SecondaryStartMarker.length());
		}

*/
		std::string DataRef = XmlFileAsString.substr(PosPrimaryStartMarker, PosPrimaryEndMarker - PosPrimaryStartMarker);
		std::cout << "DataRef: " << DataRef << std::endl;

		PosPrimaryStartMarker = (PosPrimaryEndMarker + PrimaryEndMarker.length());

		//PosPrimaryMarker = (PosPrimaryMarker + PrimaryMarker.length());
	}


The general Data structure of the XML file is like this..

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

/*<PrimaryMarker>junk junk junk

  <SecondaryStartMarker>DataRef1a<SecondaryEndMarker>

  <SecondaryStartMarker>DataRef1b<SecondaryEndMarker>

  <SecondaryStartMarker>DataRef1c<SecondaryEndMarker>

<PrimaryMarkerEnd>

<junk>

<junk>

<junk>

<PrimaryMarker>junk junk junk

  <SecondaryStartMarker>DataRef2a<SecondaryEndMarker>

  <SecondaryStartMarker>DataRef2b<SecondaryEndMarker>

  <SecondaryStartMarker>DataRef2c<SecondaryEndMarker>

  <SecondaryStartMarker>DataRef2d<SecondaryEndMarker>

<PrimaryMarkerEnd>
 */
Given that npos is a static member constant value with the greatest possible value for an element of type size_t.

It's understandable that != std::string::npos in the first 'while' will keep going so long as it doesn't reach the end of the file.

I take the npos to mean the n'th position, which suggests that I should be able to get the second loop to search for the SecondaryStartMarker starting from the PrimaryStartMarker, and keep doing it so long as it doesn't get to the end of the position of the PrimaryEndMarker i.e != PosPrimaryEndMarker .
My guess is that "npos" stands for "no position". It's the value that std::string::find returns if it doesn't find what you're searching for.

I think the inner loop should also compare to npos. I guess you could also compare to PosPrimaryEndMarker but then you will have to use < instead of != because there is no reason find would return the same position as PosPrimaryEndMarker.

You probably don't want to restart the search at PosPrimaryStartMarker each time because that would result in an infinite loop. It looks like you might want to use PosSecondaryStartMarker instead but then you need to give it a value before the loop so that it searches correctly on he first iteration.
Last edited on
Are you doing this as an exercise or because you need it?
Please note Boost provides Boost.PropertyTree:
https://www.boost.org/doc/libs/1_69_0/doc/html/property_tree.html
Thanks Peter, what you say makes sense, I changed it to < PosPrimaryEndMarker and initialised the PosSecocondaryStartMarker before the loop using

PosSecondaryStartMarker = XmlFileAsString.find(SecondaryStartMarker, PosPrimaryStartMarker);

So now it should get the position.

Because the XmlFileAsString being searched has multiple groups of data, and I need to keep the groups seperate (they will end up in arrays evetually) I can't use npos again for the inner markers. The best analogy I can think of would be that the file is like a stack of 100's of sandwiches and those sandwiches contain poptarts stacked inside the sandwiches.

The primary markers represent the slices of bread, the secondary markers represent the poptart outer layers, and the jam filling is the data. I want to take the jam out of all the poptarts on a per sandwich basis so I can have seperate groups. My understanding is npos in the second while will just plough through the sandwich stack in one go until it gets to the end.

I tried my modified code and unforunately it just seems to get stuck the same.

I just get..

PrimaryStartMarker: 86763
PrimaryEndMarker: 87173

I don't even get the cout that says "Secondary Marker Loop" which is bizzare, I just don't understand. This is the modified code.

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 ((PosPrimaryStartMarker = XmlFileAsString.find(PrimaryStartMarker, PosPrimaryStartMarker)) != std::string::npos)

	{

		std::cout << "PrimaryStartMarker: "<<PosPrimaryStartMarker << std::endl;

		PosPrimaryEndMarker = XmlFileAsString.find(PrimaryEndMarker, PosPrimaryStartMarker);
		std::cout << "PrimaryEndMarker: " << PosPrimaryEndMarker << std::endl;

		PosSecondaryStartMarker = XmlFileAsString.find(SecondaryStartMarker, PosPrimaryStartMarker);
			   
		while ((PosSecondaryStartMarker = XmlFileAsString.find(SecondaryStartMarker, PosSecondaryStartMarker)) < PosPrimaryEndMarker);
		
		{

			std::cout << "Secondary Marker Loop: " << PosSecondaryStartMarker;

			//get each data ref
					   			 		  
			PosSecondaryEndMarker = XmlFileAsString.find(SecondaryEndMarker, PosSecondaryStartMarker);

			std::string DataRef = XmlFileAsString.substr(PosSecondaryStartMarker, PosSecondaryEndMarker - PosSecondaryStartMarker);

			std::cout << "DataRef: " << DataRef;

			PosSecondaryStartMarker = (PosSecondaryEndMarker + SecondaryStartMarker.length());

		}
			   

		//std::string DataRef = XmlFileAsString.substr(PosPrimaryStartMarker, PosPrimaryEndMarker - PosPrimaryStartMarker);
		//std::cout << "DataRef: " << DataRef << std::endl;

		PosPrimaryStartMarker = (PosPrimaryEndMarker + PrimaryEndMarker.length());

		//PosPrimaryMarker = (PosPrimaryMarker + PrimaryMarker.length());
	}

Last edited on
Hi Enoizat, I'm doing it because I need it for a personal project I'm working on. I'm trying to avoid external libraries because what I'm trying to do should (in my head anyway) be pretty straightforward with while loops, so I can just keep it simple.
Remove the semicolon at the end of line 12.
Thank you Peter, I'm kicking myself for not spotting that, it works perfectly now. I really appreciate your help :-)
Topic archived. No new replies allowed.