Specialize stream output for shared_ptr<void>
[platform/upstream/libzypp.git] / zypp / base / Xml.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/base/Xml.h
10  *
11 */
12 #ifndef ZYPP_BASE_XML_H
13 #define ZYPP_BASE_XML_H
14
15 #include <iosfwd>
16 #include <string>
17 #include <vector>
18 #include <list>
19 #include <set>
20 #include <map>
21
22 #include "zypp/base/Easy.h"
23 #include "zypp/base/String.h"
24 #include "zypp/parser/xml/XmlEscape.h"
25
26 ///////////////////////////////////////////////////////////////////
27 namespace zypp
28 {
29   ///////////////////////////////////////////////////////////////////
30   namespace xmlout
31   {
32     using xml::escape;
33     using xml::unescape;
34
35     /** \relates NodeAttr NODE ATTRIBUTE representation of types [str::asString] */
36     template <class _Tp>
37     std::string asXmlNodeAttr( const _Tp & val_r )
38     { return str::asString( val_r ); }
39
40     ///////////////////////////////////////////////////////////////////
41     /// \class NodeAttr
42     /// \brief (Key, Value) string pair of XML node attributes
43     struct NodeAttr : public std::pair<std::string,std::string>
44     {
45       typedef std::pair<std::string,std::string> Pair;
46
47       template <typename _Type>
48       NodeAttr( std::string key_r, const _Type & val_r )
49       : Pair( std::move(key_r), asXmlNodeAttr(val_r) )
50       {}
51
52       NodeAttr( std::string key_r, std::string val_r )
53       : Pair( std::move(key_r), std::move(val_r) )
54       {}
55     };
56     ///////////////////////////////////////////////////////////////////
57
58     ///////////////////////////////////////////////////////////////////
59     /// \class Node
60     /// \brief RAII writing a nodes start/end tag
61     /// \code
62     /// {
63     ///   Node node( std::cout, "node", { "attr", "val" } ); // <node attr="val">
64     ///   *node << "write nodes body...."
65     /// }                                                    // </node>
66     /// \endcode
67     /// \note If the \ref optionalContent flag is passed to the \c ctor, the start
68     /// node is kept open, until the first call to \ref operator*. The start node
69     /// is closed before returning the stream.
70     /// \code
71     /// {
72     ///   Node node( std::cout, "node", Node::optionalContent, { "attr", "val" } );
73     ///                                                      // <node attr="val"
74     /// }                                                    // />
75     /// {
76     ///   Node node( std::cout, "node", Node::optionalContent, { "attr", "val" } );
77     ///                                                      // <node attr="val"
78     ///   *node << "write nodes body...."                    // />write nodes body...
79     /// }                                                    // </node>
80     /// \endcode
81     ///
82     struct Node
83     {
84       NON_COPYABLE_BUT_MOVE( Node );
85       typedef NodeAttr Attr;
86
87       struct OptionalContentType {};    ///< Ctor arg type
88       static constexpr OptionalContentType optionalContent = OptionalContentType();
89
90       /** Ctor taking nodename and attribute list */
91       Node( std::ostream & out_r, std::string name_r, const std::initializer_list<Attr> & attrs_r = {} )
92       : _out( out_r ), _name( std::move(name_r) ), _hasContent( true )
93       { printStart( attrs_r ); }
94
95       /** Convenience ctor for one attribute pair */
96       Node( std::ostream & out_r, std::string name_r, Attr attr_r )
97       : Node( out_r, std::move(name_r), { attr_r } )
98       {}
99
100       /** Optional content ctor taking nodename and attribute list */
101       Node( std::ostream & out_r, std::string name_r, OptionalContentType, const std::initializer_list<Attr> & attrs_r = {} )
102       : _out( out_r ), _name( std::move(name_r) ), _hasContent( false )
103       { printStart( attrs_r ); }
104
105       /** Optional content Convenience ctor for one attribute pair */
106       Node( std::ostream & out_r, std::string name_r, OptionalContentType, Attr attr_r )
107       : Node( out_r, std::move(name_r), optionalContent, { attr_r } )
108       {}
109
110       /** Dtor wrting end tag */
111       ~Node()
112       {
113         if ( ! _name.empty() )
114         {
115           if ( _hasContent )
116             _out << "</" << _name << ">";
117           else
118             _out << "/>";
119         }
120       }
121
122       /** Return the output stream */
123       std::ostream & operator*()
124       {
125         if ( ! _hasContent )
126         {
127           _hasContent = true;
128           if ( ! _name.empty() )
129             _out << ">";
130         }
131         return _out;
132       }
133
134     private:
135       void printStart( const std::initializer_list<Attr> & attrs_r )
136       {
137         if ( ! _name.empty() )
138         {
139           _out << "<" << _name;
140           for ( const auto & pair : attrs_r )
141             _out << " " << pair.first << "=\"" << xml::escape( pair.second ) << "\"";
142           if ( _hasContent )
143             _out << ">";
144         }
145       }
146     private:
147       std::ostream & _out;
148       std::string _name;
149       bool _hasContent;
150     };
151     ///////////////////////////////////////////////////////////////////
152
153     /** \relates Node Write a leaf node without PCDATA
154      * \code
155      * <node attr="val"/>
156      * \endcode
157      */
158     inline std::ostream & node( std::ostream & out_r, const std::string & name_r, const std::initializer_list<Node::Attr> & attrs_r = {} )
159     {
160       Node( out_r, name_r, Node::optionalContent, attrs_r );
161       return out_r;
162     }
163     /** \overload for one attribute pair */
164     inline std::ostream & node( std::ostream & out_r, const std::string & name_r, Node::Attr attr_r )
165     { return node( out_r, name_r, { attr_r } ); }
166
167   } // namespace xmlout
168   ///////////////////////////////////////////////////////////////////
169 } // namespace zypp
170 ///////////////////////////////////////////////////////////////////
171 #endif // ZYPP_BASE_XML_H