-
Zenker, Dr. Klaus (FWKE) - 126506 authoredZenker, Dr. Klaus (FWKE) - 126506 authored
XMLGeneratorVisitor.cc 5.17 KiB
#include "Application.h"
#include "VariableNetworkNode.h"
#include "XMLGeneratorVisitor.h"
#include <ChimeraTK/RegisterPath.h>
#include <libxml++/libxml++.h>
#include <cassert>
namespace ChimeraTK {
XMLGeneratorVisitor::XMLGeneratorVisitor()
: Visitor<ChimeraTK::Application, ChimeraTK::VariableNetworkNode>(), _doc(std::make_shared<xmlpp::Document>()),
_rootElement(_doc->create_root_node("application", "https://github.com/ChimeraTK/ApplicationCore")) {}
void XMLGeneratorVisitor::save(const std::string& fileName) { _doc->write_to_file_formatted(fileName); }
void XMLGeneratorVisitor::dispatch(const Application& app) {
_rootElement->set_attribute("name", app.getName());
for(auto& network : app.networkList) {
network.check();
auto feeder = network.getFeedingNode();
feeder.accept(*this);
for(auto& consumer : network.getConsumingNodes()) {
consumer.accept(*this);
}
}
}
void XMLGeneratorVisitor::dispatch(const VariableNetworkNode& node) {
if(node.getType() != NodeType::ControlSystem) return;
// Create the directory for the path name in the XML document with all parent
// directories, if not yet existing: First split the publication name into
// components and loop over each component. For each component, try to find
// the directory node and create it it does not exist. After the loop, the
// "current" will point to the Element representing the directory.
// strip the variable name from the path
ChimeraTK::RegisterPath directory(node.getPublicName());
directory--;
// the namespace map is needed to properly refer to elements with an xpath
// expression in xmlpp::Element::find()
/// @todo TODO move this somewhere else, or at least take the namespace URI
/// from a common place!
xmlpp::Node::PrefixNsMap nsMap{{"ac", "https://github.com/ChimeraTK/ApplicationCore"}};
// go through each directory path component
xmlpp::Element* current = _rootElement;
for(auto pathComponent : directory.getComponents()) {
// find directory for this path component in the current directory
std::string xpath = std::string("ac:directory[@name='") + pathComponent + std::string("']");
auto list = current->find(xpath, nsMap);
if(list.size() == 0) { // not found: create it
xmlpp::Element* newChild = current->add_child("directory");
newChild->set_attribute("name", pathComponent);
current = newChild;
}
else {
assert(list.size() == 1);
current = dynamic_cast<xmlpp::Element*>(list[0]);
assert(current != nullptr);
}
}
// now add the variable to the directory
xmlpp::Element* variable = current->add_child("variable");
ChimeraTK::RegisterPath pathName(node.getPublicName());
auto pathComponents = pathName.getComponents();
// set the name attribute
variable->set_attribute("name", pathComponents[pathComponents.size() - 1]);
// add sub-element containing the data type
std::string dataTypeName{"unknown"};
auto& owner = node.getOwner();
auto& type = owner.getValueType();
if(type == typeid(int8_t)) {
dataTypeName = "int8";
}
else if(type == typeid(uint8_t)) {
dataTypeName = "uint8";
}
else if(type == typeid(int16_t)) {
dataTypeName = "int16";
}
else if(type == typeid(uint16_t)) {
dataTypeName = "uint16";
}
else if(type == typeid(int32_t)) {
dataTypeName = "int32";
}
else if(type == typeid(uint32_t)) {
dataTypeName = "uint32";
}
else if(type == typeid(int64_t)) {
dataTypeName = "int64";
}
else if(type == typeid(uint64_t)) {
dataTypeName = "uint64";
}
else if(type == typeid(float)) {
dataTypeName = "float";
}
else if(type == typeid(double)) {
dataTypeName = "double";
}
else if(type == typeid(std::string)) {
dataTypeName = "string";
}
xmlpp::Element* valueTypeElement = variable->add_child("value_type");
valueTypeElement->set_child_text(dataTypeName);
// add sub-element containing the data flow direction
std::string dataFlowName{"application_to_control_system"};
if(owner.getFeedingNode() == node) {
dataFlowName = "control_system_to_application";
if(!owner.getFeedingNode().getDirection().withReturn) {
dataFlowName = "control_system_to_application";
}
else {
dataFlowName = "control_system_to_application_with_return";
}
}
xmlpp::Element* directionElement = variable->add_child("direction");
directionElement->set_child_text(dataFlowName);
// add sub-element containing the engineering unit
xmlpp::Element* unitElement = variable->add_child("unit");
unitElement->set_child_text(owner.getUnit());
// add sub-element containing the description
xmlpp::Element* descriptionElement = variable->add_child("description");
descriptionElement->set_child_text(owner.getDescription());
// add sub-element containing the description
xmlpp::Element* nElementsElement = variable->add_child("numberOfElements");
nElementsElement->set_child_text(std::to_string(owner.getFeedingNode().getNumberOfElements()));
}
} // namespace ChimeraTK