/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2012-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file PlainXMLFormatter.h14/// @author Daniel Krajzewicz15/// @author Michael Behrisch16/// @date 201217///18// Output formatter for plain XML output19/****************************************************************************/20#pragma once21#include <config.h>2223#ifdef HAVE_FMT24#include <fmt/ostream.h>25#endif2627#include "OutputFormatter.h"282930// ===========================================================================31// class definitions32// ===========================================================================33/**34* @class PlainXMLFormatter35* @brief Output formatter for plain XML output36*37* PlainXMLFormatter format XML like output into the output stream.38*/39class PlainXMLFormatter : public OutputFormatter {40public:41/// @brief Constructor42PlainXMLFormatter(const int defaultIndentation = 0);4344/// @brief Destructor45virtual ~PlainXMLFormatter() { }4647/** @brief Writes an XML header with optional configuration48*49* If something has been written (myXMLStack is not empty), nothing50* is written and false returned.51*52* @param[in] into The output stream to use53* @param[in] rootElement The root element to use54* @param[in] attrs Additional attributes to save within the rootElement55* @param[in] includeConfig whether the current config should be included as XML comment56* @return whether something has been written57* @todo Describe what is saved58*/59bool writeXMLHeader(std::ostream& into, const std::string& rootElement,60const std::map<SumoXMLAttr, std::string>& attrs, bool writeMetadata,61bool includeConfig);6263/** @brief Opens an XML tag64*65* An indentation, depending on the current xml-element-stack size, is written followed66* by the given xml element ("<" + xmlElement)67* The xml element is added to the stack, then.68*69* @param[in] into The output stream to use70* @param[in] xmlElement Name of element to open71* @return The OutputDevice for further processing72*/73void openTag(std::ostream& into, const std::string& xmlElement);7475/** @brief Opens an XML tag76*77* Helper method which finds the correct string before calling openTag.78*79* @param[in] into The output stream to use80* @param[in] xmlElement Id of the element to open81*/82void openTag(std::ostream& into, const SumoXMLTag& xmlElement);8384/** @brief Closes the most recently opened tag85*86* @param[in] into The output stream to use87* @return Whether a further element existed in the stack and could be closed88* @todo it is not verified that the topmost element was closed89*/90bool closeTag(std::ostream& into, const std::string& comment = "");9192/** @brief writes a preformatted tag to the device but ensures that any93* pending tags are closed94* @param[in] into The output stream to use95* @param[in] val The preformatted data96*/97void writePreformattedTag(std::ostream& into, const std::string& val);9899/** @brief writes arbitrary padding100*/101void writePadding(std::ostream& into, const std::string& val);102103/** @brief writes an arbitrary attribute104*105* @param[in] into The output stream to use106* @param[in] attr The attribute (name)107* @param[in] val The attribute value108*/109template <class T>110static void writeAttr(std::ostream& into, const std::string& attr, const T& val) {111into << " " << attr << "=\"" << toString(val, into.precision()) << "\"";112}113114/** @brief writes a named attribute115*116* @param[in] into The output stream to use117* @param[in] attr The attribute (name)118* @param[in] val The attribute value119*/120template <class T>121static void writeAttr(std::ostream& into, const SumoXMLAttr attr, const T& val) {122into << " " << toString(attr) << "=\"" << toString(val, into.precision()) << "\"";123}124125void writeTime(std::ostream& into, const SumoXMLAttr attr, const SUMOTime val) {126into << " " << toString(attr) << "=\"" << time2string(val) << "\"";127}128129bool wroteHeader() const {130return !myXMLStack.empty();131}132133private:134/// @brief The stack of begun xml elements135std::vector<std::string> myXMLStack;136137/// @brief The initial indentation level138int myDefaultIndentation;139140/// @brief whether a closing ">" might be missing141bool myHavePendingOpener;142};143144145// ===========================================================================146// specialized template implementations (for speedup)147// ===========================================================================148template <>149inline void PlainXMLFormatter::writeAttr(std::ostream& into, const SumoXMLAttr attr, const double& val) {150#ifdef HAVE_FMT151fmt::print(into, " {}=\"{:.{}f}\"", toString(attr), val, into.precision());152#else153into << " " << toString(attr) << "=\"" << toString(val, into.precision()) << "\"";154#endif155}156157158template <>159inline void PlainXMLFormatter::writeAttr(std::ostream& into, const SumoXMLAttr attr, const std::string& val) {160into << " " << toString(attr) << "=\"" << val << "\"";161}162163164