preCICE v3.1.1
Loading...
Searching...
No Matches
Printer.cpp
Go to the documentation of this file.
1#include "xml/Printer.hpp"
2#include <Eigen/Core>
3#include <algorithm>
4#include <cctype>
5#include <map>
6#include <memory>
7#include <regex>
8#include <set>
9#include <sstream>
10#include <string>
11#include <utility>
12#include <vector>
13#include "utils/String.hpp"
14#include "utils/TypeNames.hpp"
15#include "xml/XMLAttribute.hpp"
16#include "xml/XMLTag.hpp"
17
18namespace precice::xml {
19
20namespace {
21
23
25std::string toGHLink(const std::string &heading)
26{
27 try {
28 std::regex sanitizer{"[^a-zA-Z0-9-]"};
29 std::regex spaces{"\\s"};
30
31 // sanitize the heading
32 std::string sanitized = std::regex_replace(std::regex_replace(heading, sanitizer, ""), spaces, "-");
33
34 // convert to lowercase
35 std::transform(sanitized.begin(), sanitized.end(), sanitized.begin(),
36 [](unsigned char c) { return std::tolower(c); });
37 return "#" + sanitized;
38
39 } catch (const std::regex_error &e) {
40 std::cerr << "Error sanitizing link: " << e.what() << '\n';
41 std::exit(-1);
42 }
43}
44
46
48template <typename ATTRIBUTE_T>
49std::ostream &printDTD(std::ostream &out, const XMLAttribute<ATTRIBUTE_T> &attr, const std::string &ElementName)
50{
51 out << "<!ATTLIST " << ElementName << " " << attr.getName() << " CDATA ";
52
53 if (attr.hasDefaultValue()) {
54 out << "\"" << attr.getDefaultValue() << "\"";
55 } else {
56 out << "#REQUIRED";
57 }
58
59 out << ">\n";
60 return out;
61}
62
64template <typename ATTRIBUTE_T>
65std::ostream &printMD(std::ostream &out, const XMLAttribute<ATTRIBUTE_T> &attr)
66{
67 out << "| " << attr.getName() << " | " << utils::getTypeName(attr.getDefaultValue()) << " | " << attr.getUserDocumentation() << " | ";
68 if (attr.hasDefaultValue()) {
69 out << '`' << attr.getDefaultValue() << '`';
70 } else {
71 out << "_none_";
72 }
73 out << " | ";
74
75 const auto &options = attr.getOptions();
76 if (options.empty()) {
77 out << "none";
78 } else {
79 out << '`' << options.front() << '`';
80 for (auto iter = ++options.cbegin(); iter != options.cend(); ++iter) {
81 out << ", " << '`' << *iter << '`';
82 }
83 }
84
85 out << " |";
86 return out;
87}
88
90template <typename ATTRIBUTE_T>
91std::ostream &printExample(std::ostream &out, const XMLAttribute<ATTRIBUTE_T> &attr)
92{
93 out << attr.getName() << "=\"";
94 if (attr.hasDefaultValue()) {
95 out << attr.getDefaultValue();
96 } else {
97 out << '{' << utils::getTypeName(attr.getDefaultValue()) << '}';
98 }
99 out << '"';
100 return out;
101}
102
104template <typename ATTRIBUTE_T>
105std::ostream &printDocumentation(std::ostream &out, const XMLAttribute<ATTRIBUTE_T> &attr)
106{
107 out << attr.getName() << "=\"{" << utils::getTypeName(attr.getDefaultValue());
108 if (attr.hasValidation()) {
109 out << ":";
110 // print the first item
111 auto first = attr.getOptions().begin();
112 out << '\'' << *first << '\'';
113 ++first;
114 // print the remaining items with separator
115 for (; first != attr.getOptions().end(); ++first) {
116 out << " or '" << *first << '\'';
117 }
118 }
119 out << "}";
120 if (attr.hasDefaultValue()) {
121 out << "(default:'" << attr.getDefaultValue() << "')";
122 }
123 out << "\"";
124 return out;
125}
126
128
132std::ostream &printDTD(std::ostream &out, const XMLTag &tag, bool start = false)
133{
134 if (start)
135 out << "<!DOCTYPE " << tag.getFullName() << " [\n";
136
137 out << "<!ELEMENT " << tag.getFullName() << " ";
138
139 if (not tag.getSubtags().empty()) {
140
141 out << "(";
142
143 bool first = true;
144 for (auto const &subtag : tag.getSubtags()) {
145
146 std::string occurrenceChar;
147
148 XMLTag::Occurrence occ = subtag->getOccurrence();
149
150 if (occ == XMLTag::OCCUR_ARBITRARY)
151 occurrenceChar = "*";
152 else if (occ == XMLTag::OCCUR_NOT_OR_ONCE)
153 occurrenceChar = "?";
154 else if (occ == XMLTag::OCCUR_ONCE_OR_MORE)
155 occurrenceChar = "+";
156
157 out << (first ? "" : ", ") << subtag->getFullName() << occurrenceChar;
158 first = false;
159 }
160
161 out << ")>\n";
162 } else {
163 out << "EMPTY>\n";
164 }
165
166 for (const auto &pair : tag.getDoubleAttributes()) {
167 printDTD(out, pair.second, tag.getFullName());
168 }
169
170 for (const auto &pair : tag.getIntAttributes()) {
171 printDTD(out, pair.second, tag.getFullName());
172 }
173
174 for (const auto &pair : tag.getStringAttributes()) {
175 printDTD(out, pair.second, tag.getFullName());
176 }
177
178 for (const auto &pair : tag.getBooleanAttributes()) {
179 printDTD(out, pair.second, tag.getFullName());
180 }
181
182 for (const auto &pair : tag.getEigenVectorXdAttributes()) {
183 printDTD(out, pair.second, tag.getFullName());
184 }
185
186 if (not tag.getSubtags().empty()) {
187 for (const auto &subtag : tag.getSubtags()) {
188 printDTD(out, *subtag);
189 }
190 }
191
192 out << '\n';
193
194 if (start)
195 out << "]>\n";
196 return out;
197}
198
204std::ostream &printExample(std::ostream &out, const XMLTag &tag, int level)
205{
206 std::string prefix(level * 2, ' ');
207 out << prefix << '<' << tag.getFullName();
208 for (const auto &pair : tag.getDoubleAttributes()) {
209 out << ' ';
210 printExample(out, pair.second);
211 }
212 for (const auto &pair : tag.getIntAttributes()) {
213 out << ' ';
214 printExample(out, pair.second);
215 }
216 for (const auto &pair : tag.getStringAttributes()) {
217 out << ' ';
218 printExample(out, pair.second);
219 }
220 for (const auto &pair : tag.getBooleanAttributes()) {
221 out << ' ';
222 printExample(out, pair.second);
223 }
224 for (const auto &pair : tag.getEigenVectorXdAttributes()) {
225 out << ' ';
226 printExample(out, pair.second);
227 }
228 if (tag.getSubtags().empty()) {
229 out << "/>";
230 return out;
231 }
232 out << ">\n";
233
234 constexpr int threshold{1};
235 if (level >= threshold) {
236 out << std::string((level + 1) * 2, ' ') << "...\n";
237 } else {
238 std::set<std::string> namespaces;
239 for (const auto &subtag : tag.getSubtags()) {
240 const auto ns = subtag->getNamespace();
241 if (!ns.empty()) {
242 if (namespaces.count(subtag->getNamespace()) > 0) {
243 continue;
244 }
245 namespaces.emplace(ns);
246 }
247 printExample(out, *subtag, level + 1) << '\n';
248 }
249 }
250
251 out << prefix << "</" << tag.getFullName() << '>';
252 return out;
253}
254
261std::ostream &printMD(std::ostream &out, const XMLTag &tag, int level, std::map<std::string, int> &occurrences)
262{
263 out << std::string(level, '#') << ' ' << tag.getFullName() << "\n\n";
264
265 out << tag.getDocumentation() << "\n\n";
266
267 out << "**Example:** \n```xml\n";
268 printExample(out, tag, 0) << "\n```\n\n";
269
270 if (!(tag.getDoubleAttributes().empty() &&
271 tag.getIntAttributes().empty() &&
272 tag.getStringAttributes().empty() &&
273 tag.getBooleanAttributes().empty() &&
274 tag.getEigenVectorXdAttributes().empty())) {
275 out << "| Attribute | Type | Description | Default | Options |\n";
276 out << "| --- | --- | --- | --- | --- |\n";
277 for (const auto &pair : tag.getDoubleAttributes()) {
278 printMD(out, pair.second) << '\n';
279 }
280
281 for (const auto &pair : tag.getIntAttributes()) {
282 printMD(out, pair.second) << '\n';
283 }
284
285 for (const auto &pair : tag.getStringAttributes()) {
286 printMD(out, pair.second) << '\n';
287 }
288
289 for (const auto &pair : tag.getBooleanAttributes()) {
290 printMD(out, pair.second) << '\n';
291 }
292
293 for (const auto &pair : tag.getEigenVectorXdAttributes()) {
294 printMD(out, pair.second) << '\n';
295 }
296 out << "\n";
297 }
298
299 if (not tag.getSubtags().empty()) {
300 out << "**Valid Subtags:**\n\n";
301
303
304 for (const auto &subtag : tag.getSubtags()) {
305 const auto heading = subtag->getFullName();
306 auto link = toGHLink(heading);
307 auto iter = occurrences.find(heading);
308 if (iter != occurrences.end()) {
309 link.append("-").append(std::to_string(iter->second));
310 iter->second *= 1;
311 } else {
312 occurrences.emplace(heading, 1);
313 }
314
315 const auto ns = subtag->getNamespace();
316 if (ns.empty()) {
317 out << "* [" << heading << "](" << link << ") `" << subtag->getOccurrenceString(subtag->getOccurrence()) << "`\n";
318 } else {
319 auto &tags = groupedTags[ns];
320 tags.emplace_back("[" + subtag->getName() + "](" + link + ") `" + subtag->getOccurrenceString(subtag->getOccurrence()) + "`");
321 }
322 }
323 for (const auto &kv : groupedTags) {
324 out << "* " << kv.first << "\n";
325 for (const auto &link : kv.second) {
326 out << " * " << link << "\n";
327 }
328 }
329
330 out << "\n\n";
331
332 for (const auto &subtag : tag.getSubtags()) {
333 printMD(out, *subtag, level + 1, occurrences) << '\n';
334 }
335 }
336
337 out << '\n';
338 return out;
339}
340
344std::ostream &printMD(std::ostream &out, const XMLTag &tag, int level = 1)
345{
346 std::map<std::string, int> occurrences;
347 printMD(out, tag, level, occurrences);
348 return out;
349}
350
352std::ostream &printDocumentation(std::ostream &out, const XMLTag &tag, int indentation)
353{
354 const int linewidth = 1000;
355 std::string indent;
356 for (int i = 0; i < indentation; i++) {
357 indent += " ";
358 }
359
360 out << indent << "<!-- TAG " << tag.getFullName() << '\n';
361 if (not tag.getDocumentation().empty()) {
362 std::string indentedDoc = indent + " " + tag.getDocumentation();
363 out << utils::wrapText(indentedDoc, linewidth, indentation + 9);
364 out << '\n';
365 }
366 out << indent << " (can occur " << XMLTag::getOccurrenceString(tag.getOccurrence()) << " times)";
367
368 for (const auto &pair : tag.getDoubleAttributes()) {
369 out << '\n';
370 std::ostringstream attrDoc;
371 attrDoc << indent << " ATTR " << pair.first << ": "
372 << pair.second.getUserDocumentation();
373 out << utils::wrapText(attrDoc.str(), linewidth, indentation + 10);
374 }
375
376 for (const auto &pair : tag.getIntAttributes()) {
377 out << '\n';
378 std::ostringstream attrDoc;
379 attrDoc << indent << " ATTR " << pair.first << ": "
380 << pair.second.getUserDocumentation();
381 out << utils::wrapText(attrDoc.str(), linewidth, indentation + 10);
382 }
383
384 for (const auto &pair : tag.getStringAttributes()) {
385 out << '\n';
386 std::ostringstream attrDoc;
387 attrDoc << indent << " ATTR " << pair.first << ": "
388 << pair.second.getUserDocumentation();
389 out << utils::wrapText(attrDoc.str(), linewidth, indentation + 10);
390 }
391
392 for (const auto &pair : tag.getBooleanAttributes()) {
393 out << '\n';
394 std::ostringstream attrDoc;
395 attrDoc << indent << " ATTR " << pair.first << ": "
396 << pair.second.getUserDocumentation();
397 out << utils::wrapText(attrDoc.str(), linewidth, indentation + 10);
398 }
399
400 for (const auto &pair : tag.getEigenVectorXdAttributes()) {
401 out << '\n';
402 std::ostringstream attrDoc;
403 attrDoc << indent << " ATTR " << pair.first << ": "
404 << pair.second.getUserDocumentation();
405 out << utils::wrapText(attrDoc.str(), linewidth, indentation + 10);
406 }
407
408 out << " -->\n";
409 std::ostringstream tagHead;
410 tagHead << indent << "<" << tag.getFullName();
411
412 // Print XML namespaces, necessary for correct XML format and display in browser
413 for (const std::string &namespaceName : tag.getNamespaces()) {
414 tagHead << " xmlns:" << namespaceName << "=\"precice." << namespaceName << "\"";
415 }
416
417 for (const auto &pair : tag.getDoubleAttributes()) {
418 tagHead << indent << " ";
419 printDocumentation(tagHead, pair.second);
420 }
421
422 for (const auto &pair : tag.getIntAttributes()) {
423 tagHead << indent << " ";
424 printDocumentation(tagHead, pair.second);
425 }
426
427 for (const auto &pair : tag.getStringAttributes()) {
428 tagHead << indent << " ";
429 printDocumentation(tagHead, pair.second);
430 }
431
432 for (const auto &pair : tag.getBooleanAttributes()) {
433 tagHead << indent << " ";
434 printDocumentation(tagHead, pair.second);
435 }
436
437 for (const auto &pair : tag.getEigenVectorXdAttributes()) {
438 tagHead << indent << " ";
439 printDocumentation(tagHead, pair.second);
440 }
441
442 out << utils::wrapText(tagHead.str(), linewidth, indentation + 3);
443
444 if (not tag.getSubtags().empty()) {
445 out << ">\n\n";
446 for (const auto &subtag : tag.getSubtags()) {
447 printDocumentation(out, *subtag, indentation + 3);
448 }
449 out << indent << "</" << tag.getFullName() << ">\n\n";
450 } else {
451 out << "/>\n\n";
452 }
453 return out;
454}
455
456} // namespace
457
459{
460 printMD(out, tag);
461}
462
463void toDTD(std::ostream &out, const XMLTag &tag)
464{
465 printDTD(out, tag);
466}
467
469{
470 printDocumentation(out, tag, 0);
471}
472
473} // namespace precice::xml
std::string prefix
std::ostream & out
T begin(T... args)
Represents an XML tag to be configured automatically.
Definition XMLTag.hpp:31
static std::string getOccurrenceString(Occurrence occurrence)
Definition XMLTag.cpp:411
Occurrence
Types of occurrences of an XML tag.
Definition XMLTag.hpp:67
T count(T... args)
T emplace(T... args)
T end(T... args)
T exit(T... args)
T find(T... args)
std::string wrapText(const std::string &text, int linewidth, int indentation)
Definition String.cpp:12
std::string getTypeName(const double &var)
Definition TypeNames.hpp:15
contains the XML configuration parser.
void toMarkdown(std::ostream &out, const XMLTag &tag)
Prints the Markdown reference for the given tag.
Definition Printer.cpp:458
void toDTD(std::ostream &out, const XMLTag &tag)
Prints the DTD reference for the given tag.
Definition Printer.cpp:463
void toDocumentation(std::ostream &out, const XMLTag &tag)
Prints the XML reference for the given tag.
Definition Printer.cpp:468
T regex_replace(T... args)
T str(T... args)
T to_string(T... args)
T transform(T... args)
T what(T... args)