BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balxml_formatter.h
Go to the documentation of this file.
1/// @file balxml_formatter.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balxml_formatter.h -*-C++-*-
8#ifndef INCLUDED_BALXML_FORMATTER
9#define INCLUDED_BALXML_FORMATTER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balxml_formatter balxml_formatter
15/// @brief Provide a simple interface for writing formatted XML.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balxml
19/// @{
20/// @addtogroup balxml_formatter
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balxml_formatter-purpose"> Purpose</a>
25/// * <a href="#balxml_formatter-classes"> Classes </a>
26/// * <a href="#balxml_formatter-description"> Description </a>
27/// * <a href="#balxml_formatter-special-characters"> Special Characters </a>
28/// * <a href="#balxml_formatter-valid-strings"> Valid Strings </a>
29/// * <a href="#balxml_formatter-usage"> Usage </a>
30/// * <a href="#balxml_formatter-example-1-basic-usage"> Example 1: Basic Usage </a>
31///
32/// # Purpose {#balxml_formatter-purpose}
33/// Provide a simple interface for writing formatted XML.
34///
35/// # Classes {#balxml_formatter-classes}
36///
37/// - balxml::Formatter: provides formatted XML
38///
39/// @see
40///
41/// # Description {#balxml_formatter-description}
42/// The `balxml::Formatter` class provides methods to write a
43/// formatted XML to an underlining output stream. These methods generate
44/// header, tags, data, attributes, comments in a human-readable, indented
45/// format.
46///
47/// XML documents use a self-describing and simple syntax that consists of
48/// nested XML elements. Each element is bounded by a pair of opening and
49/// closing tags. Within the pair of tags, there can be more nested elements,
50/// or just plain text or numeric data in text format. The opening tag of an
51/// element can also contain attributes in the form of name="value" pairs.
52/// This component provides methods to generate these XML ingredients and takes
53/// care of proper indentation and line wrapping. Visit
54/// http://www.w3schools.com/xml/xml_syntax.asp for a complete tutorial.
55///
56/// ## Special Characters {#balxml_formatter-special-characters}
57///
58///
59/// XML defines five special characters that must not appear text; instead
60/// these characters are must be represented by multi-byte escape sequences.
61/// @code
62/// Special (Hex) XML Escape
63/// Character Value Description Sequence
64/// --------- ----- ----------- ----------
65/// " x22 quote &quot;
66/// & x26 ampersand &amp;
67/// ' x27 apostrophe &apos;
68/// < x3C less than &lt;
69/// > x3E greater than &gt;
70/// @endcode
71/// The following methods:
72/// * `addAttribute`,
73/// * `addData`, and
74/// * `addListData`
75/// implicitly convert each special character found in string input to the
76/// appropriate escape sequence in the resulting XML document.
77///
78/// ## Valid Strings {#balxml_formatter-valid-strings}
79///
80///
81/// Strings used to set element attributes and element data (see `addAttribute`,
82/// `addData`, and `addListData`) must consist of (valid) UTF-8 byte sequences
83/// excepting certain control characters.
84/// @code
85/// Control
86/// Characters Description Allowed
87/// ----------- -------------------------- -------
88/// x09 HT '\t' (horizontal tab) true
89/// x0A LF '\n' (new line) true
90/// x0D CR '\r' (carriage return) true
91/// x7F DEL (delete) false
92///
93/// x01 .. 0x1F Other than HT, LF, and CR. false
94/// @endcode
95/// Notice that range of 31 control characters between `0x01` and `0x1F`
96/// (inclusive) consist of three that are allowed and 28 that are not.
97///
98/// The detection of an invalid character in an input stream stops the transfer
99/// of data to the output stream. The output stream is put into a failed state.
100///
101/// ## Usage {#balxml_formatter-usage}
102///
103///
104/// This section illustrates intended use of this component.
105///
106/// ### Example 1: Basic Usage {#balxml_formatter-example-1-basic-usage}
107///
108///
109/// This example shows ten steps of how to create an XML document using this
110/// component's major manipulators:
111/// @code
112/// // 1. Create a formatter:
113/// balxml::Formatter formatter(bsl::cout);
114///
115/// // 2. Add a header:
116/// formatter.addHeader("UTF-8");
117///
118/// // 3. Open the root element,
119/// // Add attributes if there are any:
120/// formatter.openElement("Fruits");
121///
122/// // 4. Open an element,
123/// // Add attributes if there are any:
124/// formatter.openElement("Oranges");
125/// formatter.addAttribute("farm", "Francis' Orchard"); // ' is escaped
126/// formatter.addAttribute("size", 3.5);
127///
128/// // 5. If there are nested elements, recursively do steps 4 - 8:
129/// // 6. Else, there are no more nested elements, add data:
130/// formatter.openElement("pickDate"); // step 4
131/// formatter.addData(bdlt::Date(2004, 8, 31)); // step 6
132/// formatter.closeElement("pickDate"); // step 7
133/// formatter.addElementAndData("Quantity", 12); // step 8
134/// // element "Quantity" has no attributes, can use
135/// // shortcut 'addElementAndData' to complete steps
136/// // 4, 6 and 7 in one shot.
137///
138/// // 7. Close the element:
139/// formatter.closeElement("Oranges");
140///
141/// // 8. If there are more elements, repeat steps 4 - 8
142/// formatter.openElement("Apples"); // step 4
143/// formatter.addAttribute("farm", "Fuji & Sons"); // '&' is escaped
144/// formatter.addAttribute("size", 3);
145/// formatter.closeElement("Apples"); // step 7
146///
147/// // 9. Close the root element:
148/// formatter.closeElement("Fruits");
149/// @endcode
150/// Indentation is correctly taken care of and the user need only concern
151/// themselves with the correct ordering of the XML elements they're trying to
152/// write. The output of the above example is:
153/// @code
154/// +--bsl::cout--------------------------------------------------------------+
155/// |<?xml version="1.0" encoding="UTF-8" ?> |
156/// |<Fruits> |
157/// | <Oranges farm="Francis&apos; Orchard" size="3.5"> |
158/// | <pickDate>2004-08-31</pickDate> |
159/// | <Quantity>12</Quantity> |
160/// | </Oranges> |
161/// | <Apples farm="Fuji &amp; Sons" size="3"/> |
162/// |</Fruits> |
163/// +-------------------------------------------------------------------------+
164/// @endcode
165/// Following is a more complete usage example that uses most of the
166/// manipulators provided by balxml::Formatter:
167/// @code
168/// balxml::Formatter formatter(bsl::cout, 0, 4, 40);
169///
170/// formatter.addHeader("UTF-8");
171///
172/// formatter.openElement("Fruits");
173/// formatter.openElement("Oranges");
174/// formatter.addAttribute("farm", "Francis' Orchard");
175/// // notice that the apostrophe in the string will be escaped
176/// formatter.addAttribute("size", 3.5);
177///
178/// formatter.addElementAndData("Quantity", 12);
179///
180/// formatter.openElement("pickDate");
181/// formatter.addData(bdlt::Date(2004, 8, 31));
182/// formatter.closeElement("pickDate");
183///
184/// formatter.openElement("Feature");
185/// formatter.addAttribute("shape", "round");
186/// formatter.closeElement("Feature");
187///
188/// formatter.addComment("No wrapping for long comments");
189///
190/// formatter.closeElement("Oranges");
191///
192/// formatter.addBlankLine();
193///
194/// formatter.openElement("Apples");
195/// formatter.addAttribute("farm", "Fuji & Sons");
196/// formatter.addAttribute("size", 3);
197///
198/// formatter.openElement("pickDates",
199/// balxml::Formatter::BAEXML_NEWLINE_INDENT);
200/// formatter.addListData(bdlt::Date(2005, 1, 17));
201/// formatter.addListData(bdlt::Date(2005, 2, 21));
202/// formatter.addListData(bdlt::Date(2005, 3, 25));
203/// formatter.addListData(bdlt::Date(2005, 5, 30));
204/// formatter.addListData(bdlt::Date(2005, 7, 4));
205/// formatter.addListData(bdlt::Date(2005, 9, 5));
206/// formatter.addListData(bdlt::Date(2005, 11, 24));
207/// formatter.addListData(bdlt::Date(2005, 12, 25));
208///
209/// formatter.closeElement("pickDates");
210///
211/// formatter.openElement("Feature");
212/// formatter.addAttribute("color", "red");
213/// formatter.addAttribute("taste", "juicy");
214/// formatter.closeElement("Feature");
215///
216/// formatter.closeElement("Apples");
217///
218/// formatter.closeElement("Fruits");
219///
220/// formatter.reset();
221/// // reset the formatter for a new document in the same stream
222///
223/// formatter.addHeader();
224/// formatter.openElement("Grains");
225///
226/// bsl::ostream& os = formatter.rawOutputStream();
227/// os << "<free>anything that can mess up the XML doc</free>";
228/// // Now coming back to the formatter, but can't do the following:
229/// // formatter.addAttribute("country", "USA");
230/// formatter.addData("Corn, Wheat, Oat");
231/// formatter.closeElement("Grains");
232/// @endcode
233/// Following are the two resulting documents, as separated by the call to
234/// reset(),
235/// @code
236/// +--bsl::cout-----------------------------+
237/// |<?xml version="1.0" encoding="UTF-8" ?> |
238/// |<Fruits> |
239/// | <Oranges |
240/// | farm="Francis&apos; Orchard" |
241/// | size="3.5"> |
242/// | <Quantity>12</Quantity> |
243/// | <pickDate>2004-08-31</pickDate> |
244/// | <Feature shape="round"/> |
245/// | <!-- No wrapping for long comments --> |
246/// | </Oranges> |
247/// | |
248/// | <Apples farm="Fuji &amp; Sons" |
249/// | size="3"> |
250/// | <pickDates> |
251/// | 2005-01-17 2005-02-21 |
252/// | 2005-03-25 2005-05-30 |
253/// | 2005-07-04 2005-09-05 |
254/// | 2005-11-24 2005-12-25 |
255/// | </pickDates> |
256/// | <Feature color="red" |
257/// | taste="juicy"/> |
258/// | </Apples> |
259/// |</Fruits> |
260/// +----------------------------------------+
261/// +--bsl::cout-----------------------------+
262/// |<?xml version="1.0" encoding="UTF-8" ?> |
263/// |<Grains><free>anything that can mess up the XML doc</free>
264/// | Corn, Wheat, Oat</Grains> |
265/// +----------------------------------------+
266/// @endcode
267/// @}
268/** @} */
269/** @} */
270
271/** @addtogroup bal
272 * @{
273 */
274/** @addtogroup balxml
275 * @{
276 */
277/** @addtogroup balxml_formatter
278 * @{
279 */
280
281#include <balscm_version.h>
282
287
288#include <bslma_allocator.h>
289#include <bslma_bslallocator.h>
291
293
294#include <bsls_assert.h>
295#include <bsls_keyword.h>
296#include <bsls_objectbuffer.h>
297
298#include <bslstl_inplace.h>
299
300#include <bsl_optional.h>
301#include <bsl_ostream.h>
302#include <bsl_streambuf.h>
303#include <bsl_string.h>
304
305
306namespace balxml {
307
308class Formatter;
309
310 // ============================
311 // class Formatter_StreamHolder
312 // ============================
313
314/// This component-private class provides a mechanism for holding the
315/// `bsl::ostream` used by the `Formatter` to emit XML documents. Objects
316/// of `Formatter_StreamHolder` type can be constructed with either a
317/// `bsl::streambuf *` or a `bsl::ostream *`. If a stream holder is
318/// constructed with a `bsl::streambuf *`, then it owns its held
319/// `bsl::ostream`, which is constructed with the supplied stream buffer.
320/// If a stream holder is constructed with a `bsl::ostream *`, its held
321/// `bsl::ostream` is the supplied stream.
322///
323/// See @ref balxml_formatter
325
326 // DATA
327
328 // `bsl::ostream` if constructed with a `bsl::streambuf *`, and
329 // disengaged otherwise
330 bsl::optional<bsl::ostream> d_ownStream;
331
332 // the held `bsl::ostream`, which is equal to `&d_ownStream.value()` if
333 // `d_ownStream` is engaged, and the `bsl::ostream *` supplied on
334 // construction otherwise
335 bsl::ostream *d_stream_p;
336
337 // NOT IMPLEMENTED
339 Formatter_StreamHolder& operator=(
341
342 public:
343 // CREATORS
344
345 /// Create a `Formatter_StreamHolder` object that holds a `bsl::ostream`
346 /// constructed from the specified `streamBuffer`.
347 explicit Formatter_StreamHolder(bsl::streambuf *streamBuffer);
348
349 /// Create a `Formatter_StreamHolder` that holds the specified `stream`.
350 explicit Formatter_StreamHolder(bsl::ostream *stream);
351
352 // MANIPULATORS
353
354 /// Return the address that provides modifiable access to this object's
355 /// held `bsl::ostream`.
356 bsl::ostream *stream();
357
358 // ACCESSORS
359
360 /// Return the address that provides non-modifiable access to this
361 /// object's held `bsl::ostream`.
362 const bsl::ostream *stream() const;
363};
364
365 // =====================
366 // struct Formatter_Mode
367 // =====================
368
369/// This component-private utility `struct` provides a namespace for
370/// enumerating the set of formatting modes that the `Formatter` can take.
372
373 // TYPES
378};
379
380 // =====================
381 // class Formatter_State
382 // =====================
383
384/// This component-private, in-core, value-semantic class provides a variant
385/// that can be inhabited by an object of either the component-private
386/// `Formatter_CompactImplState` type or the component-private
387/// `Formatter_PrettyImplState` type.
388///
389/// See @ref balxml_formatter
391
392 public:
393 // TYPES
396
397 private:
398 // PRIVATE TYPES
402
403 enum { k_COMPACT_MODE_WRAP_COLUMN = -1 };
404
405 // DATA
406 Mode::Enum d_mode;
407 union {
410 };
411 allocator_type d_allocator;
412
413 // PRIVATE CREATORS
414
415 /// If the specified `wrapColumn` is -1, create a `Formatter_State`
416 /// object having a `compact` selection, which is a
417 /// `Formatter_CompactImplState` constructed with the specified
418 /// `indentLevel` and `spacesPerLevel`. Otherwise, create a
419 /// `Formatter_State` object having a `pretty` selection, which is a
420 /// `Formatter_PrettyImplState` constructed with the `indentLevel`,
421 /// `spacesPerLevel`, and `wrapColumn`. Optionally specify an
422 /// `allocator` (e.g., the address of a `bslma::Allocator` object) to
423 /// supply memory; otherwise, the default allocator is used.
424 Formatter_State(int indentLevel,
425 int spacesPerLevel,
426 int wrapColumn,
427 const allocator_type& allocator = allocator_type());
428
429 // PRIVATE MANIPULATORS
430
431 /// Return a reference providing modifiable access to the `compact`
432 /// selection of this object. The behavior is undefined unless the
433 /// current selection of this object is `compact`.
434 Compact& compact();
435
436 /// Return a reference providing modifiable access to the `pretty`
437 /// selection of this object. The behavior is undefined unless the
438 /// current selection of this object is `pretty`.
439 Pretty& pretty();
440
441 // PRIVATE ACCESSORS
442
443 /// Return a reference providing non-modifiable access to the `compact`
444 /// selection of this object. The behavior is undefined unless the
445 /// current selection of this object is `compact`.
446 const Compact& compact() const;
447
448 /// Return `Mode::e_COMPACT` if the current selection of this object is
449 /// `compact`, and return `Mode::e_PRETTY` otherwise.
450 Mode::Enum mode() const;
451
452 /// Return a reference providing non-modifiable access to the `pretty`
453 /// selection of this object. The behavior is undefined unless the
454 /// current selection of this object is `pretty`.
455 const Pretty& pretty() const;
456
457 // FRIENDS
458 friend class balxml::Formatter;
459
460 public:
461 // TRAITS
463
464 // CREATORS
465
467 /// Create a `Formatter_State` with a `compact` selection having the
468 /// default value. Optionally specify an `allocator` (e.g., the address
469 /// of a `bslma::Allocator` object) to supply memory; otherwise, the
470 /// default allocator is used.
471 explicit Formatter_State(const allocator_type& allocator);
472
473 /// Create a `Formatter_State` object having the same value as the
474 /// specified `original` object. Optionally specify an `allocator`
475 /// (e.g., the address of a `bslma::Allocator` object) to supply memory;
476 /// otherwise, the default allocator is used.
478 const allocator_type& allocator = allocator_type());
479
480 /// Destroy this object.
482
483 // MANIPULATORS
484
485 /// Assign to this object the value of the specified `rhs` and return a
486 /// reference to this object.
488
489 // ACCESSORS
490
491 /// Return the allocator associated with this object.
493};
494
495 // ===============
496 // class Formatter
497 // ===============
498
499/// This class provides a set of XML-style formatting utilities that enable
500/// transparent indentation and wrapping for users attempting to format data
501/// with XML tags and attributes. A formatter object is instantiated with a
502/// pointer to an output stream or streambuf. Users can then use the
503/// provided utilities to write element tags, attributes, data in a valid
504/// XML sequence into the underlying stream.
505///
506/// This class has no features that would impair thread safety. However, it
507/// does not mediate between two threads attempting to access the same
508/// stream.
509///
510/// See @ref balxml_formatter
512
513 public:
514 // TYPES
515
516 /// `WhitespaceType` describes options available when outputting textual
517 /// data of an element between its pair of opening and closing tags.
519
520 // PUBLIC CLASS DATA
521#ifdef BDE_VERIFY
522#pragma bde_verify push
523#pragma bde_verify -MN03
524#pragma bde_verify -UC01
525#endif
526
529 // data is output as is
530
533 // data may be wrapped if output otherwise exceeds the wrap column
534
537 // in addition to allowing wrapping, indent properly before continuing to
538 // output on the next line after wrapping
539
542 // in addition to allowing wrapping and indentation, the tags do not share
543 // their respective lines with data
544
547 // !DEPRECATED!: Use 'e_NEWLINE_INDENT' instead.
548
549#ifdef BDE_VERIFY
550#pragma bde_verify pop
551#endif
552
553 private:
554 // PRIVATE TYPES
558 typedef Formatter_Mode Mode;
559 typedef Formatter_State State;
560
561 // DATA
562 StreamHolder d_streamHolder;
563 State d_state;
564 EncoderOptions d_encoderOptions;
565
566 // NOT IMPLEMENTED
567 Formatter(const Formatter&);
568 Formatter& operator=(const Formatter&);
569
570 public:
571 // CREATORS
572
573 /// Construct an object to format XML data into the specified `output`
574 /// stream or streambuf. Optionally specify `encoderOptions`, initial
575 /// `indentLevel`, `spacesPerLevel`, and `wrapColumn` for formatting.
576 /// An `indentLevel` of 0 (the default) indicates the root element will
577 /// have no indentation. A `wrapColumn` of 0 will cause the formatter
578 /// to behave as though the line length were infinite, but will still
579 /// insert newlines and indent when starting a new element. A
580 /// `wrapColumn` of -1 will cause output to be formatted in "compact"
581 /// mode -- with no added newlines or indentation. Optionally specify a
582 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
583 /// the currently install default allocator is used. The behavior is
584 /// undefined if the `output` stream or streambuf is destroyed before
585 Formatter(bsl::streambuf *output,
586 int indentLevel = 0,
587 int spacesPerLevel = 4,
588 int wrapColumn = 80,
589 bslma::Allocator *basicAllocator = 0); // IMPLICIT
590 Formatter(bsl::ostream& output,
591 int indentLevel = 0,
592 int spacesPerLevel = 4,
593 int wrapColumn = 80,
594 bslma::Allocator *basicAllocator = 0); // IMPLICIT
595 Formatter(bsl::streambuf *output,
597 int indentLevel = 0,
598 int spacesPerLevel = 4,
599 int wrapColumn = 80,
600 bslma::Allocator *basicAllocator = 0);
601 Formatter(bsl::ostream& output,
603 int indentLevel = 0,
604 int spacesPerLevel = 4,
605 int wrapColumn = 80,
606 bslma::Allocator *basicAllocator = 0);
607
608 // MANIPULATORS
609
610 /// Add an attribute of the specified `name` and specified `value` to
611 /// the currently open element. `value` can be of the following types:
612 /// `char`, `short`, `int`, `bsls::Types::Int64`, `float`, `double`,
613 /// `bsl::string`, `bdlt::Datetime`, `bdlt::Date`, and `bdlt::Time`.
614 /// Precede this name="value" pair with a single space. Wrap line
615 /// (write the attribute on next line with proper indentation), if the
616 /// length of name="value" is too long. Optionally specify a
617 /// `formattingMode` used to control the formatting of the `value`. If
618 /// `value` is of type `bsl::string` or convertible to
619 /// `bsl::string_view`, the presence of invalid input stops the transfer
620 /// of data to the output specified on construction (see {Valid
621 /// Strings}). If `value` is of type `bsl::string` or convertible to
622 /// `bsl::string_view`, any special characters in `value` are escaped
623 /// (see {Special Characters}). If `value` is of type `char`, it is
624 /// cast to a signed byte value with a range `[ -128 .. 127 ]`. The
625 /// behavior is undefined unless the last manipulator was `openElement`
626 /// or `addAttribute`.
627 template <class TYPE>
628 void addAttribute(const bsl::string_view& name,
629 const TYPE& value,
630 int formattingMode = 0);
631
632 /// Insert one or two newline characters into the output stream such
633 /// that a blank line results. If the last output was a newline, then
634 /// only one newline is added, otherwise two newlines are added. If
635 /// following a call to `openElement`, or `addAttribute`, add a closing
636 /// `>` to the opened tag.
637 void addBlankLine();
638
639 /// [**DEPRECATED**] Use `addValidComment` instead.
640 ///
641 /// Write the specified `comment` into the stream. The optionally
642 /// specified `forceNewline`, if true, forces to start a new line solely
643 /// for the comment if it's not on a new line already. Otherwise,
644 /// comments continue on current line. If an element-opening tag is not
645 /// completed with a `>`, `addComment` will add `>`.
646 void addComment(const bsl::string_view& comment, bool forceNewline = true);
647
648 /// Add the specified `value` as the data content, where `value` can be
649 /// of the following types: `char`, `short`, `int`,
650 /// `bsls::Types::Int64`, `float`, `double`, `bsl::string`,
651 /// `bdlt::Datetime`, `bdlt::Date`, and `bdlt::Time`. Perform no
652 /// line-wrapping or indentation as if the whitespace constraint were
653 /// always `BAEXML_PRESERVE_WHITESPACE` in `openElement`, with the only
654 /// exception that an initial newline and an initial indent is added
655 /// when `openElement` specifies `BAEXML_NEWLINE_INDENT` option. If
656 /// `value` is of type `bsl::string` or convertible to
657 /// `bsl::string_view`, the presence of invalid input stops the transfer
658 /// of data to the output specified on construction (see {Valid
659 /// Strings}). If `value` is of type `bsl::string` or convertible to
660 /// `bsl::string_view`, characters in `value` are escaped (see {Special
661 /// Characters}). If `value` is of type `char`, it is cast to a signed
662 /// byte value with a range of `[ -128 .. 127 ]`. Optionally specify
663 /// the `formattingMode` to specify the format used to encode `value`.
664 /// The behavior is undefined if the call is made when there are no
665 /// opened elements.
666 template <class TYPE>
667 void addData(const TYPE& value, int formattingMode = 0);
668
669 /// Add element of the specified `name` and the specified `value` as the
670 /// data content. This has the same effect as calling the following
671 /// sequence: `openElement(name); addData(value), closeElement(name);`.
672 /// Optionally specify the `formattingMode`.
673 template <class TYPE>
674 void addElementAndData(const bsl::string_view& name,
675 const TYPE& value,
676 int formattingMode = 0);
677
678 /// Add XML header with optionally specified `encoding`. Version is
679 /// always "1.0". The behavior is undefined unless `addHeader` is the
680 /// first manipulator (with the exception of `rawOutputStream`) after
681 /// construction or `reset`.
682 void addHeader(const bsl::string_view& encoding = "UTF-8");
683
684 /// Add the specified `value` as the data content, where `value` can be
685 /// of the following types: `char`, `short`, `int`,
686 /// `bsls::Types::Int64`, `float`, `double`, `bsl::string`,
687 /// `bdlt::Datetime`, `bdlt::Date`, and `bdlt::Time`. Prefix the
688 /// `value` with a space(`0x20`) unless the data being added is the
689 /// first data on a line. When adding the data makes the line too long,
690 /// perform line-wrapping and indentation as determined by the
691 /// whitespace constraint used when the current element is opened with
692 /// `openElement`. If `value` is of type `bsl::string` or convertible
693 /// to `bsl::string_view`, the presence of invalid input stops the
694 /// transfer of data to the output specified on construction (see {Valid
695 /// Strings}). If `value` is of type `bsl::string` or convertible to
696 /// `bsl::string_view`, any special characters in `value` are escaped
697 /// (see {Special Characters}). If `value` is of type `char`, it is
698 /// cast to a signed byte value with a range of `[ -128 .. 127 ]`.
699 /// Optionally specify the `formattingMode` to specify the format used
700 /// to encode `value`. The behavior is undefined if the call is made
701 /// when there are no opened elements.
702 template <class TYPE>
703 void addListData(const TYPE& value, int formattingMode = 0);
704
705 /// Insert a literal newline into the XML output. If following a call
706 /// to `openElement`, or `addAttribute`, add a closing `>` to the opened
707 /// tag.
708 void addNewline();
709
710 /// Write the specified `comment` into the stream. Optionally specify
711 /// `forceNewline` that specifies if a new line should be added before
712 /// the comment if it is not already on a new line. If `forceNewline`
713 /// is not specified then a new line is inserted for comments not
714 /// already on a new line. Also optionally specify an
715 /// `omitEnclosingWhitespace` that specifies if a space character should
716 /// be omitted before and after `comment`. If `omitEnclosingWhitespace`
717 /// is not specified then a space character is inserted before and after
718 /// `comment`. Return 0 on success, and non-zero value otherwise. Note
719 /// that a non-zero return value is returned if either `comment`
720 /// contains `--` or if `omitEnclosingWhitespace` is `true` and
721 /// `comment` ends with `-`. Also note that if an element-opening tag
722 /// is not completed with a `>`, `addValidComment` will add `>`.
724 const bsl::string_view& comment,
725 bool forceNewline = true,
726 bool omitEnclosingWhitespace = false);
727
728 /// Decrement the indent level and add the closing tag for the element
729 /// of the specified `name`. If the element does not have content,
730 /// write `/>` and a newline into stream. Otherwise, write `</name>`
731 /// and a newline. If this `</name>` does not share the same line with
732 /// data, or it follows another element's closing tag, indent properly
733 /// before writing `</name>` and the newline. If `name` is root
734 /// element, flush the output stream. The behavior is undefined if
735 /// `name` is not the most recently opened element that's yet to be
736 /// closed.
738
739 /// Insert the closing `>` if there is an incomplete tag, and flush the
740 /// output stream.
741 void flush();
742
743 /// Open an element of the specified `name` at current indent level with
744 /// the optionally specified whitespace constraint `whitespaceMode` for
745 /// its textual data and increment indent level. `whitespaceMode`
746 /// constrains how textual data is written with `addListData` for the
747 /// current element, but not its nested elements. The behavior is
748 /// undefined if `openElement` is called after the root element is
749 /// closed and there is no subsequent call to `reset`.
751 const bsl::string_view& name,
752 WhitespaceType whitespaceMode = e_PRESERVE_WHITESPACE);
753
754 /// Return a reference to the underlining output stream. This method is
755 /// provided in order to enable user to temporarily jump out of the
756 /// formatter and write user's own free-lance content directly to the
757 /// stream.
758 bsl::ostream& rawOutputStream();
759
760 /// Reset the formatter such that it can be used to format a new XML
761 /// document as if the formatter were just constructed
762 void reset();
763
764 // ACCESSORS
765
766 /// Return the encoder options being used.
767 const EncoderOptions& encoderOptions() const;
768
769 /// Return the current level of indentation.
770 int indentLevel() const;
771
772 /// Return the current column position at a line where next output
773 /// starts. This is unreliable if called after free-lance information
774 /// is written onto the stream returned by `rawOutputStream`
775 int outputColumn() const;
776
777 /// Return the number of spaces per indentation level.
778 int spacesPerLevel() const;
779
780 /// Return 0 if no errors have been detected since construction or
781 /// since the last call to `reset`, otherwise return a negative value.
782 int status() const;
783
784 /// Return the line width where line-wrapping takes place.
785 int wrapColumn() const;
786};
787
788// ============================================================================
789// INLINE DEFINITIONS
790// ============================================================================
791
792 // ----------------------------
793 // class Formatter_StreamHolder
794 // ----------------------------
795
796// CREATORS
797inline
798Formatter_StreamHolder::Formatter_StreamHolder(bsl::streambuf *streamBuffer)
799: d_ownStream(bsl::in_place_t(), streamBuffer)
800, d_stream_p(&d_ownStream.value())
801{
802}
803
804inline
805Formatter_StreamHolder::Formatter_StreamHolder(bsl::ostream *stream)
806: d_ownStream()
807, d_stream_p(stream)
808{
809}
810
811// MANIPULATORS
812inline
814{
815 return d_stream_p;
816}
817
818// ACCESSORS
819inline
820const bsl::ostream *Formatter_StreamHolder::stream() const
821{
822 return d_stream_p;
823}
824
825 // ---------------------
826 // class Formatter_State
827 // ---------------------
828
829// PRIVATE MANIPULATORS
830inline
831Formatter_CompactImplState& Formatter_State::compact()
832{
833 BSLS_ASSERT(Mode::e_COMPACT == d_mode);
834
835 return d_compact.object();
836}
837
838inline
839Formatter_PrettyImplState& Formatter_State::pretty()
840{
841 BSLS_ASSERT(Mode::e_PRETTY == d_mode);
842
843 return d_pretty.object();
844}
845
846// PRIVATE ACCESSORS
847inline
848const Formatter_CompactImplState& Formatter_State::compact() const
849{
850 BSLS_ASSERT(Mode::e_COMPACT == d_mode);
851
852 return d_compact.object();
853}
854
855inline
856Formatter_Mode::Enum Formatter_State::mode() const
857{
858 return d_mode;
859}
860
861inline
862const Formatter_PrettyImplState& Formatter_State::pretty() const
863{
864 BSLS_ASSERT(Mode::e_PRETTY == d_mode);
865
866 return d_pretty.object();
867}
868
869// CREATORS
870inline
872: d_mode(Mode::e_COMPACT)
873, d_allocator()
874{
875 new (d_compact.buffer()) Compact();
876}
877
878inline
880: d_mode(Mode::e_COMPACT)
881, d_allocator(allocator)
882{
883 new (d_compact.buffer()) Compact();
884}
885
886// ACCESSORS
887inline
889{
890 return d_allocator;
891}
892
893 // ---------------
894 // class Formatter
895 // ---------------
896
897// MANIPULATORS
898template <class TYPE>
900 const TYPE& value,
901 int formattingMode)
902{
903 switch (d_state.mode()) {
904 case Mode::e_COMPACT: {
905 CompactUtil::addAttribute(*d_streamHolder.stream(),
906 &d_state.compact(),
907 name,
908 value,
909 formattingMode,
910 d_encoderOptions);
911 } break;
912 case Mode::e_PRETTY: {
913 PrettyUtil::addAttribute(*d_streamHolder.stream(),
914 &d_state.pretty(),
915 name,
916 value,
917 formattingMode,
918 d_encoderOptions);
919 } break;
920 }
921}
922
923inline
925{
926 switch (d_state.mode()) {
927 case Mode::e_COMPACT: {
928 CompactUtil::addBlankLine(*d_streamHolder.stream(),
929 &d_state.compact());
930 } break;
931 case Mode::e_PRETTY: {
932 PrettyUtil::addBlankLine(*d_streamHolder.stream(), &d_state.pretty());
933 } break;
934 }
935}
936
937template <class TYPE>
938void Formatter::addData(const TYPE& value, int formattingMode)
939{
940 switch (d_state.mode()) {
941 case Mode::e_COMPACT: {
942 CompactUtil::addData(*d_streamHolder.stream(),
943 &d_state.compact(),
944 value,
945 formattingMode,
946 d_encoderOptions);
947 } break;
948 case Mode::e_PRETTY: {
949 PrettyUtil::addData(*d_streamHolder.stream(),
950 &d_state.pretty(),
951 value,
952 formattingMode,
953 d_encoderOptions);
954 } break;
955 }
956}
957
958template <class TYPE>
960 const TYPE& value,
961 int formattingMode)
962{
963 switch (d_state.mode()) {
964 case Mode::e_COMPACT: {
965 CompactUtil::addElementAndData(*d_streamHolder.stream(),
966 &d_state.compact(),
967 name,
968 value,
969 formattingMode,
970 d_encoderOptions);
971 } break;
972 case Mode::e_PRETTY: {
973 PrettyUtil::addElementAndData(*d_streamHolder.stream(),
974 &d_state.pretty(),
975 name,
976 value,
977 formattingMode,
978 d_encoderOptions);
979 } break;
980 }
981}
982
983template <class TYPE>
984void Formatter::addListData(const TYPE& value, int formattingMode)
985{
986 switch (d_state.mode()) {
987 case Mode::e_COMPACT: {
988 CompactUtil::addListData(*d_streamHolder.stream(),
989 &d_state.compact(),
990 value,
991 formattingMode,
992 d_encoderOptions);
993 } break;
994 case Mode::e_PRETTY: {
995 PrettyUtil::addListData(*d_streamHolder.stream(),
996 &d_state.pretty(),
997 value,
998 formattingMode,
999 d_encoderOptions);
1000 } break;
1001 }
1002}
1003
1004inline
1006{
1007 switch (d_state.mode()) {
1008 case Mode::e_COMPACT: {
1009 CompactUtil::addNewline(*d_streamHolder.stream(), &d_state.compact());
1010 } break;
1011 case Mode::e_PRETTY: {
1012 PrettyUtil::addNewline(*d_streamHolder.stream(), &d_state.pretty());
1013 } break;
1014 }
1015}
1016
1017inline
1019{
1020 switch (d_state.mode()) {
1021 case Mode::e_COMPACT: {
1022 CompactUtil::flush(*d_streamHolder.stream(), &d_state.compact());
1023 } break;
1024 case Mode::e_PRETTY: {
1025 PrettyUtil::flush(*d_streamHolder.stream(), &d_state.pretty());
1026 } break;
1027 }
1028}
1029
1030inline
1032{
1033 switch (d_state.mode()) {
1034 case Mode::e_COMPACT: {
1035 CompactUtil::flush(*d_streamHolder.stream(), &d_state.compact());
1036 } break;
1037 case Mode::e_PRETTY: {
1038 PrettyUtil::flush(*d_streamHolder.stream(), &d_state.pretty());
1039 } break;
1040 }
1041
1042 return *d_streamHolder.stream();
1043}
1044
1045// ACCESSORS
1046inline
1048{
1049 return d_encoderOptions;
1050}
1051
1052inline
1054{
1055 int result = 0;
1056
1057 switch (d_state.mode()) {
1058 case Mode::e_COMPACT: {
1059 result = d_state.compact().indentLevel();
1060 } break;
1061 case Mode::e_PRETTY: {
1062 result = d_state.pretty().indentLevel();
1063 } break;
1064 }
1065
1066 return result;
1067}
1068
1069inline
1071{
1072 int result = 0;
1073
1074 switch (d_state.mode()) {
1075 case Mode::e_COMPACT: {
1076 result = d_state.compact().column();
1077 } break;
1078 case Mode::e_PRETTY: {
1079 result = d_state.pretty().column();
1080 } break;
1081 }
1082
1083 return result;
1084}
1085
1086inline
1088{
1089 int result = 0;
1090
1091 switch (d_state.mode()) {
1092 case Mode::e_COMPACT: {
1093 result = d_state.compact().spacesPerLevel();
1094 } break;
1095 case Mode::e_PRETTY: {
1096 result = d_state.pretty().spacesPerLevel();
1097 } break;
1098 }
1099
1100 return result;
1101}
1102
1103inline
1105{
1106 return d_streamHolder.stream()->good() ? 0 : -1;
1107}
1108
1109inline
1111{
1112 int result = 0;
1113
1114 switch (d_state.mode()) {
1115 case Mode::e_COMPACT: {
1116 result = State::k_COMPACT_MODE_WRAP_COLUMN;
1117 } break;
1118 case Mode::e_PRETTY: {
1119 result = d_state.pretty().wrapColumn();
1120 } break;
1121 }
1122
1123 return result;
1124}
1125
1126} // close package namespace
1127
1128
1129#endif
1130
1131// ----------------------------------------------------------------------------
1132// Copyright 2015 Bloomberg Finance L.P.
1133//
1134// Licensed under the Apache License, Version 2.0 (the "License");
1135// you may not use this file except in compliance with the License.
1136// You may obtain a copy of the License at
1137//
1138// http://www.apache.org/licenses/LICENSE-2.0
1139//
1140// Unless required by applicable law or agreed to in writing, software
1141// distributed under the License is distributed on an "AS IS" BASIS,
1142// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1143// See the License for the specific language governing permissions and
1144// limitations under the License.
1145// ----------------------------- END-OF-FILE ----------------------------------
1146
1147/** @} */
1148/** @} */
1149/** @} */
Definition balxml_encoderoptions.h:88
Definition balxml_formatter_compactimpl.h:160
int & indentLevel()
Definition balxml_formatter_compactimpl.h:555
int & column()
Definition balxml_formatter_compactimpl.h:543
int & spacesPerLevel()
Definition balxml_formatter_compactimpl.h:567
Definition balxml_formatter_prettyimpl.h:222
int & column()
Definition balxml_formatter_prettyimpl.h:745
int & wrapColumn()
Definition balxml_formatter_prettyimpl.h:776
int & spacesPerLevel()
Definition balxml_formatter_prettyimpl.h:770
int & indentLevel()
Definition balxml_formatter_prettyimpl.h:764
Definition balxml_formatter.h:390
BSLMF_NESTED_TRAIT_DECLARATION(Formatter_State, bslma::UsesBslmaAllocator)
~Formatter_State()
Destroy this object.
Formatter_State(const Formatter_State &original, const allocator_type &allocator=allocator_type())
bsls::ObjectBuffer< Pretty > d_pretty
Definition balxml_formatter.h:409
Formatter_State & operator=(const Formatter_State &rhs)
bsl::allocator< char > allocator_type
Definition balxml_formatter.h:394
Formatter_Mode Mode
Definition balxml_formatter.h:395
Formatter_State()
Definition balxml_formatter.h:871
bsls::ObjectBuffer< Compact > d_compact
Definition balxml_formatter.h:408
allocator_type get_allocator() const
Return the allocator associated with this object.
Definition balxml_formatter.h:888
Definition balxml_formatter.h:324
bsl::ostream * stream()
Definition balxml_formatter.h:813
Definition balxml_formatter.h:511
int addValidComment(const bsl::string_view &comment, bool forceNewline=true, bool omitEnclosingWhitespace=false)
static const WhitespaceType e_WORDWRAP
Definition balxml_formatter.h:531
Formatter(bsl::ostream &output, const EncoderOptions &encoderOptions, int indentLevel=0, int spacesPerLevel=4, int wrapColumn=80, bslma::Allocator *basicAllocator=0)
int indentLevel() const
Return the current level of indentation.
Definition balxml_formatter.h:1053
void openElement(const bsl::string_view &name, WhitespaceType whitespaceMode=e_PRESERVE_WHITESPACE)
static const WhitespaceType BAEXML_NEWLINE_INDENT
Definition balxml_formatter.h:545
FormatterWhitespaceType::Enum WhitespaceType
Definition balxml_formatter.h:518
int outputColumn() const
Definition balxml_formatter.h:1070
int status() const
Definition balxml_formatter.h:1104
const EncoderOptions & encoderOptions() const
Return the encoder options being used.
Definition balxml_formatter.h:1047
Formatter(bsl::ostream &output, int indentLevel=0, int spacesPerLevel=4, int wrapColumn=80, bslma::Allocator *basicAllocator=0)
Formatter(bsl::streambuf *output, const EncoderOptions &encoderOptions, int indentLevel=0, int spacesPerLevel=4, int wrapColumn=80, bslma::Allocator *basicAllocator=0)
void addHeader(const bsl::string_view &encoding="UTF-8")
void addElementAndData(const bsl::string_view &name, const TYPE &value, int formattingMode=0)
Definition balxml_formatter.h:959
void addNewline()
Definition balxml_formatter.h:1005
bsl::ostream & rawOutputStream()
Definition balxml_formatter.h:1031
void addListData(const TYPE &value, int formattingMode=0)
Definition balxml_formatter.h:984
void closeElement(const bsl::string_view &name)
void addData(const TYPE &value, int formattingMode=0)
Definition balxml_formatter.h:938
void addBlankLine()
Definition balxml_formatter.h:924
int wrapColumn() const
Return the line width where line-wrapping takes place.
Definition balxml_formatter.h:1110
static const WhitespaceType e_WORDWRAP_INDENT
Definition balxml_formatter.h:535
static const WhitespaceType e_PRESERVE_WHITESPACE
Definition balxml_formatter.h:527
void addAttribute(const bsl::string_view &name, const TYPE &value, int formattingMode=0)
Definition balxml_formatter.h:899
void flush()
Definition balxml_formatter.h:1018
int spacesPerLevel() const
Return the number of spaces per indentation level.
Definition balxml_formatter.h:1087
static const WhitespaceType e_NEWLINE_INDENT
Definition balxml_formatter.h:540
Formatter(bsl::streambuf *output, int indentLevel=0, int spacesPerLevel=4, int wrapColumn=80, bslma::Allocator *basicAllocator=0)
void addComment(const bsl::string_view &comment, bool forceNewline=true)
Definition bslma_bslallocator.h:580
Definition bslstl_stringview.h:441
Definition bslstl_optional.h:1861
Definition bslma_allocator.h:457
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:609
Definition balxml_base64parser.h:150
Definition bdlb_printmethods.h:283
Definition balxml_formatterwhitespacetype.h:68
Enum
Definition balxml_formatterwhitespacetype.h:71
@ e_NEWLINE_INDENT
Definition balxml_formatterwhitespacetype.h:81
@ e_WORDWRAP_INDENT
Definition balxml_formatterwhitespacetype.h:77
@ e_WORDWRAP
Definition balxml_formatterwhitespacetype.h:74
@ e_PRESERVE_WHITESPACE
Definition balxml_formatterwhitespacetype.h:72
Definition balxml_formatter_compactimpl.h:267
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_compactimpl.h:657
static bsl::ostream & addAttribute(bsl::ostream &stream, State *state, const bsl::string_view &name, const VALUE_TYPE &value, int valueFormattingMode=0, const EncoderOptions &encoderOptions=EncoderOptions())
Definition balxml_formatter_compactimpl.h:610
static bsl::ostream & addListData(bsl::ostream &stream, State *state, const VALUE_TYPE &value, int formattingMode=0, const EncoderOptions &encoderOptions=EncoderOptions())
Definition balxml_formatter_compactimpl.h:673
static bsl::ostream & addNewline(bsl::ostream &stream, State *state)
static bsl::ostream & flush(bsl::ostream &stream, State *state)
static bsl::ostream & addData(bsl::ostream &stream, State *state, const VALUE_TYPE &value, int formattingMode=0, const EncoderOptions &encoderOptions=EncoderOptions())
Definition balxml_formatter_compactimpl.h:631
static bsl::ostream & addBlankLine(bsl::ostream &stream, State *state)
Definition balxml_formatter.h:371
Enum
Definition balxml_formatter.h:374
@ e_PRETTY
Definition balxml_formatter.h:376
@ e_COMPACT
Definition balxml_formatter.h:375
Definition balxml_formatter_prettyimpl.h:370
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:897
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:832
static bsl::ostream & flush(bsl::ostream &stream, State *state)
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:859
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:882
static bsl::ostream & addBlankLine(bsl::ostream &stream, State *state)
Definition bslma_usesbslmaallocator.h:343
Definition bsls_objectbuffer.h:276