]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/input_output/FGXMLElement.cpp
One step ahead of JSBSim CVS.
[flightgear.git] / src / FDM / JSBSim / input_output / FGXMLElement.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Author:       Jon Berndt
4  Date started: 09/28/2004
5  Purpose:      XML element class
6  Called by:    FGXMLParse
7
8  ------------- Copyright (C) 2001  Jon S. Berndt (jon@jsbsim.org) -------------
9
10  This program is free software; you can redistribute it and/or modify it under
11  the terms of the GNU Lesser General Public License as published by the Free Software
12  Foundation; either version 2 of the License, or (at your option) any later
13  version.
14
15  This program is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
18  details.
19
20  You should have received a copy of the GNU Lesser General Public License along with
21  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22  Place - Suite 330, Boston, MA  02111-1307, USA.
23
24  Further information about the GNU Lesser General Public License can also be found on
25  the world wide web at http://www.gnu.org.
26
27 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
28 INCLUDES
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
30
31 #include "FGXMLElement.h"
32
33 #include <cmath>
34 #include <cstdlib>
35 #include <iostream>
36
37 using namespace std;
38
39 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40 FORWARD DECLARATIONS
41 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
42
43 namespace JSBSim {
44
45 static const char *IdSrc = "$Id: FGXMLElement.cpp,v 1.32 2011/02/13 00:42:45 jberndt Exp $";
46 static const char *IdHdr = ID_XMLELEMENT;
47
48 bool Element::converterIsInitialized = false;
49 map <string, map <string, double> > Element::convert;
50
51 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52 CLASS IMPLEMENTATION
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
54
55 Element::Element(const string& nm)
56 {
57   name   = nm;
58   parent = 0L;
59   element_index = 0;
60
61   if (!converterIsInitialized) {
62     converterIsInitialized = true;
63     // convert ["from"]["to"] = factor, so: from * factor = to
64     // Length
65     convert["M"]["FT"] = 3.2808399;
66     convert["FT"]["M"] = 1.0/convert["M"]["FT"];
67     convert["KM"]["FT"] = 3280.8399;
68     convert["FT"]["KM"] = 1.0/convert["KM"]["FT"];
69     convert["FT"]["IN"] = 12.0;
70     convert["IN"]["FT"] = 1.0/convert["FT"]["IN"];
71     convert["IN"]["M"] = convert["IN"]["FT"] * convert["FT"]["M"];
72     convert["M"]["IN"] = convert["M"]["FT"] * convert["FT"]["IN"];
73     // Area
74     convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
75     convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
76     convert["M2"]["IN2"] = convert["M"]["IN"]*convert["M"]["IN"];
77     convert["IN2"]["M2"] = 1.0/convert["M2"]["IN2"];
78     convert["FT2"]["IN2"] = 144.0;
79     convert["IN2"]["FT2"] = 1.0/convert["FT2"]["IN2"];
80     // Volume
81     convert["IN3"]["CC"] = 16.387064;
82     convert["CC"]["IN3"] = 1.0/convert["IN3"]["CC"];
83     convert["FT3"]["IN3"] = 1728.0;
84     convert["IN3"]["FT3"] = 1.0/convert["FT3"]["IN3"];
85     convert["M3"]["FT3"] = 35.3146667;
86     convert["FT3"]["M3"] = 1.0/convert["M3"]["FT3"];
87     convert["LTR"]["IN3"] = 61.0237441;
88     convert["IN3"]["LTR"] = 1.0/convert["LTR"]["IN3"];
89     // Mass & Weight
90     convert["LBS"]["KG"] = 0.45359237;
91     convert["KG"]["LBS"] = 1.0/convert["LBS"]["KG"];
92     convert["SLUG"]["KG"] = 14.59390;
93     convert["KG"]["SLUG"] = 1.0/convert["SLUG"]["KG"];
94     // Moments of Inertia
95     convert["SLUG*FT2"]["KG*M2"] = 1.35594;
96     convert["KG*M2"]["SLUG*FT2"] = 1.0/convert["SLUG*FT2"]["KG*M2"];
97     // Angles
98     convert["RAD"]["DEG"] = 180.0/M_PI;
99     convert["DEG"]["RAD"] = 1.0/convert["RAD"]["DEG"];
100     // Angular rates
101     convert["RAD/SEC"]["DEG/SEC"] = convert["RAD"]["DEG"];
102     convert["DEG/SEC"]["RAD/SEC"] = 1.0/convert["RAD/SEC"]["DEG/SEC"];
103     // Spring force
104     convert["LBS/FT"]["N/M"] = 14.5939;
105     convert["N/M"]["LBS/FT"] = 1.0/convert["LBS/FT"]["N/M"];
106     // Damping force
107     convert["LBS/FT/SEC"]["N/M/SEC"] = 14.5939;
108     convert["N/M/SEC"]["LBS/FT/SEC"] = 1.0/convert["LBS/FT/SEC"]["N/M/SEC"];
109     // Damping force (Square Law)
110     convert["LBS/FT2/SEC2"]["N/M2/SEC2"] = 47.880259;
111     convert["N/M2/SEC2"]["LBS/FT2/SEC2"] = 1.0/convert["LBS/FT2/SEC2"]["N/M2/SEC2"];
112     // Power
113     convert["WATTS"]["HP"] = 0.001341022;
114     convert["HP"]["WATTS"] = 1.0/convert["WATTS"]["HP"];
115     // Force
116     convert["N"]["LBS"] = 0.22482;
117     convert["LBS"]["N"] = 1.0/convert["N"]["LBS"];
118     // Velocity
119     convert["KTS"]["FT/SEC"] = 1.68781;
120     convert["FT/SEC"]["KTS"] = 1.0/convert["KTS"]["FT/SEC"];
121     convert["M/S"]["FT/S"] = 3.2808399;
122     convert["M/SEC"]["FT/SEC"] = 3.2808399;
123     convert["FT/S"]["M/S"] = 1.0/convert["M/S"]["FT/S"];
124     convert["M/SEC"]["FT/SEC"] = 3.2808399;
125     convert["FT/SEC"]["M/SEC"] = 1.0/convert["M/SEC"]["FT/SEC"];
126     convert["KM/SEC"]["FT/SEC"] = 3280.8399;
127     convert["FT/SEC"]["KM/SEC"] = 1.0/convert["KM/SEC"]["FT/SEC"];
128     // Torque
129     convert["FT*LBS"]["N*M"] = 1.35581795;
130     convert["N*M"]["FT*LBS"] = 1/convert["FT*LBS"]["N*M"];
131     // Valve
132     convert["M4*SEC/KG"]["FT4*SEC/SLUG"] = convert["M"]["FT"]*convert["M"]["FT"]*
133       convert["M"]["FT"]*convert["M"]["FT"]/convert["KG"]["SLUG"];
134     convert["FT4*SEC/SLUG"]["M4*SEC/KG"] =
135       1.0/convert["M4*SEC/KG"]["FT4*SEC/SLUG"];
136     // Pressure
137     convert["INHG"]["PSF"] = 70.7180803;
138     convert["PSF"]["INHG"] = 1.0/convert["INHG"]["PSF"];
139     convert["ATM"]["INHG"] = 29.9246899;
140     convert["INHG"]["ATM"] = 1.0/convert["ATM"]["INHG"];
141     convert["PSI"]["INHG"] = 2.03625437;
142     convert["INHG"]["PSI"] = 1.0/convert["PSI"]["INHG"];
143     convert["INHG"]["PA"] = 3386.0; // inches Mercury to pascals
144     convert["PA"]["INHG"] = 1.0/convert["INHG"]["PA"];
145     convert["LBS/FT2"]["N/M2"] = 14.5939/convert["FT"]["M"];
146     convert["N/M2"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["N/M2"];
147     convert["LBS/FT2"]["PA"] = convert["LBS/FT2"]["N/M2"];
148     convert["PA"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["PA"];
149     // Mass flow
150     convert["KG/MIN"]["LBS/MIN"] = convert["KG"]["LBS"];
151     // Fuel Consumption
152     convert["LBS/HP*HR"]["KG/KW*HR"] = 0.6083;
153     convert["KG/KW*HR"]["LBS/HP*HR"] = 1.0/convert["LBS/HP*HR"]["KG/KW*HR"];
154     // Density
155     convert["KG/L"]["LBS/GAL"] = 8.3454045;
156     convert["LBS/GAL"]["KG/L"] = 1.0/convert["KG/L"]["LBS/GAL"];
157
158     // Length
159     convert["M"]["M"] = 1.00;
160     convert["KM"]["KM"] = 1.00;
161     convert["FT"]["FT"] = 1.00;
162     convert["IN"]["IN"] = 1.00;
163     // Area
164     convert["M2"]["M2"] = 1.00;
165     convert["FT2"]["FT2"] = 1.00;
166     // Volume
167     convert["IN3"]["IN3"] = 1.00;
168     convert["CC"]["CC"] = 1.0;
169     convert["M3"]["M3"] = 1.0;
170     convert["FT3"]["FT3"] = 1.0;
171     convert["LTR"]["LTR"] = 1.0;
172     // Mass & Weight
173     convert["KG"]["KG"] = 1.00;
174     convert["LBS"]["LBS"] = 1.00;
175     // Moments of Inertia
176     convert["KG*M2"]["KG*M2"] = 1.00;
177     convert["SLUG*FT2"]["SLUG*FT2"] = 1.00;
178     // Angles
179     convert["DEG"]["DEG"] = 1.00;
180     convert["RAD"]["RAD"] = 1.00;
181     // Angular rates
182     convert["DEG/SEC"]["DEG/SEC"] = 1.00;
183     convert["RAD/SEC"]["RAD/SEC"] = 1.00;
184     // Spring force
185     convert["LBS/FT"]["LBS/FT"] = 1.00;
186     convert["N/M"]["N/M"] = 1.00;
187     // Damping force
188     convert["LBS/FT/SEC"]["LBS/FT/SEC"] = 1.00;
189     convert["N/M/SEC"]["N/M/SEC"] = 1.00;
190     // Damping force (Square law)
191     convert["LBS/FT2/SEC2"]["LBS/FT2/SEC2"] = 1.00;
192     convert["N/M2/SEC2"]["N/M2/SEC2"] = 1.00;
193     // Power
194     convert["HP"]["HP"] = 1.00;
195     convert["WATTS"]["WATTS"] = 1.00;
196     // Force
197     convert["N"]["N"] = 1.00;
198     // Velocity
199     convert["FT/SEC"]["FT/SEC"] = 1.00;
200     convert["KTS"]["KTS"] = 1.00;
201     convert["M/S"]["M/S"] = 1.0;
202     convert["M/SEC"]["M/SEC"] = 1.0;
203     convert["KM/SEC"]["KM/SEC"] = 1.0;
204     // Torque
205     convert["FT*LBS"]["FT*LBS"] = 1.00;
206     convert["N*M"]["N*M"] = 1.00;
207     // Valve
208     convert["M4*SEC/KG"]["M4*SEC/KG"] = 1.0;
209     convert["FT4*SEC/SLUG"]["FT4*SEC/SLUG"] = 1.0;
210     // Pressure
211     convert["PSI"]["PSI"] = 1.00;
212     convert["PSF"]["PSF"] = 1.00;
213     convert["INHG"]["INHG"] = 1.00;
214     convert["ATM"]["ATM"] = 1.0;
215     convert["PA"]["PA"] = 1.0;
216     convert["N/M2"]["N/M2"] = 1.00;
217     convert["LBS/FT2"]["LBS/FT2"] = 1.00;
218     // Mass flow
219     convert["LBS/SEC"]["LBS/SEC"] = 1.00;
220     convert["KG/MIN"]["KG/MIN"] = 1.0;
221     convert["LBS/MIN"]["LBS/MIN"] = 1.0;
222     // Fuel Consumption
223     convert["LBS/HP*HR"]["LBS/HP*HR"] = 1.0;
224     convert["KG/KW*HR"]["KG/KW*HR"] = 1.0;
225     // Density
226     convert["KG/L"]["KG/L"] = 1.0;
227     convert["LBS/GAL"]["LBS/GAL"] = 1.0;
228   }
229 }
230
231 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232
233 Element::~Element(void)
234 {
235   for (unsigned int i=0; i<children.size(); i++) delete children[i];
236   data_lines.clear();
237   attributes.clear();
238   attribute_key.clear();
239 }
240
241 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242
243 string Element::GetAttributeValue(const string& attr)
244 {
245   int select=-1;
246   for (unsigned int i=0; i<attribute_key.size(); i++) {
247     if (attribute_key[i] == attr) select = i;
248   }
249   if (select < 0) return string("");
250   else return attributes[attr];
251 }
252
253 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
254
255 double Element::GetAttributeValueAsNumber(const string& attr)
256 {
257   string attribute = GetAttributeValue(attr);
258
259   if (attribute.empty()) return HUGE_VAL;
260   else return (atof(attribute.c_str()));
261 }
262
263 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
264
265 Element* Element::GetElement(unsigned int el)
266 {
267   if (children.size() > el) {
268     element_index = el;
269     return children[el];
270   }
271   else {
272     element_index = 0;
273     return 0L;
274   }
275 }
276
277 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
278
279 Element* Element::GetNextElement(void)
280 {
281   if (children.size() > element_index+1) {
282     element_index++;
283     return children[element_index];
284   } else {
285     element_index = 0;
286     return 0L;
287   }
288 }
289
290 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291
292 string Element::GetDataLine(unsigned int i)
293 {
294   if (data_lines.size() > 0) return data_lines[i];
295   else return string("");
296 }
297
298 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299
300 double Element::GetDataAsNumber(void)
301 {
302   if (data_lines.size() == 1) {
303     return atof(data_lines[0].c_str());
304   } else if (data_lines.size() == 0) {
305     return HUGE_VAL;
306   } else {
307     cerr << "Attempting to get single data value from multiple lines in element " << name << endl;
308     return HUGE_VAL;
309   }
310 }
311
312 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313
314 unsigned int Element::GetNumElements(const string& element_name)
315 {
316   unsigned int number_of_elements=0;
317   Element* el=FindElement(element_name);
318   while (el) {
319     number_of_elements++;
320     el=FindNextElement(element_name);
321   }
322   return number_of_elements;
323 }
324
325 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326
327 Element* Element::FindElement(const string& el)
328 {
329   if (el.empty() && children.size() >= 1) {
330     element_index = 1;
331     return children[0];
332   }
333   for (unsigned int i=0; i<children.size(); i++) {
334     if (el == children[i]->GetName()) {
335       element_index = i+1;
336       return children[i];
337     }
338   }
339   element_index = 0;
340   return 0L;
341 }
342
343 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344
345 Element* Element::FindNextElement(const string& el)
346 {
347   if (el.empty()) {
348     if (element_index < children.size()) {
349       return children[element_index++];
350     } else {
351       element_index = 0;
352       return 0L;
353     }
354   }
355   for (unsigned int i=element_index; i<children.size(); i++) {
356     if (el == children[i]->GetName()) {
357       element_index = i+1;
358       return children[i];
359     }
360   }
361   element_index = 0;
362   return 0L;
363 }
364
365 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366
367 double Element::FindElementValueAsNumber(const string& el)
368 {
369   Element* element = FindElement(el);
370   if (element) {
371     return element->GetDataAsNumber();
372   } else {
373     cerr << "Attempting to get single data value from multiple lines" << endl;
374     return 0;
375   }
376 }
377
378 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379
380 string Element::FindElementValue(const string& el)
381 {
382   Element* element = FindElement(el);
383   if (element) {
384     return element->GetDataLine();
385   } else {
386     return "";
387   }
388 }
389
390 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
391
392 double Element::FindElementValueAsNumberConvertTo(const string& el, const string& target_units)
393 {
394   Element* element = FindElement(el);
395
396   if (!element) {
397     cerr << "Attempting to get non-existent element " << el << endl;
398     exit(0);
399   }
400
401   string supplied_units = element->GetAttributeValue("unit");
402
403   if (!supplied_units.empty()) {
404     if (convert.find(supplied_units) == convert.end()) {
405       cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
406            << " conversion in FGXMLElement.cpp." << endl;
407       exit(-1);
408     }
409     if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
410       cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
411                    << target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
412       exit(-1);
413     }
414   }
415
416   double value = element->GetDataAsNumber();
417   if (!supplied_units.empty()) {
418     value *= convert[supplied_units][target_units];
419   }
420
421   return value;
422 }
423
424 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
425
426 double Element::FindElementValueAsNumberConvertFromTo( const string& el,
427                                                        const string& supplied_units,
428                                                        const string& target_units)
429 {
430   Element* element = FindElement(el);
431
432   if (!element) {
433     cerr << "Attempting to get non-existent element " << el << endl;
434     exit(0);
435   }
436
437   if (!supplied_units.empty()) {
438     if (convert.find(supplied_units) == convert.end()) {
439       cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
440            << " conversion in FGXMLElement.cpp." << endl;
441       exit(-1);
442     }
443     if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
444       cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
445                    << target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
446       exit(-1);
447     }
448   }
449
450   double value = element->GetDataAsNumber();
451   if (!supplied_units.empty()) {
452     value *= convert[supplied_units][target_units];
453   }
454
455   return value;
456 }
457
458 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
459
460 FGColumnVector3 Element::FindElementTripletConvertTo( const string& target_units)
461 {
462   FGColumnVector3 triplet;
463   Element* item;
464   double value=0.0;
465   string supplied_units = GetAttributeValue("unit");
466
467   if (!supplied_units.empty()) {
468     if (convert.find(supplied_units) == convert.end()) {
469       cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
470            << " conversion in FGXMLElement.cpp." << endl;
471       exit(-1);
472     }
473     if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
474       cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
475                    << target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
476       exit(-1);
477     }
478   }
479
480   item = FindElement("x");
481   if (!item) item = FindElement("roll");
482   if (item) {
483     value = item->GetDataAsNumber();
484     if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
485   } else {
486     value = 0.0;
487   }
488   triplet(1) = value;
489
490   item = FindElement("y");
491   if (!item) item = FindElement("pitch");
492   if (item) {
493     value = item->GetDataAsNumber();
494     if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
495   } else {
496     value = 0.0;
497   }
498   triplet(2) = value;
499
500   item = FindElement("z");
501   if (!item) item = FindElement("yaw");
502   if (item) {
503     value = item->GetDataAsNumber();
504     if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
505   } else {
506     value = 0.0;
507   }
508   triplet(3) = value;
509
510   return triplet;
511 }
512
513 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
514
515 void Element::Print(unsigned int level)
516 {
517   unsigned int i, spaces;
518
519   level+=2;
520   for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
521   cout << "Element Name: " << name;
522   for (i=0; i<attributes.size(); i++) {
523     cout << "  " << attribute_key[i] << " = " << attributes[attribute_key[i]];
524   }
525   cout << endl;
526   for (i=0; i<data_lines.size(); i++) {
527     for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
528     cout << data_lines[i] << endl;
529   }
530   for (i=0; i<children.size(); i++) {
531     children[i]->Print(level);
532   }
533 }
534
535 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
536
537 void Element::AddAttribute(const string& name, const string& value)
538 {
539   attribute_key.push_back(name);
540   attributes[name] = value;
541 }
542
543 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
544
545 void Element::AddData(string d)
546 {
547   string::size_type string_start = d.find_first_not_of(" \t");
548   if (string_start != string::npos && string_start > 0) {
549     d.erase(0,string_start);
550   }
551   data_lines.push_back(d);
552 }
553
554 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
555
556 } // end namespace JSBSim