-
Maurice Zimmnau authoredMaurice Zimmnau authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
main.cpp 17.66 KiB
#include <iostream>
#include <filesystem>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <cmath>
// Function to remove a substring from the end of a string
std::string substractStringFromEnd(const std::string& string, const std::string& string_to_substract) {
if (string.size() >= string_to_substract.size() &&
string.compare(string.size() - string_to_substract.size(), string_to_substract.size(), string_to_substract) == 0) {
// If the string ends with the substring, remove it
return string.substr(0, string.size() - string_to_substract.size());
}
// Otherwise, return the original string unchanged
return string;
}
void printPtree(const boost::property_tree::ptree &tree, const std::string &prefix = "") {
for (const auto &node : tree) {
// Print current node name
std::cout << prefix << node.first;
// Print node value only if not empty
if (!node.second.data().empty()) {
std::cout << ": " << node.second.data();
}
std::cout << std::endl;
// Recursively print child nodes
printPtree(node.second, prefix + " ");
}
}
int containsSymbol(const std::string& my_string, const std::string& my_symbol) {
if (my_string.find(my_symbol) != std::string::npos) {
return 1;
} else {
return 0;
}
}
boost::property_tree::ptree getChildTreeFromParentTree(const boost::property_tree::ptree& parent_tree, const std::string& node_name_to_search) {
boost::property_tree::ptree child_tree{};
for (const auto& node : parent_tree) {
if (node.first == node_name_to_search) {
child_tree.add_child(node.first, node.second);
} else {
boost::property_tree::ptree myPtree{};
myPtree = getChildTreeFromParentTree(node.second, node_name_to_search);
for (const auto& child_node : myPtree) {
child_tree.add_child(child_node.first, child_node.second);
}
}
}
return child_tree;
}
unsigned int getNumberOfNodes(const boost::property_tree::ptree& ptree, const std::string& node_name_to_search) {
unsigned int counter{0};
for (const auto& node : ptree) {
if (node.first == node_name_to_search) {
++counter;
}
}
return counter;
}
boost::property_tree::ptree GetSubtreeByAttributevalue(const boost::property_tree::ptree& ptree,
const std::string& node_path,
const std::string& attribute_for_which_to_filter,
const std::string& attribute_value) {
boost::property_tree::ptree subtree{};
boost::property_tree::ptree temp_tree{};
std::string parent_path{node_path.substr(0, node_path.find_last_of('/'))};
std::string child_name{node_path.substr(node_path.find_last_of('/')+1)};
if (!containsSymbol(node_path, "/")) {
parent_path = "";
child_name = node_path;
}
try
{
temp_tree = ptree.get_child(boost::property_tree::ptree::path_type(parent_path, '/'));
}
catch(const std::exception& e)
{
std::cerr << "Error occured at: " << __FILE__ << ", ";
std::cerr << "in function: " << __func__ << "(), ";
std::cerr << "in line: " << __LINE__ << std::endl;
std::cerr << "Error creating xml tree: " << e.what() << std::endl;
std::cerr << "Aborting Programm!" << std::endl;
std::exit(1);
}
for (const auto& node : temp_tree) {
bool bool1{node.first == child_name};
bool bool2{node.second.get_optional<std::string>("<xmlattr>." + attribute_for_which_to_filter) == attribute_value};
if (bool1 && bool2) {
subtree = node.second;
}
}
if (subtree.empty()) {
std::string myMessage{"Could not find node '" + child_name + "' with attribute '" + attribute_for_which_to_filter + "'=" + attribute_value};
throw boost::property_tree::ptree_bad_data(myMessage, subtree);
}
return subtree;
}
enum State {
LoadingConfigFile,
LoadingAircraftDesignFilePaths,
LoadingFilePathsIntoPtrees,
ExtractingConfigTreeInforamtion,
SubstractingNodeValues,
WritingOutput,
ProgrammFinished
};
int main () {
std::filesystem::path config_file_path{"design_evaluator_conf.xml"};
std::vector<std::filesystem::path> aircraft_design_file_paths{};
boost::property_tree::ptree config_tree{}, program_settings_tree{}, subpaths_tree{};
std::vector<boost::property_tree::ptree> aircraft_design_trees{};
std::vector<boost::property_tree::ptree> result_tree{};
State state{State::LoadingConfigFile};
while (true) {
switch (state) {
case State::LoadingConfigFile: {
std::cout << "Current State: " << state << std::endl;
// Check if path is valid
if (!std::filesystem::exists(config_file_path)) {
std::cerr << "Error occured at: " << __FILE__ << ", ";
std::cerr << "in function: " << __func__ << "(), ";
std::cerr << "in line: " << __LINE__ << std::endl;
std::cerr << "File or Path does not exist: " << config_file_path << std::endl;
std::cerr << "Aborting Programm!" << std::endl;
return 1;
}
// If path is valid, store cofig.xml as ptree (Property Tree) object
try
{
boost::property_tree::read_xml(config_file_path.string(),
config_tree,
boost::property_tree::xml_parser::no_comments |
boost::property_tree::xml_parser::trim_whitespace);
}
catch(const std::exception& e)
{
std::cerr << "Error occured at: " << __FILE__ << ", ";
std::cerr << "in function: " << __func__ << "(), ";
std::cerr << "in line: " << __LINE__ << std::endl;
std::cerr << "Error creating xml tree: " << e.what() << std::endl;
std::cerr << "Aborting Programm!" << std::endl;
return 1;
}
state = State::LoadingAircraftDesignFilePaths;
break;
}
case State::LoadingAircraftDesignFilePaths: {
std::cout << "Current State: " << state << std::endl;
program_settings_tree = getChildTreeFromParentTree(config_tree, "aircraft_design");
for (const auto& node : program_settings_tree) {
// if (node.second.get<int>("<xmlattr>.ID") == 0) {
// aircraft_design_file_paths.insert(aircraft_design_file_paths.begin(), node.second.get<std::string>("design_directory") + node.second.get<std::string>("file_name"));
// } else {
// aircraft_design_file_paths.push_back(node.second.get<std::string>("design_directory") + node.second.get<std::string>("file_name"));
// }
aircraft_design_file_paths.push_back(node.second.get<std::string>("design_directory") + node.second.get<std::string>("file_name"));
}
for (const auto& element : aircraft_design_file_paths) {
if (!std::filesystem::exists(element)) {
std::cerr << "Error occured at: " << __FILE__ << ", ";
std::cerr << "in function: " << __func__ << "(), ";
std::cerr << "in line: " << __LINE__ << std::endl;
std::cerr << "File or Path does not exist: " << element << std::endl;
}
}
for (const auto& element : aircraft_design_file_paths) {
if (!std::filesystem::exists(element)) {
std::cerr << "Aborting Programm!" << std::endl;
return 1;
}
}
state = State::LoadingFilePathsIntoPtrees;
break;
}
case State::LoadingFilePathsIntoPtrees: {
std::cout << "Current State: " << state << std::endl;
try
{
for (const auto& element : aircraft_design_file_paths) {
boost::property_tree::ptree temp_tree{};
boost::property_tree::read_xml(element.string(),
temp_tree,
boost::property_tree::xml_parser::no_comments |
boost::property_tree::xml_parser::trim_whitespace);
aircraft_design_trees.push_back(temp_tree);
}
}
catch(const std::exception& e)
{
std::cerr << "Error occured at: " << __FILE__ << ", ";
std::cerr << "in function: " << __func__ << "(), ";
std::cerr << "in line: " << __LINE__ << std::endl;
std::cerr << "Error creating xml tree: " << e.what() << std::endl;
std::cerr << "Aborting Programm!" << std::endl;
return 1;
}
state = State::ExtractingConfigTreeInforamtion;
break;
}
case State::ExtractingConfigTreeInforamtion: {
std::cout << "Current State: " << state << std::endl;
subpaths_tree = getChildTreeFromParentTree(config_tree, "sub_path");
state = State::SubstractingNodeValues;
break;
}
case State::SubstractingNodeValues: {
std::cout << "Current State: " << state << std::endl;
try
{
for (const auto& tree : std::ranges::subrange(aircraft_design_trees.begin() + 1, aircraft_design_trees.end())) {
boost::property_tree::ptree temp_tree{};
for (const auto& node : subpaths_tree) {
// double upstream_value{std::nan("")};
double upstream_value{NAN};
double local_value{NAN};
std::string unit{"?"};
std::string node_path = node.second.get_value<std::string>();
if (containsSymbol(node_path, "@")) {
std::string pre{node_path.substr(0, node_path.find_first_of('@'))};
std::string temp_string{node_path.substr(node_path.find_first_of('@'))};
std::string attribute_value{temp_string.substr(temp_string.find_first_of('@')+1, temp_string.find_first_of('/')-1)};
std::string post{temp_string.substr(temp_string.find_first_of('/')+1)};
// TODO(Oli): try to fit this into own function, with multiple '@' seperations
boost::property_tree::ptree temp_upstream_tree{GetSubtreeByAttributevalue(aircraft_design_trees.at(0), pre, "ID", attribute_value)};
boost::property_tree::ptree temp_local_tree{GetSubtreeByAttributevalue(tree, pre, "ID", attribute_value)};
boost::property_tree::ptree temp_unit_tree{GetSubtreeByAttributevalue(tree, pre, "ID", attribute_value)};
upstream_value = temp_upstream_tree.get<double>(boost::property_tree::ptree::path_type(post, '/'));
local_value = temp_local_tree.get<double>(boost::property_tree::ptree::path_type(post, '/'));
unit = temp_unit_tree.get<std::string>(boost::property_tree::ptree::path_type(substractStringFromEnd(post, "value") + "unit", '/'));
} else {
upstream_value = aircraft_design_trees.at(0).get<double>(boost::property_tree::ptree::path_type(node_path, '/'));
local_value = tree.get<double>(boost::property_tree::ptree::path_type(node_path, '/'));
unit = tree.get<std::string>(boost::property_tree::ptree::path_type(substractStringFromEnd(node_path, "value") + "unit", '/'));
}
temp_tree.put(node.second.get<std::string>("<xmlattr>.Name"), local_value - upstream_value);
temp_tree.put(node.second.get<std::string>("<xmlattr>.Name") + ".<xmlattr>.unit", unit);
}
result_tree.push_back(temp_tree);
}
}
catch(const std::exception& e)
{
std::cerr << "Error occured at: " << __FILE__ << ", ";
std::cerr << "in function: " << __func__ << "(), ";
std::cerr << "in line: " << __LINE__ << std::endl;
std::cerr << "Error substracting node values: " << e.what() << std::endl;
std::cerr << "Aborting Programm!" << std::endl;
return 1;
}
state = State::WritingOutput;
break;
}
case State::WritingOutput: {
std::cout << "Current State: " << state << std::endl;
// Write Output
// Create header
boost::property_tree::ptree output_tree{};
output_tree.put("html.<xmlattr>.lang", "en");
output_tree.put("html.head.meta.<xmlattr>.content", "width=device-width, initial-scale=1.0");
output_tree.put("html.head.meta.<xmlattr>.name", "viewport");
output_tree.put("html.head.meta.<xmlattr>.charset", "utf-8");
output_tree.put("html.head.title", "<probably same as report name>");
output_tree.put("html.head.link.<xmlattr>.href", "style.css");
output_tree.put("html.head.link.<xmlattr>.rel", "stylesheet");
// Create body
boost::property_tree::ptree temp_tree{};
temp_tree.put("<xmlattr>.class", "content");
temp_tree.put("h1", "Design evaluation report");
temp_tree.put("div.<xmlattr>.class", "container");
// Create data tables
unsigned int aircraft_counter{0};
for (const auto& tree : result_tree) {
++aircraft_counter;
boost::property_tree::ptree data_tree{};
data_tree.put("<xmlattr>.class", "box data");
boost::property_tree::ptree my_tree{GetSubtreeByAttributevalue(program_settings_tree, "aircraft_design", "ID", std::to_string(aircraft_counter))};
std::string myString{my_tree.get<std::string>("name")};
data_tree.put("h2", myString);
data_tree.put("table.<xmlattr>.class", "content-table");
data_tree.put("table.caption", "Residual Values");
data_tree.put("table.thead", "");
data_tree.put("table.tbody", "");
boost::property_tree::ptree thead{};
thead.add_child("th", boost::property_tree::ptree{"paramter"});
// thead.add_child("th", boost::property_tree::ptree{"symbol"});
thead.add_child("th", boost::property_tree::ptree{"value"});
thead.add_child("th", boost::property_tree::ptree{"unit"});
data_tree.add_child("table.thead.tr", thead);
for (const auto& node : tree) {
boost::property_tree::ptree tbody{};
tbody.add_child("td", boost::property_tree::ptree{node.first});
tbody.add_child("td", boost::property_tree::ptree{node.second.data()});
tbody.add_child("td", boost::property_tree::ptree{node.second.get<std::string>("<xmlattr>.unit")});
data_tree.add_child("table.tbody.tr", tbody);
}
temp_tree.add_child("div.div", data_tree);
}
output_tree.add_child("html.body.div", temp_tree);
// Write .html file
boost::property_tree::xml_writer_settings<std::string> settings(' ', 4); // 4 spaces for indentation
boost::property_tree::write_xml("ReportXYZ.html",
output_tree,
std::locale(),
settings);
state = State::ProgrammFinished;
break;
}
case State::ProgrammFinished: {
std::cout << "Programm terminated successfully." << std::endl;
return 0;
break;
}
default: {
// TODO(Oli): check why when nodes have the same name only one is printed in the result_tree
// Questions:
// where are filepath of output.html and config.xml specified?
break;
}
}
}
}
/*
for (auto element : result_tree) {
std::cout << "TREE: " << std::endl;
printPtree(element);
std::cout << std::endl;
}
*/