Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2012-2025 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 : /****************************************************************************/
14 : /// @file CSVFormatter.cpp
15 : /// @author Michael Behrisch
16 : /// @date 2025-06-12
17 : ///
18 : // An output formatter for CSV files
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <utils/common/MsgHandler.h>
23 : #include <utils/common/ToString.h>
24 : #include "CSVFormatter.h"
25 :
26 :
27 : // ===========================================================================
28 : // member method definitions
29 : // ===========================================================================
30 6 : CSVFormatter::CSVFormatter(const std::string& columnNames, const char separator)
31 6 : : OutputFormatter(OutputFormatterType::CSV), myHeaderFormat(columnNames), mySeparator(separator) {
32 6 : if (myHeaderFormat == "none") {
33 0 : myWroteHeader = true;
34 : }
35 6 : }
36 :
37 :
38 : void
39 720 : CSVFormatter::openTag(std::ostream& /* into */, const std::string& xmlElement) {
40 720 : myCurrentDepth++;
41 720 : if (myCurrentDepth > (int)myXMLStack.size()) {
42 12 : myXMLStack.emplace_back(std::unique_ptr<std::ostringstream>(new std::ostringstream()));
43 : }
44 720 : if (!myWroteHeader) {
45 606 : myCurrentTag = xmlElement;
46 : }
47 720 : if (myMaxDepth == myCurrentDepth && myWroteHeader && myCurrentTag != xmlElement) {
48 0 : WRITE_WARNINGF("Encountered mismatch in XML tags (expected % but got %). Column names may be incorrect.", myCurrentTag, xmlElement);
49 : }
50 720 : }
51 :
52 :
53 : void
54 696 : CSVFormatter::openTag(std::ostream& /* into */, const SumoXMLTag& xmlElement) {
55 696 : myCurrentDepth++;
56 696 : if (myCurrentDepth > (int)myXMLStack.size()) {
57 12 : myXMLStack.emplace_back(std::unique_ptr<std::ostringstream>(new std::ostringstream()));
58 : }
59 696 : if (!myWroteHeader) {
60 12 : myCurrentTag = toString(xmlElement);
61 : }
62 1386 : if (myMaxDepth == myCurrentDepth && myWroteHeader && myCurrentTag != toString(xmlElement)) {
63 0 : WRITE_WARNINGF("Encountered mismatch in XML tags (expected % but got %). Column names may be incorrect.", myCurrentTag, toString(xmlElement));
64 : }
65 696 : }
66 :
67 :
68 : bool
69 1422 : CSVFormatter::closeTag(std::ostream& into, const std::string& /* comment */) {
70 1422 : if (myMaxDepth == 0) {
71 0 : myMaxDepth = myCurrentDepth;
72 : }
73 1422 : if (myMaxDepth == myCurrentDepth && !myWroteHeader) {
74 6 : if (!myCheckColumns) {
75 0 : WRITE_WARNING("Column based formats are still experimental. Autodetection only works for homogeneous output.");
76 : }
77 12 : into << joinToString(myHeader, mySeparator) << "\n";
78 6 : myWroteHeader = true;
79 : }
80 1422 : if (myCurrentDepth == myMaxDepth) {
81 1392 : if (myCheckColumns && myExpectedAttrs != mySeenAttrs) {
82 0 : WRITE_ERRORF("Incomplete attribute set '%', this file format does not support CSV output yet.", toString(mySeenAttrs));
83 : }
84 1392 : for (auto it = myXMLStack.begin(); it != myXMLStack.end() - 1; ++it) {
85 696 : into << (*it)->str();
86 : }
87 : // remove the final separator
88 696 : std::string final = myXMLStack[myCurrentDepth - 1]->str();
89 696 : final[final.size() - 1] = '\n';
90 : into << final;
91 : mySeenAttrs.reset();
92 : }
93 1422 : if (myCurrentDepth > 0) {
94 1416 : if (!myWroteHeader) {
95 600 : const std::string text = myXMLStack[myCurrentDepth - 1]->str();
96 600 : const int count = (int)std::count(text.begin(), text.end(), mySeparator);
97 600 : myHeader.resize(myHeader.size() - count);
98 : }
99 1416 : myXMLStack[myCurrentDepth - 1]->str("");
100 1416 : myXMLStack[myCurrentDepth - 1]->clear();
101 1416 : myCurrentDepth--;
102 : }
103 1422 : return false;
104 : }
105 :
106 :
107 : /****************************************************************************/
|