Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
CSVFormatter.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2012-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
18// An output formatter for CSV files
19/****************************************************************************/
20#include <config.h>
21
22#ifdef HAVE_FMT
23#ifdef _MSC_VER
24#pragma warning(push)
25#pragma warning(disable: 4868) // mask warning about left-to-right evaluation order
26#endif
27#include <fmt/ostream.h>
28#include <fmt/ranges.h>
29#ifdef _MSC_VER
30#pragma warning(pop)
31#endif
32#endif
35#include "CSVFormatter.h"
36
37
38// ===========================================================================
39// member method definitions
40// ===========================================================================
41CSVFormatter::CSVFormatter(const std::string& columnNames, const char separator)
42 : OutputFormatter(OutputFormatterType::CSV), myHeaderFormat(columnNames), mySeparator(separator) {
43 if (myHeaderFormat == "none") {
44 myWroteHeader = true;
45 }
46}
47
48
49bool
50CSVFormatter::writeXMLHeader(std::ostream& into, const std::string& rootElement,
51 const std::map<SumoXMLAttr, std::string>& attrs, bool /* writeMetadata */,
52 bool /* includeConfig */) {
53 if (attrs.size() > 2) {
54 myHaveRootAttrs = true;
55 openTag(into, rootElement);
56 for (const auto& a : attrs) {
57 if (a.first != SUMO_ATTR_XMLNS && a.first != SUMO_ATTR_SCHEMA_LOCATION) {
58 writeAttr(into, a.first, a.second, false, false);
59 }
60 }
61 return true;
62 }
63 return false;
64}
65
66
67void
68CSVFormatter::openTag(std::ostream& /* into */, const std::string& xmlElement) {
69 myXMLStack.push_back({xmlElement, (int)myValues.size()});
70}
71
72
73void
74CSVFormatter::openTag(std::ostream& /* into */, const SumoXMLTag& xmlElement) {
75 myXMLStack.push_back({toString(xmlElement), (int)myValues.size()});
76}
77
78
79bool
80CSVFormatter::closeTag(std::ostream& into, const std::string& /* comment */) {
81 if (myMaxDepth == 0) {
82 // the auto detection case: the first closed tag determines the depth
83 myMaxDepth = (int)myXMLStack.size();
84 }
85 const bool eof = myXMLStack.empty() || (myHaveRootAttrs && myXMLStack.size() == 1);
86 if ((myMaxDepth == (int)myXMLStack.size() || eof) && !myWroteHeader) {
87 // First complete row or EOF: write the header
88 if (!myCheckColumns) {
89 WRITE_WARNING("Column based formats are still experimental. Autodetection only works for homogeneous output.");
90 }
91 bool full = myHeaderFormat == "full";
92 if (myHeaderFormat == "auto") {
93 const std::set<std::string> uniq(myHeader.begin(), myHeader.end());
94 full = uniq.size() < myHeader.size();
95 }
96#ifdef HAVE_FMT
97 fmt::print(into, "{}\n", fmt::join(full ? myFullHeader : myHeader, std::string_view(&mySeparator, 1)));
98#else
99 into << joinToString(full ? myFullHeader : myHeader, mySeparator) << "\n";
100#endif
101 myWroteHeader = true;
102 }
103 if (myNeedsWrite) {
104 myValues.resize(myHeader.size());
105#ifdef HAVE_FMT
106 const std::string row = fmt::format("{}", fmt::join(myValues, std::string_view(&mySeparator, 1)));
107#else
108 const std::string row = joinToString(myValues, mySeparator);
109#endif
110 myBufferedRows.emplace_back(row);
111 mySeenAttrs.reset();
112 myNeedsWrite = false;
113 }
114 if (myWroteHeader && !myBufferedRows.empty()) {
115 for (const std::string& row : myBufferedRows) {
116 into << row << '\n';
117 }
118 myBufferedRows.clear();
119 }
120 if (!eof) {
121 if ((int)myValues.size() > myXMLStack.back().second) {
122 myValues.resize(myXMLStack.back().second);
123 }
124 myXMLStack.pop_back();
125 return true;
126 }
127 return false;
128}
129
130
131/****************************************************************************/
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
OutputFormatterType
SumoXMLTag
Numbers representing SUMO-XML - element names.
@ SUMO_ATTR_XMLNS
@ SUMO_ATTR_SCHEMA_LOCATION
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:322
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:57
const std::string myHeaderFormat
the format to use for the column names
bool myHaveRootAttrs
whether any root attribute have been encountered
void openTag(std::ostream &into, const std::string &xmlElement) override
Keeps track of an open XML tag by adding a new element to the stack.
bool myNeedsWrite
whether any attribute has been written since the last row was emitted
void writeAttr(std::ostream &into, const SumoXMLAttr attr, const T &val, const bool isNull, const bool escape)
Writes a named attribute.
bool closeTag(std::ostream &into, const std::string &comment="") override
Closes the most recently opened tag.
SumoXMLAttrMask mySeenAttrs
which CSV columns have been set (just for checking completeness)
std::vector< std::string > myHeader
the CSV header
int myMaxDepth
the maximum depth of the XML hierarchy (excluding the root element)
bool writeXMLHeader(std::ostream &into, const std::string &rootElement, const std::map< SumoXMLAttr, std::string > &attrs, bool, bool) override
Writes an "XML header".
bool myCheckColumns
whether the columns should be checked for completeness
const char mySeparator
The value separator.
std::vector< std::pair< const std::string, int > > myXMLStack
The name and number of attributes in the currently open XML elements.
CSVFormatter(const std::string &columnNames, const char separator=';')
Constructor.
std::vector< std::string > myFullHeader
the CSV header if we write the full name
bool myWroteHeader
whether the CSV header line has been written
std::vector< std::string > myValues
the current attribute / column values
std::vector< std::string > myBufferedRows
partial rows buffered before the schema is known (depth < myMaxDepth)
Abstract base class for output formatters.