BDE 4.39.x Production Release
Loading...
Searching...
No Matches
balxml_formatter_prettyimpl.h
Go to the documentation of this file.
1/// @file balxml_formatter_prettyimpl.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balxml_formatter_prettyimpl.h -*-C++-*-
8#ifndef INCLUDED_BALXML_FORMATTER_PRETTYIMPL
9#define INCLUDED_BALXML_FORMATTER_PRETTYIMPL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balxml_formatter_prettyimpl balxml_formatter_prettyimpl
15/// @brief Provide pretty-printing implementation for `balxml_formatter`.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balxml
19/// @{
20/// @addtogroup balxml_formatter_prettyimpl
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balxml_formatter_prettyimpl-purpose"> Purpose</a>
25/// * <a href="#balxml_formatter_prettyimpl-classes"> Classes </a>
26/// * <a href="#balxml_formatter_prettyimpl-description"> Description </a>
27///
28/// # Purpose {#balxml_formatter_prettyimpl-purpose}
29/// Provide pretty-printing implementation for @ref balxml_formatter .
30///
31/// # Classes {#balxml_formatter_prettyimpl-classes}
32///
33/// - balxml::Formatter_PrettyImplState: state of formatter state machine
34/// - balxml::Formatter_PrettyImplStateId: labels for formatter state
35/// - balxml::Formatter_PrettyImplUtil: actions of formatter state machine
36///
37/// # Description {#balxml_formatter_prettyimpl-description}
38/// This private, subordinate component to @ref balxml_formatter
39/// provides an in-core value semantic attribute class,
40/// `balxml::Formatter_PrettyImplState`, and a utility `struct`,
41/// `balxml::Formatter_PrettyImplUtil`, that implements XML pretty-printing
42/// operations using the state value type. These two classes work in
43/// conjunction to implement a state machine for pretty-printing an XML document
44/// given a sequence of tokens to emit. The class
45/// `balxml::Formatter_PrettyImplStateId` enumerates the set of labels for
46/// distinct states of `balxml::Formatter_PrettyImplState`, upon which most
47/// control-flow decisions of `balxml::Formatter_PrettyImplUtil` are based.
48/// @}
49/** @} */
50/** @} */
51
52/** @addtogroup bal
53 * @{
54 */
55/** @addtogroup balxml
56 * @{
57 */
58/** @addtogroup balxml_formatter_prettyimpl
59 * @{
60 */
61
62#include <balscm_version.h>
63
67
69
71
72#include <bslma_bslallocator.h>
74
76
77#include <bsl_ios.h>
78#include <bsl_ostream.h>
79#include <bsl_string_view.h>
80#include <bsl_vector.h>
81
82
83namespace balxml {
84
85 // ==================================
86 // struct Formatter_PrettyImplStateId
87 // ==================================
88
89/// This `struct` provides a namespace for enumerating the set of labels for
90/// distinct states of `Formatter_PrettyImplState`.
91///
92/// See @ref balxml_formatter_prettyimpl
94
95 // TYPES
96 enum Enum {
97 /// This state indicates that the current write position of the
98 /// formatter is at the start of the document. The formatter is
99 /// only allowed to add an XML header when in this state.
101
102 /// This state indicates that the current write position of the
103 /// formatter is after some tokens have been emitted, such as an XML
104 /// header and/or some comments, but before any XML tags have been
105 /// emitted. The formatter is not allowed to emit an XML header
106 /// when in this state.
108
109 /// This state indicates that the current write position of the
110 /// formatter is immediately after the name of an opening tag, or
111 /// otherwise immediately after the value of an attribute of an
112 /// opening tag. In this state, most token printing operations,
113 /// other than adding attributes, need to emit a ">" character to
114 /// close the currently open tag before emitting their content. For
115 /// example:
116 /// @code
117 /// 1| <someTag
118 /// `---------^
119 ///
120 /// *
121 /// \note Note that there is no '>' character yet
122 /// @endcode
123 /// or:
124 /// @code
125 /// 1| <someTag attr="value" otherAttr="42"
126 /// `-------------------------------------^
127 /// @endcode
129
130 /// This state indicates that the current write position of the
131 /// formatter is after a complete opening tag, before any data for
132 /// the tag, and that there are tokens already emitted on the
133 /// current line (i.e., that the current write position is not at
134 /// the start of the line). In this state, whether or not token
135 /// printing operations need to emit a new line and indentation
136 /// generally depends on the whitespace mode set for the currently-open tag.
137 ///
138 /// \note Note that comments are not considered data.
139 /// For example:
140 /// @code
141 /// 1| <someTag>
142 /// `----------^
143 /// @endcode
144 /// or:
145 /// @code
146 /// 1| <someTag> <!-- comment -->
147 /// `---------------------------^
148 /// @endcode
149 /// or:
150 /// @code
151 /// 1| <someTag attr="value">
152 /// 2| <!-- comment -->
153 /// `-------------------^
154 /// @endcode
156
157 /// This state indicates that the current write position of the
158 /// formatter is at column 0 (i.e., that it is at the start of a new
159 /// line) and either 1) after a closing tag, or 2) after a complete
160 /// opening tag and optional data. In this state, most token
161 /// printing operations need to emit indentation before their
162 /// content. For example:
163 /// @code
164 /// 1| <someTag>
165 /// 2|
166 /// `^
167 /// @endcode
168 /// or:
169 /// @code
170 /// 1| <someTag>
171 /// 2| </someTag>
172 /// 3|
173 /// `^
174 ///
175 /// *
176 /// \note Note that the 'closeElement' operation, which is used to
177 /// print closing tags, e.g., "</example>", *always* writes a
178 /// newline character after the closing tag.
179 /// @endcode
180 /// or:
181 /// @code
182 /// 1| <someTag>
183 /// 2| some list data
184 /// 3| some more list data
185 /// 4|
186 /// `^
187 /// @endcode
189
190 /// This state indicates that the current write position of the
191 /// formatter is after one or more data tokens for the
192 /// currently-open tag, and that there are tokens already emitted on
193 /// the current line (i.e., that the current write position is not
194 /// at the start of a new line). In this state, data printing
195 /// operations must put delimiting whitespace before their data.
196 /// What whitespace they emit may depend on the whitespace mode of
197 /// the currently-open tag. For example:
198 /// @code
199 /// 1| <someTag> someData
200 /// `-------------------^
201 /// @endcode
202 /// or
203 /// @code
204 /// 1| <someTag>
205 /// 2| some list data
206 /// 3| some more list data
207 /// `----------------------^
208 /// @endcode
210
211 /// This state indicates that the current write position of the
212 /// formatter is immediately after the top-level closing tag of the
213 /// document.
215 };
216};
217
218 // ===============================
219 // class Formatter_PrettyImplState
220 // ===============================
221
222/// This class provides an in-core, value-semantic attribute type that
223/// maintains all of the state information needed to pretty-print an XML
224/// document using the operations provided by `Formatter_PrettyImplUtil`.
225///
226/// See @ref balxml_formatter_prettyimpl
228
229 public:
230 // TYPES
234
235 private:
236 // DATA
237
238 // the canonical "state" in the state machine, upon which most
239 // control-flow decisions are based when printing
240 Id::Enum d_id;
241
242 // number of indentations to perform when printing an element on a new
243 // line
244 int d_indentLevel;
245
246 // number of spaces to print per level of indentation
247 int d_spacesPerLevel;
248
249 // the current column number
250 int d_column;
251
252 // the column number at which an element will be printed on the next
253 // line and optionally indented depending on the requested whitespace
254 // mode
255 int d_wrapColumn;
256
257 // a stack of names of currently nested elements with the whitespace
258 // handling constraint for each element in the stack
259 bsl::vector<WhitespaceType::Enum> d_elementNesting;
260
261 public:
262 // TRAITS
265
266 // CREATORS
267
268 /// Create a `Formatter_PrettyImplState` having an `id` attribute of
269 /// `Id::e_AT_START`, `indentLevel`, `spacesPerLevel`, `column`, and
270 /// `wrapColumn` attributes of 0, and an empty `elementNesting`
271 /// attribute. Optionally specify an `allocator` (e.g., the address of
272 /// a `bslma::Allocator` object) to supply memory; otherwise, the
273 /// default allocator is used.
275 explicit Formatter_PrettyImplState(const allocator_type& allocator);
276
277 /// Create a `Formatter_PrettyImplState` having an `id` attribute of
278 /// `Id::e_AT_START`, the specified `indentLevel`, the specified
279 /// `spacesPerLevel`, and the specified `wrapColumn`, a `column`
280 /// attribute of 0, and an empty `elementNesting` attribute. Optionally
281 /// specify an `allocator` (e.g., the address of a `bslma::Allocator`
282 /// object) to supply memory; otherwise, the default allocator is used.
284 int indentLevel,
285 int spacesPerLevel,
286 int wrapColumn,
287 const allocator_type& allocator = allocator_type());
288
289 /// Create a `Formatter_PrettyImplState` having the specified `id`,
290 /// `indentLevel`, `spacesPerLevel`, `column`, `wrapColumn`, and
291 /// `elementNesting` attributes. Optionally specify an `allocator`
292 /// (e.g., the address of a `bslma::Allocator` object) to supply memory;
293 /// otherwise, the default allocator is used.
295 Id::Enum id,
296 int indentLevel,
297 int spacesPerLevel,
298 int column,
299 int wrapColumn,
301 const allocator_type& allocator = allocator_type());
302
303 /// Create a `Formatter_PrettyImplState` object having the same value as
304 /// the specified `original` object. Optionally specify an `allocator`
305 /// (e.g., the address of a `bslma::Allocator` object) to supply memory;
306 /// otherwise, the default allocator is used.
308 const Formatter_PrettyImplState& original,
309 const allocator_type& allocator = allocator_type());
310
311 // MANIPULATORS
312
313 /// Return a reference providing modifiable access to the `column`
314 /// attribute of this object.
315 int& column();
316
317 /// Return a reference providing modifiable access to the
318 /// `elementNesting` attribute of this object.
320
321 /// Return a reference providing modifiable access to the `id` attribute
322 /// of this object.
323 Id::Enum& id();
324
325 /// Return a reference providing modifiable access to the `indentLevel`
326 /// attribute of this object.
327 int& indentLevel();
328
329 /// Return a reference providing modifiable access to the
330 /// `spacesPerLevel` attribute of this object.
331 int& spacesPerLevel();
332
333 /// Return a reference providing modifiable access to the `wrapColumn`
334 /// attribute of this object.
335 int& wrapColumn();
336
337 // ACCESSORS
338
339 /// Return a reference providing non-modifiable access to the `column`
340 /// attribute of this object.
341 const int& column() const;
342
343 /// Return a reference providing non-modifiable access to the
344 /// `elementNesting` attribute of this object.
346
347 /// Return the allocator associated with this object.
349
350 /// Return a reference providing non-modifiable access to the `id`
351 /// attribute of this object.
352 const Id::Enum& id() const;
353
354 /// Return a reference providing non-modifiable access to the
355 /// `indentLevel` attribute of this object.
356 const int& indentLevel() const;
357
358 /// Return a reference providing non-modifiable access to the
359 /// `spacesPerLevel` attribute of this object.
360 const int& spacesPerLevel() const;
361
362 /// Return a reference providing non-modifiable access to the
363 /// `wrapColumn` attribute of this object.
364 const int& wrapColumn() const;
365};
366
367 // ==============================
368 // class Formatter_PrettyImplUtil
369 // ==============================
370
371/// This utility `struct` provides a namespace for a suite of operations
372/// used to pretty-print XML documents given a sequence of tokens to emit.
373/// Together with `Formatter_PrettyImplState`, this `struct` provides an
374/// implementation of a state machine for such pretty-printing.
375///
376/// See @ref balxml_formatter_prettyimpl
378
379 // TYPES
383
384 private:
385 // PRIVATE TYPES
386 enum {
387 k_VALUE_STRING_BUFFER_SIZE = 256,
388
389 k_INFINITE_WRAP_COLUMN = 0
390 };
391
393 BufferedAllocator;
394
395 // PRIVATE CLASS METHODS
396
397 /// Add an attribute of the specified `name` and `value` to the
398 /// currently open element in the specified `stream`, with formatting
399 /// depending on the specified `state`, and update the `state`
400 /// accordingly. Precede this name="value" pair with a single space.
401 /// Wrap line (write the attribute on next line with proper
402 /// indentation), if the length of name="value" is too long. `value` is
403 /// truncated at any invalid UTF-8 byte-sequence or any control
404 /// character. The list of invalid control characters includes
405 /// characters in the range `[0x00, 0x20)` and `0x7F` (DEL) but does not
406 /// include `0x9`, `0xA`, and `0x0D`. The five special characters:
407 /// apostrophe, double quote, ampersand, less than, and greater than are escaped in the output XML.
408 ///
409 /// \pre The behavior is undefined unless the
410 /// last manipulator was `openElement` or `addAttribute`.
411 static void addAttributeImpl(bsl::ostream& stream,
412 State *state,
413 const bsl::string_view& name,
414 const bsl::string_view& value);
415
416 /// Write the specified `openMarker`, `comment`, and then `closeMarker`
417 /// into the specified `stream`, with formatting depending on the
418 /// specified `state`, and update the `state` accordingly. If an
419 /// element-opening tag is not completed with a `>`, `addCommentImpl`
420 /// will add `>`.
421 static void addCommentImpl(bsl::ostream& stream,
422 State *state,
423 const bsl::string_view& comment,
424 const bsl::string_view& openMarker,
425 const bsl::string_view& closeMarker);
426
427 /// Write the specified `openMarker`, `comment`, and then `closeMarker`
428 /// into the specified `stream` on their own line, with formatting
429 /// depending on the specified `state`, and update the `state`
430 /// accordingly. If an element-opening tag is not completed with a `>`,
431 /// `addCommentImpl` will add `>`.
432 static void addCommentOnNewLineImpl(bsl::ostream& stream,
433 State *state,
434 const bsl::string_view& comment,
435 const bsl::string_view& openMarker,
436 const bsl::string_view& closeMarker);
437
438 static void addDataImpl(bsl::ostream& stream,
439 State *state,
440 const bsl::string_view& value);
441
442 /// Add the specified `value` as the data content to the specified
443 /// `stream`, with formatting depending on the specified `state`, and
444 /// update `state` accordingly. `addListData` prefixes the `value` with
445 /// a space(`0x20`) unless the data being added is the first data on a
446 /// line. In the case of `addData`, perform no line-wrapping or
447 /// indentation as if the whitespace constraint were always
448 /// `BAEXML_PRESERVE_WHITESPACE` in `openElement`, with the only
449 /// exception that an initial newline and an initial indent is added
450 /// when `openElement` specifies `BAEXML_NEWLINE_INDENT` option. In the
451 /// case of `addListData`, when adding the data makes the line too long,
452 /// perform line-wrapping and indentation as determined by the
453 /// whitespace constraint used when the current element is opened with
454 /// `openElement`. `value` is truncated at any invalid UTF-8
455 /// byte-sequence or any control character. The list of invalid control
456 /// characters includes characters in the range `[0x00, 0x20)` and
457 /// `0x7F` (DEL) but does not include `0x9`, `0xA`, and `0x0D`. The
458 /// five special characters: apostrophe, double quote, ampersand, less
459 /// than, and greater than are escaped in the output XML.
460 ///
461 /// \pre The behavior is undefined if the call is made when there are no opened elements.
462 static void addListDataImpl(bsl::ostream& stream,
463 State *state,
464 const bsl::string_view& value);
465
466 public:
467 // CLASS METHODS
468
469 /// Add an attribute of the specified `name` and specified `value` to
470 /// the currently open element in the specified `stream`, with
471 /// formatting depending on the specified `state`, and update the
472 /// `state` accordingly. Return the `stream`. `value` can be of the
473 /// following types: `char`, `short`, `int`, `bsls::Types::Int64`,
474 /// `float`, `double`, `bsl::string`, `bdlt::Datetime`, `bdlt::Date`,
475 /// and `bdlt::Time`. Precede this name="value" pair with a single
476 /// space. Wrap line (write the attribute on next line with proper
477 /// indentation), if the length of name="value" is too long. Optionally
478 /// specify `formattingMode` and `encoderOptions` to control the
479 /// formatting of `value`. If `value` is of type `bsl::string`, it is
480 /// truncated at any invalid UTF-8 byte-sequence or any control
481 /// character. The list of invalid control characters includes
482 /// characters in the range `[0x00, 0x20)` and `0x7F` (DEL) but does not
483 /// include `0x9`, `0xA`, and `0x0D`. The five special characters:
484 /// apostrophe, double quote, ampersand, less than, and greater than are
485 /// escaped in the output XML. If `value` is of type `char`, it is cast
486 /// to a signed byte value with a range `[ -128 .. 127 ]`.
487 ///
488 /// \pre The behavior is undefined unless the last manipulator was `openElement`
489 /// or `addAttribute`.
490 template <class VALUE_TYPE>
491 static bsl::ostream& addAttribute(
492 bsl::ostream& stream,
493 State *state,
494 const bsl::string_view& name,
495 const VALUE_TYPE& value,
496 int formattingMode = 0,
497 const EncoderOptions& encoderOptions = EncoderOptions());
498
499 /// Insert one or two newline characters into the specified `stream`
500 /// stream such that a blank line results, depending on the specified
501 /// `state`, and update the `state` accordingly. Return the `stream`.
502 /// If the last output was a newline, then only one newline is added,
503 /// otherwise two newlines are added. If following a call to
504 /// `openElement`, or `addAttribute`, add a closing `>` to the opened
505 /// tag.
506 static bsl::ostream& addBlankLine(bsl::ostream& stream, State *state);
507
508 /// Write the specified `comment` into the specified `stream`, with
509 /// formatting depending on the specified `state`, and update the
510 /// `state` accordingly. Return the `stream`. The optionally specified
511 /// `forceNewline`, if true, forces to start a new line solely for the
512 /// comment if it's not on a new line already. Otherwise, comments
513 /// continue on current line. If an element-opening tag is not
514 /// completed with a `>`, `addComment` will add `>`.
515 ///
516 /// @deprecated Use @ref addValidComment instead.
517 static bsl::ostream& addComment(
518 bsl::ostream& stream,
519 State *state,
520 const bsl::string_view& comment,
521 bool forceNewline = true);
522
523 /// Add the specified `value` as the data content to the specified
524 /// `stream`, with formatting depending on the specified `state`, and
525 /// update `state` accordingly. Return the `stream`. Return the
526 /// `stream`. `value` can be of the following types: `char`, `short`,
527 /// `int`, `bsls::Types::Int64`, `float`, `double`, `bsl::string`,
528 /// `bdlt::Datetime`, `bdlt::Date`, and `bdlt::Time`. Perform no
529 /// line-wrapping or indentation as if the whitespace constraint were
530 /// always `BAEXML_PRESERVE_WHITESPACE` in `openElement`, with the only
531 /// exception that an initial newline and an initial indent is added
532 /// when `openElement` specifies `BAEXML_NEWLINE_INDENT` option. If
533 /// `value` is of type `bsl::string`, it is truncated at any invalid
534 /// UTF-8 byte-sequence or any control character. The list of invalid
535 /// control characters includes characters in the range `[0x00, 0x20)`
536 /// and `0x7F` (DEL) but does not include `0x9`, `0xA`, and `0x0D`. The
537 /// five special characters: apostrophe, double quote, ampersand, less
538 /// than, and greater than are escaped in the output XML. If `value` is
539 /// of type `char`, it is cast to a signed byte value with a range of '[
540 /// -128 .. 127 ]`. Optionally specify the `formattingMode' and
541 /// `encoderOptions` to specify the format used to encode `value`.
542 ///
543 /// \pre The behavior is undefined if the call is made when there are no opened
544 /// elements.
545 template <class VALUE_TYPE>
546 static bsl::ostream& addData(
547 bsl::ostream& stream,
548 State *state,
549 const VALUE_TYPE& value,
550 int formattingMode = 0,
551 const EncoderOptions& encoderOptions = EncoderOptions());
552
553 /// Add element of the specified `name` and the specified `value` as the
554 /// data content to the specified `stream`, with formatting depending on
555 /// the specified `state` and the optionally specified `encoderOptions`,
556 /// and update `state` accordingly. Return the `stream`. This has the
557 /// same effect as calling the following sequence: 'openElement(name);
558 /// addData(value), closeElement(name);'. Optionally specify the
559 /// `formattingMode`.
560 template <class TYPE>
561 static bsl::ostream& addElementAndData(
562 bsl::ostream& stream,
563 State *state,
564 const bsl::string_view& name,
565 const TYPE& value,
566 int formattingMode = 0,
567 const EncoderOptions& encoderOptions = EncoderOptions());
568
569 /// Add XML header with optionally specified `encoding` to the specified
570 /// `stream`, with formatting depending on the specified `state`, and
571 /// update `state` accordingly. Return the `stream`. Version is always "1.0".
572 ///
573 /// \pre The behavior is undefined unless `addHeader` is the first
574 /// manipulator (with the exception of `rawOutputStream`) after
575 /// construction or `reset`.
576 static bsl::ostream& addHeader(bsl::ostream& stream,
577 State *state,
578 const bsl::string_view& encoding);
579
580 /// Add the specified `value` as the data content to the specified
581 /// `stream`, with formatting depending on the specified `state`, and
582 /// update `state` accordingly. Return the `stream`. `value` can be of
583 /// the following types: `char`, `short`, `int`, `bsls::Types::Int64`,
584 /// `float`, `double`, `bsl::string`, `bdlt::Datetime`, `bdlt::Date`,
585 /// and `bdlt::Time`. Prefix the `value` with a space(`0x20`) unless
586 /// the data being added is the first data on a line. When adding the
587 /// data makes the line too long, perform line-wrapping and indentation
588 /// as determined by the whitespace constraint used when the current
589 /// element is opened with `openElement`. If `value` is of type
590 /// `bsl::string`, it is truncated at any invalid UTF-8 byte-sequence or
591 /// any control character. The list of invalid control characters
592 /// includes characters in the range `[0x00, 0x20)` and `0x7F` (DEL) but
593 /// does not include `0x9`, `0xA`, and `0x0D`. The five special
594 /// characters: apostrophe, double quote, ampersand, less than, and
595 /// greater than are escaped in the output XML. If `value` is of type
596 /// `char`, it is cast to a signed byte value with a range of '[ -128 ..
597 /// 127 ]`. Optionally specify the `formattingMode' and
598 /// `encoderOptions` to specify the format used to encode `value`.
599 ///
600 /// \pre The behavior is undefined if the call is made when there are no opened
601 /// elements.
602 template <class VALUE_TYPE>
603 static bsl::ostream& addListData(
604 bsl::ostream& stream,
605 State *state,
606 const VALUE_TYPE& value,
607 int formattingMode = 0,
608 const EncoderOptions& encoderOptions = EncoderOptions());
609
610 /// Insert a literal newline into the XML output of the specified
611 /// `stream`, with formatting depending on the specified `state`, and
612 /// update `state` accordingly. Return the `stream`. If following a
613 /// call to `openElement`, or `addAttribute`, add a closing `>` to the
614 /// opened tag.
615 static bsl::ostream& addNewline(bsl::ostream& stream, State *state);
616
617 /// Write the specified `comment` into the specified `stream`, with
618 /// formatting depending on the specified `state`, and update the
619 /// `state` accordingly. If the optionally specified `forceNewline` is
620 /// `true` then a new line is inserted for comments not already on a new
621 /// line. Also optionally specify an `omitEnclosingWhitespace` that
622 /// specifies if a space character should be omitted before and after
623 /// `comment`. If `omitEnclosingWhitespace` is not specified then a
624 /// space character is inserted before and after `comment`. Return 0 on success, and non-zero value otherwise.
625 ///
626 /// \note Note that a non-zero return
627 /// value is returned if either `comment` contains `--` or if
628 /// `omitEnclosingWhitespace` is `true` and `comment` ends with `-`.
629 /// Also note that if an element-opening tag is not completed with a
630 /// `>`, `addValidComment` will add `>`.
631 static int addValidComment(
632 bsl::ostream& stream,
633 State *state,
634 const bsl::string_view& comment,
635 bool forceNewline = true,
636 bool omitEnclosingWhitespace = false);
637
638 /// Decrement the indent level and add the closing tag for the element
639 /// of the specified `name` to the specified `stream`, with formatting
640 /// depending on the specified `state`, and update `state` accordingly.
641 /// Return the `stream`. If the element does not have content, write
642 /// `/>` and a newline into stream. Otherwise, write `</name>` and a
643 /// newline. If this `</name>` does not share the same line with data,
644 /// or it follows another element's closing tag, indent properly before
645 /// writing `</name>` and the newline. If `name` is root element, flush the output stream.
646 ///
647 /// \pre The behavior is undefined if `name` is not the
648 /// most recently opened element that's yet to be closed.
649 static bsl::ostream& closeElement(bsl::ostream& stream,
650 State *state,
651 const bsl::string_view& name);
652
653 /// Insert the closing `>` if there is an incomplete tag, and flush the
654 /// specified output `stream`, with formatting depending on the
655 /// specified `state`, and update `state` accordingly. Return the
656 /// `stream`.
657 static bsl::ostream& flush(bsl::ostream& stream, State *state);
658
659 /// Open an element of the specified `name` at current indent level with
660 /// the optionally specified whitespace constraint `whitespaceMode` for
661 /// its textual data to the specified `stream`, with formatting
662 /// depending on the specified `state`, and update `state` accordingly,
663 /// incrementing the indent level. Return the `stream`.
664 /// `whitespaceMode` constrains how textual data is written with
665 /// `addListData` for the current element, but not its nested elements.
666 ///
667 /// \pre The behavior is undefined if `openElement` is called after the root
668 /// element is closed and there is no subsequent call to `reset`.
669 static bsl::ostream&
670 openElement(bsl::ostream& stream,
671 State *state,
672 const bsl::string_view& name,
673 WhitespaceType::Enum whitespaceMode =
675
676 /// Reset the specified formatter `state` such that it can be used to
677 /// format a new XML document as if the formatter were just constructed
678 static void reset(State *state);
679};
680
681// ============================================================================
682// INLINE DEFINITIONS
683// ============================================================================
684
685 // -------------------------------
686 // class Formatter_PrettyImplState
687 // -------------------------------
688
689// CREATORS
690inline
692: d_id(Id::e_AT_START)
693, d_indentLevel(0)
694, d_spacesPerLevel(0)
695, d_column(0)
696, d_wrapColumn(0)
697, d_elementNesting()
698{
699}
700
701inline
703 const allocator_type& allocator)
704: d_id(Id::e_AT_START)
705, d_indentLevel(0)
706, d_spacesPerLevel(0)
707, d_column(0)
708, d_wrapColumn(0)
709, d_elementNesting(allocator)
710{
711}
712
713inline
715 const Formatter_PrettyImplState& original,
716 const allocator_type& allocator)
717: d_id(original.d_id)
718, d_indentLevel(original.d_indentLevel)
719, d_spacesPerLevel(original.d_spacesPerLevel)
720, d_column(original.d_column)
721, d_wrapColumn(original.d_wrapColumn)
722, d_elementNesting(original.d_elementNesting, allocator)
723{
724}
725
726inline
728 int indentLevel,
729 int spacesPerLevel,
730 int wrapColumn,
731 const allocator_type& allocator)
732: d_id(Id::e_AT_START)
733, d_indentLevel(indentLevel)
734, d_spacesPerLevel(spacesPerLevel)
735, d_column()
736, d_wrapColumn(wrapColumn)
737, d_elementNesting(allocator)
738{
739}
740
741inline
743 Id::Enum id,
744 int indentLevel,
745 int spacesPerLevel,
746 int column,
747 int wrapColumn,
748 const bsl::vector<WhitespaceType::Enum>& elementNesting,
749 const allocator_type& allocator)
750: d_id(id)
751, d_indentLevel(indentLevel)
752, d_spacesPerLevel(spacesPerLevel)
753, d_column(column)
754, d_wrapColumn(wrapColumn)
755, d_elementNesting(elementNesting, allocator)
756{
757}
758
759// MANIPULATORS
760inline
762{
763 return d_column;
764}
765
766inline
769{
770 return d_elementNesting;
771}
772
773inline
778
779inline
781{
782 return d_indentLevel;
783}
784
785inline
787{
788 return d_spacesPerLevel;
789}
790
791inline
793{
794 return d_wrapColumn;
795}
796
797// ACCESSORS
798inline
800{
801 return d_column;
802}
803
804inline
807{
808 return d_elementNesting;
809}
810
811inline
814{
815 return d_elementNesting.get_allocator();
816}
817
818inline
820{
821 return d_id;
822}
823
824inline
826{
827 return d_indentLevel;
828}
829
830inline
832{
833 return d_spacesPerLevel;
834}
835
836inline
838{
839 return d_wrapColumn;
840}
841
842 // ------------------------------
843 // class Formatter_PrettyImplUtil
844 // ------------------------------
845
846// CLASS METHODS
847template <class VALUE_TYPE>
849 bsl::ostream& stream,
850 State *state,
851 const bsl::string_view& name,
852 const VALUE_TYPE& value,
853 int formattingMode,
854 const EncoderOptions& encoderOptions)
855{
856 BufferedAllocator allocator;
857 bdlsb::MemOutStreamBuf sb(&allocator);
858 bsl::ostream ss(&sb);
859
860 TypesPrintUtil::print(ss, value, formattingMode, &encoderOptions);
861 if (!ss.good()) {
862 stream.setstate(bsl::ios_base::failbit);
863 return stream; // RETURN
864 }
865
866 const bsl::string_view valueString(sb.data(), sb.length());
867
868 addAttributeImpl(stream, state, name, valueString);
869
870 return stream;
871}
872
873
874template <class VALUE_TYPE>
876 bsl::ostream& stream,
877 State *state,
878 const VALUE_TYPE& valueData,
879 int formattingMode,
880 const EncoderOptions& encoderOptions)
881{
882 BufferedAllocator allocator;
883 bdlsb::MemOutStreamBuf sb(&allocator);
884 bsl::ostream ss(&sb);
885
886 TypesPrintUtil::print(ss, valueData, formattingMode, &encoderOptions);
887 if (!ss.good()) {
888 stream.setstate(bsl::ios_base::failbit);
889 return stream; // RETURN
890 }
891
892 const bsl::string_view valueString(sb.data(), sb.length());
893 addDataImpl(stream, state, valueString);
894 return stream;
895}
896
897template <class TYPE>
899 bsl::ostream& stream,
900 State *state,
901 const bsl::string_view& name,
902 const TYPE& value,
903 int formattingMode,
904 const EncoderOptions& encoderOptions)
905{
907 addData(stream, state, value, formattingMode, encoderOptions);
908 closeElement(stream, state, name);
909 return stream;
910}
911
912template <class VALUE_TYPE>
914 bsl::ostream& stream,
915 State *state,
916 const VALUE_TYPE& value,
917 int formattingMode,
918 const EncoderOptions& encoderOptions)
919{
920 BufferedAllocator allocator;
921 bdlsb::MemOutStreamBuf sb(&allocator);
922 bsl::ostream ss(&sb);
923
924 TypesPrintUtil::print(ss, value, formattingMode, &encoderOptions);
925 if (!ss.good()) {
926 stream.setstate(bsl::ios_base::failbit);
927 return stream; // RETURN
928 }
929
930 const bsl::string_view valueString(sb.data(), sb.length());
931 addListDataImpl(stream, state, valueString);
932 return stream;
933}
934
935inline
937{
938 state->column() = 0;
939 state->id() = StateId::e_AT_START;
940 state->indentLevel() -= static_cast<int>(state->elementNesting().size());
941 state->elementNesting().clear();
942}
943
944} // close package namespace
945
946
947#endif // INCLUDED_BALXML_FORMATTER_PRETTYIMPL
948
949// ----------------------------------------------------------------------------
950// Copyright 2021 Bloomberg Finance L.P.
951//
952// Licensed under the Apache License, Version 2.0 (the "License");
953// you may not use this file except in compliance with the License.
954// You may obtain a copy of the License at
955//
956// http://www.apache.org/licenses/LICENSE-2.0
957//
958// Unless required by applicable law or agreed to in writing, software
959// distributed under the License is distributed on an "AS IS" BASIS,
960// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
961// See the License for the specific language governing permissions and
962// limitations under the License.
963// ----------------------------- END-OF-FILE ----------------------------------
964
965/** @} */
966/** @} */
967/** @} */
Definition balxml_encoderoptions.h:89
Definition balxml_formatter_prettyimpl.h:227
Formatter_PrettyImplState()
Definition balxml_formatter_prettyimpl.h:691
Id::Enum & id()
Definition balxml_formatter_prettyimpl.h:774
bsl::allocator< char > allocator_type
Definition balxml_formatter_prettyimpl.h:231
int & column()
Definition balxml_formatter_prettyimpl.h:761
int & wrapColumn()
Definition balxml_formatter_prettyimpl.h:792
Formatter_PrettyImplStateId Id
Definition balxml_formatter_prettyimpl.h:232
int & spacesPerLevel()
Definition balxml_formatter_prettyimpl.h:786
FormatterWhitespaceType WhitespaceType
Definition balxml_formatter_prettyimpl.h:233
int & indentLevel()
Definition balxml_formatter_prettyimpl.h:780
BSLMF_NESTED_TRAIT_DECLARATION(Formatter_PrettyImplState, bslma::UsesBslmaAllocator)
allocator_type get_allocator() const
Return the allocator associated with this object.
Definition balxml_formatter_prettyimpl.h:813
bsl::vector< WhitespaceType::Enum > & elementNesting()
Definition balxml_formatter_prettyimpl.h:768
Definition bdlma_localsequentialallocator.h:230
Definition bdlsb_memoutstreambuf.h:212
bsl::size_t length() const
Return the number of valid characters in this stream buffer.
Definition bdlsb_memoutstreambuf.h:419
const char * data() const
Definition bdlsb_memoutstreambuf.h:413
Definition bslma_bslallocator.h:588
Definition bslstl_stringview.h:471
size_type size() const BSLS_KEYWORD_NOEXCEPT
Return the number of elements in this vector.
Definition bslstl_vector.h:3019
Definition bslstl_vector.h:1120
allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:4621
void swap(vector &other) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(AllocatorTraits void clear() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:1938
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition balxml_base64parser.h:150
Definition balxml_formatterwhitespacetype.h:70
Enum
Definition balxml_formatterwhitespacetype.h:73
@ e_PRESERVE_WHITESPACE
Definition balxml_formatterwhitespacetype.h:74
Definition balxml_formatter_prettyimpl.h:93
Enum
Definition balxml_formatter_prettyimpl.h:96
@ e_TRAILING_DATA_BETWEEN_TAGS
Definition balxml_formatter_prettyimpl.h:209
@ e_IN_TAG
Definition balxml_formatter_prettyimpl.h:128
@ e_AFTER_START_NO_TAG
Definition balxml_formatter_prettyimpl.h:107
@ e_AT_START
Definition balxml_formatter_prettyimpl.h:100
@ e_FIRST_DATA_BETWEEN_TAGS
Definition balxml_formatter_prettyimpl.h:155
@ e_AT_END
Definition balxml_formatter_prettyimpl.h:214
@ e_FIRST_DATA_AT_LINE_BETWEEN_TAGS
Definition balxml_formatter_prettyimpl.h:188
Definition balxml_formatter_prettyimpl.h:377
static bsl::ostream & addListData(bsl::ostream &stream, State *state, const VALUE_TYPE &value, int formattingMode=0, const EncoderOptions &encoderOptions=EncoderOptions())
Definition balxml_formatter_prettyimpl.h:913
Formatter_PrettyImplState State
Definition balxml_formatter_prettyimpl.h:380
static bsl::ostream & addNewline(bsl::ostream &stream, State *state)
static bsl::ostream & addAttribute(bsl::ostream &stream, State *state, const bsl::string_view &name, const VALUE_TYPE &value, int formattingMode=0, const EncoderOptions &encoderOptions=EncoderOptions())
Definition balxml_formatter_prettyimpl.h:848
static bsl::ostream & flush(bsl::ostream &stream, State *state)
static bsl::ostream & addComment(bsl::ostream &stream, State *state, const bsl::string_view &comment, bool forceNewline=true)
FormatterWhitespaceType WhitespaceType
Definition balxml_formatter_prettyimpl.h:382
static bsl::ostream & addData(bsl::ostream &stream, State *state, const VALUE_TYPE &value, int formattingMode=0, const EncoderOptions &encoderOptions=EncoderOptions())
Definition balxml_formatter_prettyimpl.h:875
static int addValidComment(bsl::ostream &stream, State *state, const bsl::string_view &comment, bool forceNewline=true, bool omitEnclosingWhitespace=false)
static bsl::ostream & openElement(bsl::ostream &stream, State *state, const bsl::string_view &name, WhitespaceType::Enum whitespaceMode=WhitespaceType::e_PRESERVE_WHITESPACE)
static bsl::ostream & addElementAndData(bsl::ostream &stream, State *state, const bsl::string_view &name, const TYPE &value, int formattingMode=0, const EncoderOptions &encoderOptions=EncoderOptions())
Definition balxml_formatter_prettyimpl.h:898
static bsl::ostream & addBlankLine(bsl::ostream &stream, State *state)
static bsl::ostream & addHeader(bsl::ostream &stream, State *state, const bsl::string_view &encoding)
static void reset(State *state)
Definition balxml_formatter_prettyimpl.h:936
static bsl::ostream & closeElement(bsl::ostream &stream, State *state, const bsl::string_view &name)
Formatter_PrettyImplStateId StateId
Definition balxml_formatter_prettyimpl.h:381
static bsl::ostream & print(bsl::ostream &stream, const TYPE &object, int formattingMode, const EncoderOptions *encoderOptions=0)
Definition balxml_typesprintutil.h:1166
Definition bslma_usesbslmaallocator.h:344