xml-Parser in C++

SSJ

Grünschnabel
Hallo zusammen

Ich haben sehr einfachen xml Parser geschrieben, der noch nicht so funktioniert, wie er sollte.
Erklaerung: Der Parser durchlaeuft die Datei. Wenn er einen oeffnenden Tag ( ' < ' ) findet, legt er einen Stack an. Dann geht er weiter und speichert die weiteren Tags mit ihren jeweiligen Werten im Stack. Wenn ein schliessender Tag kommt ( ' /> ' ) werden alle Werte, die er bisher gespeichert hat, aus dem Stack genommen und zusammen gerechnet. Die Summe wird wieder auf den Stack gelegt und alle bisherigen Tags werden verworfen. So macht er weiter und addiert die neu gesammelten Werte wieder mit der vorhergehenden Summe und gibt am Schluss den Schlusswert (die Impedanz) zurueck.
Leider gibt das Programm jetzt immer nur 0.00 aus.
Ich habe im Programm auch Subtraktion, Multiplikation und Division implementiert, weil das Programm mehr tun sollte als nur addieren. Aber erst soll es ueberhaupt mal laufen, bis es die anderen Rechenoperationen anwenden kann.

Ich hoffe jemand sieht den Fehler und kann mir sagen, warum die Werte nicht addiert werden und das Programm immer nur Null als Resultat ausgibt, anstatt 11.

Mein Code:

Code:
#include <iostream>
#include <string>
#include <algorithm>
#include <fstream>
#include <stack>
#include <list>
#include <sstream>

using namespace std;

// string zu irgendeinem datentyp konvertieren
template <class T>
bool from_string(T& t, const string& s, ios_base& (*f)(ios_base&))
{
 istringstream iss(s);
 return !(iss >> f >> t).fail();
}

struct complex 
{
	float     real;
	float     imag;
};

//addieren
complex addComplex(complex a, complex b)
{
	complex res;
	res.real=a.real+b.real;
	res.imag=a.imag+b.imag;
	return res;
}


//subtrahieren
complex subtractComplex(complex a, complex b)
{
	complex res;
	res.real=a.real-b.real;
	res.imag=a.imag-b.imag;
	return res;
}


//multiplizieren
complex multiplyComplex(complex a, complex b)
{
	complex res;
	res.real=a.real*b.real - a.imag*b.imag;
	res.imag=a.imag*b.real + a.real*b.imag;
	return res;
}


//dividieren
complex divideComplex(complex a, complex b)
{
	complex res;

	//{ac + bd}{c^2 + d^2}
	res.real = (a.real*b.real + a.imag*b.imag)*(b.real*b.real + b.imag*b.imag);
	res.imag = 1/((a.imag*b.real - a.real*b.imag)*(b.real*b.real + b.imag*b.imag));
	return res;
}

//komplex in string umwandeln in der form (real,imag)
string complexToString(complex c)
{
	string real, imag;
	string rv;
	//float val =3.456;
	stringstream ss (stringstream::in | stringstream::out);

	rv = "("; 
	ss << c.real;
	rv += ss.str();
	rv += ",";
	ss << c.imag;
	rv += ss.str();
	rv += ")";
	ss << c.imag;

	return rv;
}

complex stringToComplex(string s)
{
	string real, imag;
	complex rv;
	real = s.substr(1, s.find(","));
	imag = s.substr(s.find(","), s.find(")")-s.find(","));
	from_string<float>(rv.real, real, std::dec);
	from_string<float>(rv.imag, imag, std::dec);
	return rv;
}


