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#include <fmt/ostream.h>
24#include <fmt/ranges.h>
25#endif
28#include "CSVFormatter.h"
29
30
31// ===========================================================================
32// member method definitions
33// ===========================================================================
34CSVFormatter::CSVFormatter(const std::string& columnNames, const char separator)
35 : OutputFormatter(OutputFormatterType::CSV), myHeaderFormat(columnNames), mySeparator(separator) {
36 if (myHeaderFormat == "none") {
37 myWroteHeader = true;
38 }
39}
40
41
42void
43CSVFormatter::openTag(std::ostream& /* into */, const std::string& xmlElement) {
44 myXMLStack.push_back((int)myValues.size());
45 if (!myWroteHeader) {
46 myCurrentTag = xmlElement;
47 }
48 if (myMaxDepth == (int)myXMLStack.size() && myWroteHeader && myCurrentTag != xmlElement) {
49 WRITE_WARNINGF("Encountered mismatch in XML tags (expected % but got %). Column names may be incorrect.", myCurrentTag, xmlElement);
50 }
51}
52
53
54void
55CSVFormatter::openTag(std::ostream& /* into */, const SumoXMLTag& xmlElement) {
56 myXMLStack.push_back((int)myValues.size());
57 if (!myWroteHeader) {
58 myCurrentTag = toString(xmlElement);
59 }
60 if (myMaxDepth == (int)myXMLStack.size() && myWroteHeader && myCurrentTag != toString(xmlElement)) {
61 WRITE_WARNINGF("Encountered mismatch in XML tags (expected % but got %). Column names may be incorrect.", myCurrentTag, toString(xmlElement));
62 }
63}
64
65
66bool
67CSVFormatter::closeTag(std::ostream& into, const std::string& /* comment */) {
68 if (myMaxDepth == 0) {
69 // the auto detection case: the first closed tag determines the depth
70 myMaxDepth = (int)myXMLStack.size();
71 }
72 if ((myMaxDepth == (int)myXMLStack.size() || myXMLStack.empty()) && !myWroteHeader) {
73 // First complete row or EOF: write the header
74 if (!myCheckColumns) {
75 WRITE_WARNING("Column based formats are still experimental. Autodetection only works for homogeneous output.");
76 }
77#ifdef HAVE_FMT
78 fmt::print(into, "{}\n", fmt::join(myHeader, std::string_view(&mySeparator, 1)));
79#else
80 into << joinToString(myHeader, mySeparator) << "\n";
81#endif
82 myWroteHeader = true;
83 }
84 if (myNeedsWrite) {
85#ifdef HAVE_FMT
86 const std::string row = fmt::format("{}", fmt::join(myValues, std::string_view(&mySeparator, 1)));
87#else
88 const std::string row = joinToString(myValues, mySeparator);
89#endif
90 myBufferedRows.emplace_back(row);
91 mySeenAttrs.reset();
92 myNeedsWrite = false;
93 }
94 if (myWroteHeader && !myBufferedRows.empty()) {
95 for (const std::string& row : myBufferedRows) {
96 into << row << '\n';
97 }
98 myBufferedRows.clear();
99 }
100 if (!myXMLStack.empty()) {
101 if ((int)myValues.size() > myXMLStack.back()) {
102 myValues.resize(myXMLStack.back());
103 }
104 myXMLStack.pop_back();
105 }
106 return false;
107}
108
109
110/****************************************************************************/
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
OutputFormatterType
SumoXMLTag
Numbers representing SUMO-XML - element names.
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:313
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:49
const std::string myHeaderFormat
the format to use for the column names
bool myNeedsWrite
whether any attribute has been written since the last row was emitted
std::string myCurrentTag
the currently read tag (only valid when generating the header)
SumoXMLAttrMask mySeenAttrs
which CSV columns have been set (just for checking completeness)
std::vector< int > myXMLStack
The number of attributes in the currently open XML elements.
std::vector< std::string > myHeader
the CSV header
int myMaxDepth
the maximum depth of the XML hierarchy (excluding the root element)
bool myCheckColumns
whether the columns should be checked for completeness
const char mySeparator
The value separator.
bool closeTag(std::ostream &into, const std::string &comment="")
Closes the most recently opened tag.
void openTag(std::ostream &into, const std::string &xmlElement)
Keeps track of an open XML tag by adding a new element to the stack.
CSVFormatter(const std::string &columnNames, const char separator=';')
Constructor.
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.