Imported Upstream version 14.45.0
[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 [asString] */
36     template <class _Tp>
37     std::string asXmlNodeAttr( const _Tp & val_r )
38     { return 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     /// \note If the nodename is empty or starts with an \c !, a comment is written.
83     ///
84     struct Node
85     {
86       NON_COPYABLE_BUT_MOVE( Node );
87       typedef NodeAttr Attr;
88
89       struct OptionalContentType {};    ///< Ctor arg type
90       static constexpr OptionalContentType optionalContent = OptionalContentType();
91
92       /** Ctor taking nodename and attribute list */
93       Node( std::ostream & out_r, std::string name_r, const std::initializer_list<Attr> & attrs_r = {} )
94       : _out( out_r ), _name( std::move(name_r) ), _hasContent( true )
95       { printStart( attrs_r ); }
96
97       /** Convenience ctor for one attribute pair */
98       Node( std::ostream & out_r, std::string name_r, Attr attr_r )
99       : Node( out_r, std::move(name_r), { attr_r } )
100       {}
101
102       /** Optional content ctor taking nodename and attribute list */
103       Node( std::ostream & out_r, std::string name_r, OptionalContentType, const std::initializer_list<Attr> & attrs_r = {} )
104       : _out( out_r ), _name( std::move(name_r) ), _hasContent( false )
105       { printStart( attrs_r ); }
106
107       /** Optional content Convenience ctor for one attribute pair */
108       Node( std::ostream & out_r, std::string name_r, OptionalContentType, Attr attr_r )
109       : Node( out_r, std::move(name_r), optionalContent, { attr_r } )
110       {}
111
112       /** Dtor wrting end tag */
113       ~Node()
114       {
115         if ( _name.empty() )
116           _out << "-->";
117         else
118         {
119           if ( _hasContent )
120             _out << "</" << _name << ">";
121           else
122             _out << "/>";
123         }
124       }
125
126       /** Return the output stream */
127       std::ostream & operator*()
128       {
129         if ( ! _hasContent )
130         {
131           _hasContent = true;
132           if ( _name.empty() )
133             _out << "|";
134           else
135             _out << ">";
136         }
137         return _out;
138       }
139
140     private:
141       void printStart( const std::initializer_list<Attr> & attrs_r )
142       {
143         if ( _name.empty() || _name[0] == '!' )
144         {
145           _out << "<!--" << _name;
146           _name.clear();
147         }
148         else
149           _out << "<" << _name;
150
151         for ( const auto & pair : attrs_r )
152           _out << " " << pair.first << "=\"" << xml::escape( pair.second ) << "\"";
153
154         if ( ! _name.empty() && _hasContent )
155           _out << ">";
156       }
157     private:
158       std::ostream & _out;
159       std::string _name;
160       bool _hasContent;
161     };
162     ///////////////////////////////////////////////////////////////////
163
164     /** \relates Node Write a leaf node without PCDATA
165      * \code
166      * <node attr="val"/>
167      * \endcode
168      */
169     inline std::ostream & node( std::ostream & out_r, const std::string & name_r, const std::initializer_list<Node::Attr> & attrs_r = {} )
170     {
171       Node( out_r, name_r, Node::optionalContent, attrs_r );
172       return out_r;
173     }
174     /** \overload for one attribute pair */
175     inline std::ostream & node( std::ostream & out_r, const std::string & name_r, Node::Attr attr_r )
176     { return node( out_r, name_r, { attr_r } ); }
177
178   } // namespace xmlout
179   ///////////////////////////////////////////////////////////////////
180
181   /// \name Default dumpAsXmlOn based on asString.
182   ///
183   //@{
184   template <class _Tp>
185   inline std::ostream & dumpAsXmlOn( std::ostream & str, const _Tp & obj, const std::string & name_r )
186   {
187     xmlout::Node guard( str, name_r, xmlout::Node::optionalContent );
188     const std::string & content( asString( obj ) );
189     if ( ! content.empty() ) *guard << content;
190     return str;
191   }
192   //@}
193   //
194 } // namespace zypp
195 ///////////////////////////////////////////////////////////////////
196 #endif // ZYPP_BASE_XML_H