1 /***************************************************************************
2  *  Copyright 2014, 2015 Marcelo Y. Matuda                                 *
3  *  Copyright 1991, 1992, 1993, 1994, 1995, 1996, 2001, 2002               *
4  *    David R. Hill, Leonard Manzara, Craig Schock                         *
5  *                                                                         *
6  *  This program is free software: you can redistribute it and/or modify   *
7  *  it under the terms of the GNU General Public License as published by   *
8  *  the Free Software Foundation, either version 3 of the License, or      *
9  *  (at your option) any later version.                                    *
10  *                                                                         *
11  *  This program is distributed in the hope that it will be useful,        *
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
14  *  GNU General Public License for more details.                           *
15  *                                                                         *
16  *  You should have received a copy of the GNU General Public License      *
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
18  ***************************************************************************/
19 // 2014-09
20 // This file was created by Marcelo Y. Matuda, and code/information
21 // from Gnuspeech was added to it later.
22 
23 #include "XMLConfigFileReader.h"
24 
25 #include <memory>
26 
27 #include "Exception.h"
28 #include "Log.h"
29 #include "Model.h"
30 #include "RapidXmlUtil.h"
31 #include "Text.h"
32 
33 
34 
35 using namespace rapidxml;
36 
37 namespace {
38 
39 const std::string booleanExpressionTagName   = "boolean-expression";
40 const std::string booleanExpressionsTagName  = "boolean-expressions";
41 const std::string categoriesTagName          = "categories";
42 const std::string categoryTagName            = "category";
43 const std::string categoryRefTagName         = "category-ref";
44 const std::string commentTagName             = "comment";
45 const std::string equationTagName            = "equation";
46 const std::string equationGroupTagName       = "equation-group";
47 const std::string equationsTagName           = "equations";
48 const std::string expressionSymbolsTagName   = "expression-symbols";
49 const std::string parameterTagName           = "parameter";
50 const std::string parameterProfilesTagName   = "parameter-profiles";
51 const std::string parametersTagName          = "parameters";
52 const std::string parameterTargetsTagName    = "parameter-targets";
53 const std::string parameterTransitionTagName = "parameter-transition";
54 const std::string pointOrSlopesTagName       = "point-or-slopes";
55 const std::string pointTagName               = "point";
56 const std::string pointsTagName              = "points";
57 const std::string postureCategoriesTagName   = "posture-categories";
58 const std::string posturesTagName            = "postures";
59 const std::string postureTagName             = "posture";
60 const std::string ruleTagName                = "rule";
61 const std::string rulesTagName               = "rules";
62 const std::string slopeTagName               = "slope";
63 const std::string slopeRatioTagName          = "slope-ratio";
64 const std::string slopesTagName              = "slopes";
65 const std::string specialProfilesTagName     = "special-profiles";
66 const std::string specialTransitionsTagName  = "special-transitions";
67 const std::string symbolEquationTagName      = "symbol-equation";
68 const std::string symbolsTagName             = "symbols";
69 const std::string symbolTagName              = "symbol";
70 const std::string symbolTargetsTagName       = "symbol-targets";
71 const std::string targetTagName              = "target";
72 const std::string transitionTagName          = "transition";
73 const std::string transitionGroupTagName     = "transition-group";
74 const std::string transitionsTagName         = "transitions";
75 
76 const std::string defaultAttrName        = "default";
77 const std::string displayTimeAttrName    = "display-time";
78 const std::string equationAttrName       = "equation";
79 const std::string formulaAttrName        = "formula";
80 const std::string freeTimeAttrName       = "free-time";
81 const std::string isPhantomAttrName      = "is-phantom";
82 const std::string maximumAttrName        = "maximum";
83 const std::string minimumAttrName        = "minimum";
84 const std::string nameAttrName           = "name";
85 const std::string p12AttrName            = "p12";
86 const std::string p23AttrName            = "p23";
87 const std::string p34AttrName            = "p34";
88 const std::string slopeAttrName          = "slope";
89 const std::string symbolAttrName         = "symbol";
90 const std::string timeExpressionAttrName = "time-expression";
91 const std::string typeAttrName           = "type";
92 const std::string transitionAttrName     = "transition";
93 const std::string valueAttrName          = "value";
94 
95 const std::string beatSymbolName       = "beat";
96 const std::string durationSymbolName   = "duration";
97 const std::string mark1SymbolName      = "mark1";
98 const std::string mark2SymbolName      = "mark2";
99 const std::string mark3SymbolName      = "mark3";
100 const std::string qssaSymbolName       = "qssa";
101 const std::string qssbSymbolName       = "qssb";
102 const std::string rdSymbolName         = "rd";
103 const std::string transitionSymbolName = "transition";
104 
105 } /* namespace */
106 
107 namespace GS {
108 namespace TRMControlModel {
109 
110 void
parseCategories(rapidxml::xml_node<char> * categoriesElem)111 XMLConfigFileReader::parseCategories(rapidxml::xml_node<char>* categoriesElem)
112 {
113 	for (xml_node<char>* categoryElem = firstChild(categoriesElem, categoryTagName);
114 				categoryElem;
115 				categoryElem = nextSibling(categoryElem, categoryTagName)) {
116 
117 		std::shared_ptr<Category> newCategory(new Category(attributeValue(categoryElem, nameAttrName)));
118 		model_.categoryList().push_back(newCategory);
119 
120 		xml_node<char>* commentElem = firstChild(categoryElem, commentTagName);
121 		if (commentElem) {
122 			model_.categoryList().back()->setComment(commentElem->value());
123 		}
124 	}
125 }
126 
127 void
parseParameters(rapidxml::xml_node<char> * parametersElem)128 XMLConfigFileReader::parseParameters(rapidxml::xml_node<char>* parametersElem)
129 {
130 	for (xml_node<char>* parameterElem = firstChild(parametersElem, parameterTagName);
131 				parameterElem;
132 				parameterElem = nextSibling(parameterElem, parameterTagName)) {
133 
134 		std::string name   = attributeValue(parameterElem, nameAttrName);
135 		float minimum      = Text::parseString<float>(attributeValue(parameterElem, minimumAttrName));
136 		float maximum      = Text::parseString<float>(attributeValue(parameterElem, maximumAttrName));
137 		float defaultValue = Text::parseString<float>(attributeValue(parameterElem, defaultAttrName));
138 		std::string comment;
139 
140 		xml_node<char>* commentElem = firstChild(parameterElem, commentTagName);
141 		if (commentElem) {
142 			comment = commentElem->value();
143 		}
144 
145 		model_.parameterList().emplace_back(name, minimum, maximum, defaultValue, comment);
146 	}
147 }
148 
149 void
parseSymbols(rapidxml::xml_node<char> * symbolsElem)150 XMLConfigFileReader::parseSymbols(rapidxml::xml_node<char>* symbolsElem)
151 {
152 	for (xml_node<char>* symbolElem = firstChild(symbolsElem, symbolTagName);
153 				symbolElem;
154 				symbolElem = nextSibling(symbolElem, symbolTagName)) {
155 
156 		std::string name   = attributeValue(symbolElem, nameAttrName);
157 		float minimum      = Text::parseString<float>(attributeValue(symbolElem, minimumAttrName));
158 		float maximum      = Text::parseString<float>(attributeValue(symbolElem, maximumAttrName));
159 		float defaultValue = Text::parseString<float>(attributeValue(symbolElem, defaultAttrName));
160 		std::string comment;
161 
162 		xml_node<char>* commentElem = firstChild(symbolElem, commentTagName);
163 		if (commentElem) {
164 			comment = commentElem->value();
165 		}
166 
167 		model_.symbolList().emplace_back(name, minimum, maximum, defaultValue, comment);
168 	}
169 }
170 
171 void
parsePostureSymbols(rapidxml::xml_node<char> * symbolTargetsElem,Posture & posture)172 XMLConfigFileReader::parsePostureSymbols(rapidxml::xml_node<char>* symbolTargetsElem, Posture& posture)
173 {
174 	for (xml_node<char>* targetElem = firstChild(symbolTargetsElem, targetTagName);
175 				targetElem;
176 				targetElem = nextSibling(targetElem, targetTagName)) {
177 
178 		const std::string name = attributeValue(targetElem, nameAttrName);
179 		const std::string value = attributeValue(targetElem, valueAttrName);
180 		for (unsigned int i = 0, size = model_.symbolList().size(); i < size; ++i) {
181 			const Symbol& symbol = model_.symbolList()[i];
182 			if (symbol.name() == name) {
183 				posture.setSymbolTarget(i, Text::parseString<float>(value));
184 			}
185 		}
186 	}
187 }
188 
189 void
parsePostureCategories(rapidxml::xml_node<char> * postureCategoriesElem,Posture & posture)190 XMLConfigFileReader::parsePostureCategories(rapidxml::xml_node<char>* postureCategoriesElem, Posture& posture)
191 {
192 	for (xml_node<char>* catRefElem = firstChild(postureCategoriesElem, categoryRefTagName);
193 				catRefElem;
194 				catRefElem = nextSibling(catRefElem, categoryRefTagName)) {
195 
196 		const std::string name = attributeValue(catRefElem, nameAttrName);
197 		if (name != posture.name()) {
198 			std::shared_ptr<Category> postureCat = model_.findCategory(name);
199 			if (!postureCat) {
200 				THROW_EXCEPTION(TRMControlModelException, "Posture category not found: " << name << '.');
201 			}
202 			posture.categoryList().push_back(postureCat);
203 		}
204 	}
205 }
206 
207 void
parsePostureParameters(rapidxml::xml_node<char> * parameterTargetsElem,Posture & posture)208 XMLConfigFileReader::parsePostureParameters(rapidxml::xml_node<char>* parameterTargetsElem, Posture& posture)
209 {
210 	for (xml_node<char>* targetElem = firstChild(parameterTargetsElem, targetTagName);
211 				targetElem;
212 				targetElem = nextSibling(targetElem, targetTagName)) {
213 
214 		std::string parameterName = attributeValue(targetElem, nameAttrName);
215 		unsigned int parameterIndex = model_.findParameterIndex(parameterName);
216 
217 		posture.setParameterTarget(parameterIndex, Text::parseString<float>(attributeValue(targetElem, valueAttrName)));
218 	}
219 }
220 
221 void
parsePosture(rapidxml::xml_node<char> * postureElem)222 XMLConfigFileReader::parsePosture(rapidxml::xml_node<char>* postureElem)
223 {
224 	std::unique_ptr<Posture> posture(new Posture(
225 						attributeValue(postureElem, symbolAttrName),
226 						model_.parameterList().size(),
227 						model_.symbolList().size()));
228 
229 	for (xml_node<char>* childElem = firstChild(postureElem);
230 				childElem;
231 				childElem = nextSibling(childElem)) {
232 		if (compareElementName(childElem, postureCategoriesTagName)) {
233 			parsePostureCategories(childElem, *posture);
234 		} else if (compareElementName(childElem, parameterTargetsTagName)) {
235 			parsePostureParameters(childElem, *posture);
236 		} else if (compareElementName(childElem, symbolTargetsTagName)) {
237 			parsePostureSymbols(childElem, *posture);
238 		} else if (compareElementName(childElem, commentTagName)) {
239 			posture->setComment(childElem->value());
240 		}
241 	}
242 
243 	model_.postureList().add(std::move(posture));
244 }
245 
246 void
parsePostures(rapidxml::xml_node<char> * posturesElem)247 XMLConfigFileReader::parsePostures(rapidxml::xml_node<char>* posturesElem)
248 {
249 	for (xml_node<char>* postureElem = firstChild(posturesElem, postureTagName);
250 				postureElem;
251 				postureElem = nextSibling(postureElem, postureTagName)) {
252 		parsePosture(postureElem);
253 	}
254 }
255 
256 void
parseEquationsGroup(rapidxml::xml_node<char> * equationGroupElem)257 XMLConfigFileReader::parseEquationsGroup(rapidxml::xml_node<char>* equationGroupElem)
258 {
259 	EquationGroup group;
260 	group.name = attributeValue(equationGroupElem, nameAttrName);
261 
262 	for (xml_node<char>* equationElem = firstChild(equationGroupElem, equationTagName);
263 				equationElem;
264 				equationElem = nextSibling(equationElem, equationTagName)) {
265 
266 		std::string name = attributeValue(equationElem, nameAttrName);
267 		std::string formula = attributeValue(equationElem, formulaAttrName, true);
268 		std::string comment;
269 		xml_node<char>* commentElem = firstChild(equationElem, commentTagName);
270 		if (commentElem) {
271 			comment = commentElem->value();
272 		}
273 
274 		if (formula.empty()) {
275 			LOG_ERROR("Equation " << name << " without formula (ignored).");
276 		} else {
277 			std::shared_ptr<Equation> eq(new Equation(name));
278 			eq->setFormula(formula);
279 			if (!comment.empty()) {
280 				eq->setComment(comment);
281 			}
282 
283 			group.equationList.push_back(eq);
284 		}
285 	}
286 
287 	model_.equationGroupList().push_back(std::move(group));
288 }
289 
290 void
parseEquations(rapidxml::xml_node<char> * equationsElem)291 XMLConfigFileReader::parseEquations(rapidxml::xml_node<char>* equationsElem)
292 {
293 	for (xml_node<char>* groupElem = firstChild(equationsElem, equationGroupTagName);
294 				groupElem;
295 				groupElem = nextSibling(groupElem, equationGroupTagName)) {
296 		parseEquationsGroup(groupElem);
297 	}
298 }
299 
300 void
parseSlopeRatio(rapidxml::xml_node<char> * slopeRatioElem,Transition & transition)301 XMLConfigFileReader::parseSlopeRatio(rapidxml::xml_node<char>* slopeRatioElem, Transition& transition)
302 {
303 	std::unique_ptr<Transition::SlopeRatio> p(new Transition::SlopeRatio());
304 
305 	for (xml_node<char>* childElem = firstChild(slopeRatioElem);
306 				childElem;
307 				childElem = nextSibling(childElem)) {
308 		if (compareElementName(childElem, pointsTagName)) {
309 			for (xml_node<char>* pointElem = firstChild(childElem, pointTagName);
310 						pointElem;
311 						pointElem = nextSibling(pointElem, pointTagName)) {
312 				std::unique_ptr<Transition::Point> p2(new Transition::Point());
313 				p2->type = Transition::Point::getTypeFromName(attributeValue(pointElem, typeAttrName));
314 				p2->value = Text::parseString<float>(attributeValue(pointElem, valueAttrName));
315 
316 				const std::string timeExpr = attributeValue(pointElem, timeExpressionAttrName, true);
317 				if (timeExpr.empty()) {
318 					p2->freeTime = Text::parseString<float>(attributeValue(pointElem, freeTimeAttrName));
319 				} else {
320 					std::shared_ptr<Equation> equation = model_.findEquation(timeExpr);
321 					if (!equation) {
322 						THROW_EXCEPTION(UnavailableResourceException, "Equation not found: " << timeExpr << '.');
323 					}
324 					p2->timeExpression = equation;
325 				}
326 
327 				if (std::string("yes") == attributeValue(pointElem, isPhantomAttrName, true)) {
328 					p2->isPhantom = true;
329 				}
330 				p->pointList.push_back(std::move(p2));
331 			}
332 		} else if (compareElementName(childElem, slopesTagName)) {
333 			for (xml_node<char>* slopeElem = firstChild(childElem, slopeTagName);
334 						slopeElem;
335 						slopeElem = nextSibling(slopeElem, slopeTagName)) {
336 				std::unique_ptr<Transition::Slope> p2(new Transition::Slope());
337 				p2->slope = Text::parseString<float>(attributeValue(slopeElem, slopeAttrName));
338 				p2->displayTime = Text::parseString<float>(attributeValue(slopeElem, displayTimeAttrName));
339 				p->slopeList.push_back(std::move(p2));
340 			}
341 		}
342 	}
343 
344 	transition.pointOrSlopeList().push_back(std::move(p));
345 }
346 
347 void
parseTransitionPointOrSlopes(rapidxml::xml_node<char> * pointOrSlopesElem,Transition & transition)348 XMLConfigFileReader::parseTransitionPointOrSlopes(rapidxml::xml_node<char>* pointOrSlopesElem, Transition& transition)
349 {
350 	for (xml_node<char>* childElem = firstChild(pointOrSlopesElem);
351 				childElem;
352 				childElem = nextSibling(childElem)) {
353 		if (compareElementName(childElem, pointTagName)) {
354 			std::unique_ptr<Transition::Point> p(new Transition::Point());
355 			p->type = Transition::Point::getTypeFromName(attributeValue(childElem, typeAttrName));
356 			p->value = Text::parseString<float>(attributeValue(childElem, valueAttrName));
357 
358 			const std::string timeExpr = attributeValue(childElem, timeExpressionAttrName, true);
359 			if (timeExpr.empty()) {
360 				p->freeTime = Text::parseString<float>(attributeValue(childElem, freeTimeAttrName));
361 			} else {
362 				std::shared_ptr<Equation> equation = model_.findEquation(timeExpr);
363 				if (!equation) {
364 					THROW_EXCEPTION(UnavailableResourceException, "Equation not found: " << timeExpr << '.');
365 				}
366 				p->timeExpression = equation;
367 			}
368 
369 			if (std::string("yes") == attributeValue(childElem, isPhantomAttrName, true)) {
370 				p->isPhantom = true;
371 			}
372 			transition.pointOrSlopeList().push_back(std::move(p));
373 		} else if (compareElementName(childElem, slopeRatioTagName)) {
374 			parseSlopeRatio(childElem, transition);
375 		}
376 	}
377 }
378 
379 void
parseTransitionsGroup(rapidxml::xml_node<char> * transitionGroupElem,bool special)380 XMLConfigFileReader::parseTransitionsGroup(rapidxml::xml_node<char>* transitionGroupElem, bool special)
381 {
382 	TransitionGroup group;
383 	group.name = attributeValue(transitionGroupElem, nameAttrName);
384 
385 	for (xml_node<char>* childElem = firstChild(transitionGroupElem,transitionTagName);
386 				childElem;
387 				childElem = nextSibling(childElem, transitionTagName)) {
388 
389 		std::string name = attributeValue(childElem, nameAttrName);
390 		Transition::Type type = Transition::getTypeFromName(attributeValue(childElem, typeAttrName));
391 
392 		std::shared_ptr<Transition> tr(new Transition(name, type, special));
393 
394 		for (xml_node<char>* transitionChildElem = firstChild(childElem);
395 					transitionChildElem;
396 					transitionChildElem = nextSibling(transitionChildElem)) {
397 			if (compareElementName(transitionChildElem, pointOrSlopesTagName)) {
398 				parseTransitionPointOrSlopes(transitionChildElem, *tr);
399 			} else if (compareElementName(transitionChildElem, commentTagName)) {
400 				tr->setComment(transitionChildElem->value());
401 			}
402 		}
403 
404 		group.transitionList.push_back(tr);
405 	}
406 
407 	if (special) {
408 		model_.specialTransitionGroupList().push_back(std::move(group));
409 	} else {
410 		model_.transitionGroupList().push_back(std::move(group));
411 	}
412 }
413 
414 void
parseTransitions(rapidxml::xml_node<char> * transitionsElem,bool special)415 XMLConfigFileReader::parseTransitions(rapidxml::xml_node<char>* transitionsElem, bool special)
416 {
417 	for (xml_node<char>* groupElem = firstChild(transitionsElem, transitionGroupTagName);
418 				groupElem;
419 				groupElem = nextSibling(groupElem, transitionGroupTagName)) {
420 		parseTransitionsGroup(groupElem, special);
421 	}
422 }
423 
424 void
parseRuleParameterProfiles(rapidxml::xml_node<char> * parameterProfilesElem,Rule & rule)425 XMLConfigFileReader::parseRuleParameterProfiles(rapidxml::xml_node<char>* parameterProfilesElem, Rule& rule)
426 {
427 	for (xml_node<char>* paramTransElem = firstChild(parameterProfilesElem,parameterTransitionTagName);
428 				paramTransElem;
429 				paramTransElem = nextSibling(paramTransElem, parameterTransitionTagName)) {
430 
431 		std::string parameterName = attributeValue(paramTransElem, nameAttrName);
432 		unsigned int parameterIndex = model_.findParameterIndex(parameterName);
433 
434 		const std::string transitionName = attributeValue(paramTransElem, transitionAttrName);
435 		std::shared_ptr<Transition> transition = model_.findTransition(transitionName);
436 		if (!transition) {
437 			THROW_EXCEPTION(UnavailableResourceException, "Transition not found: " << transitionName << '.');
438 		}
439 
440 		rule.setParamProfileTransition(parameterIndex, transition);
441 	}
442 }
443 
444 void
parseRuleSpecialProfiles(rapidxml::xml_node<char> * specialProfilesElem,Rule & rule)445 XMLConfigFileReader::parseRuleSpecialProfiles(rapidxml::xml_node<char>* specialProfilesElem, Rule& rule)
446 {
447 	for (xml_node<char>* paramTransElem = firstChild(specialProfilesElem, parameterTransitionTagName);
448 				paramTransElem;
449 				paramTransElem = nextSibling(paramTransElem, parameterTransitionTagName)) {
450 
451 		std::string parameterName = attributeValue(paramTransElem, nameAttrName);
452 		unsigned int parameterIndex = model_.findParameterIndex(parameterName);
453 
454 		const std::string transitionName = attributeValue(paramTransElem, transitionAttrName);
455 		std::shared_ptr<Transition> transition = model_.findSpecialTransition(transitionName);
456 		if (!transition) {
457 			THROW_EXCEPTION(UnavailableResourceException, "Special transition not found: " << transitionName << '.');
458 		}
459 
460 		rule.setSpecialProfileTransition(parameterIndex, transition);
461 	}
462 }
463 
464 void
parseRuleExpressionSymbols(rapidxml::xml_node<char> * expressionSymbolsElem,Rule & rule)465 XMLConfigFileReader::parseRuleExpressionSymbols(rapidxml::xml_node<char>* expressionSymbolsElem, Rule& rule)
466 {
467 	for (xml_node<char>* symbEquElem = firstChild(expressionSymbolsElem, symbolEquationTagName);
468 				symbEquElem;
469 				symbEquElem = nextSibling(symbEquElem, symbolEquationTagName)) {
470 
471 		const std::string name = attributeValue(symbEquElem, nameAttrName);
472 		const std::string equationName = attributeValue(symbEquElem, equationAttrName);
473 
474 		std::shared_ptr<Equation> equation = model_.findEquation(equationName);
475 		if (!equation) {
476 			THROW_EXCEPTION(UnavailableResourceException, "Equation not found: " << equationName << '.');
477 		}
478 
479 		if (name == rdSymbolName) {
480 			rule.exprSymbolEquations().ruleDuration = equation;
481 		} else if (name == beatSymbolName) {
482 			rule.exprSymbolEquations().beat = equation;
483 		} else if (name == mark1SymbolName) {
484 			rule.exprSymbolEquations().mark1 = equation;
485 		} else if (name == mark2SymbolName) {
486 			rule.exprSymbolEquations().mark2 = equation;
487 		} else if (name == mark3SymbolName) {
488 			rule.exprSymbolEquations().mark3 = equation;
489 		}
490 	}
491 }
492 
493 void
parseRuleBooleanExpressions(rapidxml::xml_node<char> * booleanExpressionsElem,Rule & rule)494 XMLConfigFileReader::parseRuleBooleanExpressions(rapidxml::xml_node<char>* booleanExpressionsElem, Rule& rule)
495 {
496 	std::vector<std::string> exprList;
497 	for (xml_node<char>* boolExprElem = firstChild(booleanExpressionsElem, booleanExpressionTagName);
498 				boolExprElem;
499 				boolExprElem = nextSibling(boolExprElem, booleanExpressionTagName)) {
500 		exprList.push_back(boolExprElem->value());
501 	}
502 	rule.setBooleanExpressionList(exprList, model_);
503 }
504 
505 void
parseRule(rapidxml::xml_node<char> * ruleElem)506 XMLConfigFileReader::parseRule(rapidxml::xml_node<char>* ruleElem)
507 {
508 	std::unique_ptr<Rule> rule(new Rule(model_.parameterList().size()));
509 
510 	for (xml_node<char>* childElem = firstChild(ruleElem);
511 				childElem;
512 				childElem = nextSibling(childElem)) {
513 		if (compareElementName(childElem, booleanExpressionsTagName)) {
514 			parseRuleBooleanExpressions(childElem, *rule);
515 		} else if (compareElementName(childElem, parameterProfilesTagName)) {
516 			parseRuleParameterProfiles(childElem, *rule);
517 		} else if (compareElementName(childElem, specialProfilesTagName)) {
518 			parseRuleSpecialProfiles(childElem, *rule);
519 		} else if (compareElementName(childElem, expressionSymbolsTagName)) {
520 			parseRuleExpressionSymbols(childElem, *rule);
521 		} else if (compareElementName(childElem, commentTagName)) {
522 			rule->setComment(childElem->value());
523 		}
524 	}
525 
526 	model_.ruleList().push_back(std::move(rule));
527 }
528 
529 void
parseRules(rapidxml::xml_node<char> * rulesElem)530 XMLConfigFileReader::parseRules(rapidxml::xml_node<char>* rulesElem)
531 {
532 	for (xml_node<char>* ruleElem = firstChild(rulesElem, ruleTagName);
533 				ruleElem;
534 				ruleElem = nextSibling(ruleElem, ruleTagName)) {
535 		parseRule(ruleElem);
536 	}
537 }
538 
539 
540 
541 /*******************************************************************************
542  * Constructor.
543  */
XMLConfigFileReader(Model & model,const std::string & filePath)544 XMLConfigFileReader::XMLConfigFileReader(Model& model, const std::string& filePath)
545 		: model_(model)
546 		, filePath_(filePath)
547 {
548 }
549 
550 /*******************************************************************************
551  * Destructor.
552  */
~XMLConfigFileReader()553 XMLConfigFileReader::~XMLConfigFileReader()
554 {
555 }
556 
557 void
loadModel()558 XMLConfigFileReader::loadModel()
559 {
560 	std::string source = readXMLFile(filePath_);
561 	xml_document<char> doc;
562 	doc.parse<parse_no_data_nodes | parse_validate_closing_tags>(&source[0]);
563 
564 	xml_node<char>* root = doc.first_node();
565 	if (root == 0) {
566 		THROW_EXCEPTION(XMLException, "Root element not found.");
567 	}
568 
569 	LOG_DEBUG("categories");
570 	xml_node<char>* categoriesElem = firstChild(root, categoriesTagName);
571 	if (categoriesElem == 0) {
572 		THROW_EXCEPTION(TRMControlModelException, "Categories element not found.");
573 	}
574 	parseCategories(categoriesElem);
575 
576 	LOG_DEBUG("parameters");
577 	xml_node<char>* parametersElem = firstChild(root, parametersTagName);
578 	if (parametersElem == 0) {
579 		THROW_EXCEPTION(TRMControlModelException, "Parameters element not found.");
580 	}
581 	parseParameters(parametersElem);
582 
583 	LOG_DEBUG("symbols");
584 	xml_node<char>* symbolsElem = firstChild(root, symbolsTagName);
585 	if (symbolsElem == 0) {
586 		THROW_EXCEPTION(TRMControlModelException, "Categories element not found.");
587 	}
588 	parseSymbols(symbolsElem);
589 
590 	LOG_DEBUG("postures");
591 	xml_node<char>* posturesElem = firstChild(root, posturesTagName);
592 	if (posturesElem == 0) {
593 		THROW_EXCEPTION(TRMControlModelException, "Postures element not found.");
594 	}
595 	parsePostures(posturesElem);
596 
597 	LOG_DEBUG("equations");
598 	xml_node<char>* equationsElem = firstChild(root, equationsTagName);
599 	if (equationsElem == 0) {
600 		THROW_EXCEPTION(TRMControlModelException, "Equations element not found.");
601 	}
602 	parseEquations(equationsElem);
603 
604 	LOG_DEBUG("transitions");
605 	xml_node<char>* transitionsElem = firstChild(root, transitionsTagName);
606 	if (transitionsElem == 0) {
607 		THROW_EXCEPTION(TRMControlModelException, "Transitions element not found.");
608 	}
609 	parseTransitions(transitionsElem, false);
610 
611 	LOG_DEBUG("special-transitions");
612 	xml_node<char>* specialTransitionsElem = firstChild(root, specialTransitionsTagName);
613 	if (specialTransitionsElem == 0) {
614 		THROW_EXCEPTION(TRMControlModelException, "Special-transitions element not found.");
615 	}
616 	parseTransitions(specialTransitionsElem, true);
617 
618 	LOG_DEBUG("rules");
619 	xml_node<char>* rulesElem = firstChild(root, rulesTagName);
620 	if (rulesElem == 0) {
621 		THROW_EXCEPTION(TRMControlModelException, "Rules element not found.");
622 	}
623 	parseRules(rulesElem);
624 }
625 
626 } /* namespace TRMControlModel */
627 } /* namespace GS */
628