int main(int argc, char *argv[])
{
   //char          filename[128];
	ifstream      file;
	string        zeile;
	stack<string> stack;
	string        test ("");
	string		  value;
	complex		  val1;
	complex		  val2;
	//complex		  retVal;
	stringstream	ss (stringstream::in | stringstream::out);
	bool		  debug;

	debug = false;

   file.open("inputfile.dat"); //filename);

   if (file.good())
   {
       // file geoeffnet

       // An den Anfang der Datei springen
       file.seekg(ios::beg);

       while (! file.eof())
       {
				

			// Die Datei zeilenweise auslesen
           getline(file, zeile);

			// ParseLine: gehe Zeile Durch, wenn <, dann neues Zeichen, das auf den Stack muss, sonst wenn </
			// haben wir ein Closing Tag

			bool tag_opened = false;
			bool quote_opened = false;
			test = "";
			complex oneConstant;
			oneConstant.real = 1.0f;
			oneConstant.imag = 0.0f;

			for (int i = 0; i<zeile.length(); i++)
			{
               if (zeile[i]=='<')
				{
					tag_opened = true;
				}
				else if ((zeile[i]=='"') && (!quote_opened))
				{
					quote_opened = true;
				}
				else if ((tag_opened || quote_opened) && (!(zeile[i]=='"')) && (!(zeile[i]=='>')))
					test += zeile[i];
				else if ((quote_opened == true  && zeile[i]=='"') || (tag_opened == true  && zeile[i]=='>'))
				{
					tag_opened = false;
					quote_opened = false;
					if (debug)
						if (!test.empty()) cout << test << endl;

					if (test.compare("/resistance") == 0)
					{
						// Resistance: Z = R
						if (debug)
							cout << "Closing resistance found" << endl;
						value = stack.top();
						from_string<float>(val1.real, value, dec);
						val1.imag = 0.0f;
						// den wert vom stack nehmen
						stack.pop();
						// wert zurueck tun
						stack.push(complexToString(val1));
					}
					else if (test.compare("/coil") == 0)
					{
						 if (debug)
							cout << "Closing coil found" << endl;
						value = stack.top();
						from_string<float>(val1.imag, value, std::dec);
						val1.real = 0.0f;
						// wert vom stack nehmen
						stack.pop();				
						stack.push(complexToString(val1));
					}
					else if (test.compare("/condenser") == 0)
					{
						if (debug)
							cout << "Closing condenser found" << endl;
						value = stack.top();
						// wert vom stack nehmen
						stack.pop();
						from_string<float>(val1.imag, value, dec);
						val1.imag *= -1;
						val1.real = 0.0f;
						// den "<condenser>" tag entfernen
						stack.pop();
						stack.push(complexToString(val1));
					}
					else if (test.compare("/parallel") == 0)
					{
						// parallel: alle werte zusammen addieren bis zum schluss tag mit 1/wert
						if (debug)
							cout << "Closing parallel found" << endl;
						while (!(stack.top().compare("parallel")))
						{
							val1 = stringToComplex(stack.top());
							stack.pop();
							val2 = stringToComplex(stack.top());
							stack.pop();
							stack.push(complexToString(addComplex(divideComplex(oneConstant, val1), divideComplex(oneConstant, val1))));
						}
						// start series tag entfernen
						stack.pop();
					}
					else if (test.compare("/series") == 0)
					{
						// series: alle werte addieren
						if (debug)
							cout << "Closing series found" << endl;
						while (!(stack.top().compare("series")))
						{
							val1 = stringToComplex(stack.top());
							stack.pop();
							val2 = stringToComplex(stack.top());
							stack.pop();
							stack.push(complexToString(addComplex(val1, val2)));
						}
						// start series tag entfernen
						stack.pop();
					}
					else if (test.compare("/circuit") == 0)
					{
						if (debug)
							cout << "Closing circuit found" << endl;
						// resultat plotten
						cout << "Impedance: " << stack.top() << endl;
					}
					else
					{
						stack.push (zeile);
					}
					test = "";	
				}
			}
		}
   }
   else
   {
       // Wenn die Datei nicht geoeffnet werden konnte
       cout << "Datei nicht gefunden." << endl;
   }

   return 0;
}


Das xml-File:

Code:
<circuit>
	<series>
		<resistance>"5"</resistance>
		<parallel>
			<resistance>"2"</resistance
			<series>
				<resistance>"1"</resistance>
				<coil>"1"</coil>
			</series>
		</parallel>
		<condenser>"2"</condenser>
	</series>
</circuit>
 
Hi.

Ein paar grundlegende Ungereimtheiten:
SSJ hat gesagt.:
C++:
return !(iss >> f >> t).fail();
Warum so kompliziert? Außerdem hast du das badbit vergessen.
C++:
return (iss >> f >> t);
SSJ hat gesagt.:
C++:
file.open("inputfile.dat"); //filename);

   if (file.good())
   {
       // file geoeffnet
Warum fragst du denn das goodbit ab? Warum fragst du nicht das ab, was dich tatsächlich interessiert? Dann kannst du dir auch den Kommentar sparen.
C++:
if (file.is_open()) {

SSJ hat gesagt.:
C++:
while (! file.eof())
       {
			// Die Datei zeilenweise auslesen
           getline(file, zeile);
Warum so kompliziert (und falsch)? Du prüfst wieder nur einen (der 3) Fehlerzustände ab. Was ist mit bad() bzw. fail()? Dann liest du eine Zeile ein, prüfst aber gar nicht ob überhaupt noch eine Zeile eingelesen werden konnte.
C++:
while (getline(file, zeile)) {
   ..
}
Dann prüfst du keine deiner Konvertierungen from_string<float>() Aufrufe etc. Da liegt dann auch der Hund begraben, denn soetwas wie "\t\t<resistance>\"5\"</resistance>" läßt sich nicht in einen float konvertieren.

Warum hast du denn in der XML Datei die Werte in Anführungszeichen gesetzt?

Gruß
 
Hallo deepthroat;

danke fuer die Korrekturen, ich werde sie umsetzen;

die Werte sind in Anfuehrungszeichen, weil das die Vorgabe ist; es soll die Suche nach Integern erleichtern

Code:
	else if (test.compare("/circuit") == 0)
					{
						if (debug)
							cout << "Closing circuit found" << endl;
						// resultat plotten
						cout << "Impedance: " << stack.top() << endl;
					}
					else
					{
						stack.push (zeile);
					}
					test = "";

Ich muss hier 'push(zeile)' zu 'push(test)' aendern, dann bekomme ich den Wert 1,10.
Diesen Fehler habe ich noch soeben gefunden.
 
Deine Funktion divideComplex hat einen Fehler. Dort musst du schreiben

C++:
//(bc-ad)/(cc+dd)
res.imag = (a.imag*b.real - a.real*b.imag)/(b.real*b.real + b.imag*b.imag);
 
Zurück