1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/base/Xml.h
12 #ifndef ZYPP_BASE_XML_H
13 #define ZYPP_BASE_XML_H
22 #include "zypp/base/Easy.h"
23 #include "zypp/base/String.h"
24 #include "zypp/parser/xml/XmlEscape.h"
26 ///////////////////////////////////////////////////////////////////
29 ///////////////////////////////////////////////////////////////////
35 /** \relates NodeAttr NODE ATTRIBUTE representation of types [asString] */
37 std::string asXmlNodeAttr( const Tp & val_r )
38 { return asString( val_r ); }
40 ///////////////////////////////////////////////////////////////////
42 /// \brief (Key, Value) string pair of XML node attributes
43 struct NodeAttr : public std::pair<std::string,std::string>
45 typedef std::pair<std::string,std::string> Pair;
47 template <typename Tp>
48 NodeAttr( std::string key_r, const Tp & val_r )
49 : Pair( std::move(key_r), asXmlNodeAttr(val_r) )
52 NodeAttr( std::string key_r, std::string val_r )
53 : Pair( std::move(key_r), std::move(val_r) )
56 ///////////////////////////////////////////////////////////////////
58 ///////////////////////////////////////////////////////////////////
60 /// \brief RAII writing a nodes start/end tag
63 /// Node node( std::cout, "node", { "attr", "val" } ); // <node attr="val">
64 /// *node << "write nodes body...."
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.
72 /// Node node( std::cout, "node", Node::optionalContent, { "attr", "val" } );
73 /// // <node attr="val"
76 /// Node node( std::cout, "node", Node::optionalContent, { "attr", "val" } );
77 /// // <node attr="val"
78 /// *node << "write nodes body...." // />write nodes body...
82 /// \note If the nodename is empty or starts with an \c !, a comment is written.
86 NON_COPYABLE_BUT_MOVE( Node );
87 typedef NodeAttr Attr;
89 struct OptionalContentType {}; ///< Ctor arg type
90 static constexpr OptionalContentType optionalContent = OptionalContentType();
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 ); }
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 } )
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 ); }
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 } )
112 /** Dtor wrting end tag */
120 _out << "</" << _name << ">";
126 /** Exception type thrown if attributes are added to a closed start node. */
127 struct HasContentException{};
129 /** Add additional attributes (requires OptionalContentType)
130 * \throw HasContentException If start node is already closed
132 Node & addAttr( const std::initializer_list<Attr> & attrs_r = {} )
135 throw HasContentException();
136 printAttr( attrs_r );
140 /** \overload for one */
141 Node & addAttr( const Attr & attr_r )
142 { return addAttr( { attr_r } ); }
145 /** Return the output stream */
146 std::ostream & operator*()
160 void printStart( const std::initializer_list<Attr> & attrs_r )
162 if ( _name.empty() || _name[0] == '!' )
164 _out << "<!--" << _name;
165 _name.clear(); // a comment
168 _out << "<" << _name;
170 printAttr( attrs_r );
172 if ( !isComment() && _hasContent )
176 void printAttr( const std::initializer_list<Attr> & attrs_r )
178 for ( const auto & pair : attrs_r )
179 _out << " " << pair.first << "=\"" << xml::escape( pair.second ) << "\"";
182 bool isComment() const
183 { return _name.empty(); }
190 ///////////////////////////////////////////////////////////////////
192 /** \relates Node Write a leaf node without PCDATA
197 inline std::ostream & node( std::ostream & out_r, const std::string & name_r, const std::initializer_list<Node::Attr> & attrs_r = {} )
199 Node( out_r, name_r, Node::optionalContent, attrs_r );
202 /** \overload for one attribute pair */
203 inline std::ostream & node( std::ostream & out_r, const std::string & name_r, Node::Attr attr_r )
204 { return node( out_r, name_r, { attr_r } ); }
206 } // namespace xmlout
207 ///////////////////////////////////////////////////////////////////
209 /// \name Default dumpAsXmlOn based on asString.
213 inline std::ostream & dumpAsXmlOn( std::ostream & str, const Tp & obj, const std::string & name_r )
215 xmlout::Node guard( str, name_r, xmlout::Node::optionalContent );
216 const std::string & content( asString( obj ) );
217 if ( ! content.empty() ) *guard << xml::escape( content );
223 ///////////////////////////////////////////////////////////////////
224 #endif // ZYPP_BASE_XML_H