Forked from
Eclipse Projects / Eclipse openpass / opSimulation
1725 commits behind, 4 commits ahead of the upstream repository.
-
Reinhard Biegel authoredReinhard Biegel authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
xmlParser.h 6.19 KiB
/*******************************************************************************
* Copyright (c) 2017, 2018, 2019, 2020 in-tech GmbH
* 2016, 2017, 2018 ITK Engineering GmbH
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
//-----------------------------------------------------------------------------
//! @file XmlParser.h
//! @brief This file contains helper functions to parse the configuration.
//-----------------------------------------------------------------------------
#pragma once
#include <string>
#include <unordered_map>
#include <QDomDocument>
#include <QFile>
#include "common/log.h"
namespace SimulationCommon {
extern bool GetFirstChildElement(QDomElement rootElement, const std::string &tag, QDomElement &result);
extern bool GetFirstChild(QDomElement rootElement, QDomElement &result);
extern bool GetLastChildElement(QDomElement rootElement, const std::string &tag, QDomElement &result);
extern bool ParseCurrentInt(QDomElement currentElement, int &result);
/// Tempalted wrapper for Parse* functions
template <typename T>
bool Parse(QDomElement rootElement, const std::string &tag, T &result);
extern bool ParseString(QDomElement rootElement, const std::string &tag, std::string &result);
extern bool ParseDouble(QDomElement rootElement, const std::string &tag, double &result);
extern bool ParseDoubleVector(QDomElement rootElement, const std::string &tag, std::vector<double> &result);
extern bool ParseInt(QDomElement rootElement, const std::string &tag, int &result);
extern bool ParseULong(QDomElement rootElement, const std::string &tag, unsigned long &result);
extern bool ParseBool(QDomElement rootElement, const std::string &tag, bool &result);
extern bool ParseAttributeString(QDomElement element, const std::string &attributeName, std::string &result, std::optional<std::string> defaultValue = std::nullopt);
extern bool ParseAttributeDouble(QDomElement element, const std::string &attributeName, double &result, std::optional<double> defaultValue = std::nullopt);
extern bool ParseAttributeInt(QDomElement element, const std::string &attributeName, int &result);
extern bool ParseAttributeBool(QDomElement element, const std::string &attributeName, bool &result);
extern bool ParseAttributeStringVector(QDomElement element, const std::string &attributeName, std::vector<std::string> *result);
extern bool ParseAttributeDoubleVector(QDomElement element, const std::string &attributeName, std::vector<double> *result);
extern bool ParseAttributeIntVector(QDomElement element, const std::string &attributeName, std::vector<int> *result);
extern bool ParseAttributeBoolVector(QDomElement element, const std::string &attributeName, std::vector<bool> *result);
/*!
* \brief Parses the value of an XML attribute into the provided container.
*
* Depending on the datatype of the result parameter, different parsing techniques are applied.
*
* \param[in] element XML element holding the attribute
* \param[in] attributeName Name of the attribute to parse the value from
* \param[out] result Container holding the result
*
* \return True on successful parsing, false otherwise.
*/
template <typename T>
bool ParseAttribute(QDomElement element, const std::string &attributeName, T &result);
//! Returns true if the given element has an attribute of the given name
bool HasAttribute(QDomElement element, const std::string &attributeName);
/*!
* \brief Imports a probability map
*
* \details This method imports a probability map for some value of type T. T can either be int, double or string
*
*
* @param[in] parentElement Element containing the information
* @param[in] key Name how the value is specified in the xml file
* @param[in] tag Name of the tags that should be imported
* @param[out] probabilities Map where the probabilities get saved
* @param[in] mustAddUpToOne flag which specifies wether the sum of all probalities must be 1
* @return true, if successful
*/
template <typename T>
bool ImportProbabilityMap(QDomElement parentElement,
const std::string key,
const QString tag,
std::vector<std::pair<T, double>> &probabilities,
bool mustAddUpToOne = true)
{
double probabilitySum = 0.0;
QDomElement childElement;
if (!GetFirstChildElement(parentElement, tag.toStdString(), childElement))
{
LOG_INTERN(LogLevel::Error) << "At least one element is required.";
return false;
}
while (!childElement.isNull())
{
T keyValue;
double probability;
if (!ParseAttribute<T>(childElement, key, keyValue))
{
LOG_INTERN(LogLevel::Error) << "Key is invalid.";
return false;
}
if (!ParseAttributeDouble(childElement, "Probability", probability))
{
LOG_INTERN(LogLevel::Error) << "Probability is invalid.";
return false;
}
probabilities.push_back({keyValue, probability});
probabilitySum += probability;
childElement = childElement.nextSiblingElement(tag);
}
//Checks probabilities
if (mustAddUpToOne && std::abs(probabilitySum - 1.0) > 1e-6)
{
LOG_INTERN(LogLevel::Error) << "Probabilities do not add up to 1.0.";
return false;
}
if (probabilitySum > 1.0 + 1e-6)
{
LOG_INTERN(LogLevel::Error) << "Probabilities add up to more than 1.0.";
return false;
}
return true;
}
} // namespace SimulationCommon
[[maybe_unused]] static void ThrowIfFalse(bool success, const QDomElement element, const std::string &message)
{
if (!success)
{
LogErrorAndThrow("Could not import element " + element.tagName().toStdString() +
" (line " + std::to_string(element.lineNumber()) +
", column " + std::to_string(element.columnNumber()) + "): " +
message);
}
}