• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef TOOLS_GN_XML_ELEMENT_WRITER_H_
6 #define TOOLS_GN_XML_ELEMENT_WRITER_H_
7 
8 #include <memory>
9 #include <ostream>
10 #include <string>
11 #include <string_view>
12 #include <utility>
13 #include <vector>
14 
15 // Vector of XML attribute key-value pairs.
16 class XmlAttributes
17     : public std::vector<std::pair<std::string_view, std::string_view>> {
18  public:
19   XmlAttributes();
20   XmlAttributes(std::string_view attr_key, std::string_view attr_value);
21 
22   XmlAttributes& add(std::string_view attr_key, std::string_view attr_value);
23 };
24 
25 // Helper class for writing XML elements. New XML element is started in
26 // XmlElementWriter constructor and ended in its destructor. XmlElementWriter
27 // handles XML file formatting in order to produce human-readable document.
28 class XmlElementWriter {
29  public:
30   // Starts new XML element. This constructor adds no indentation and is
31   // designed for XML root element.
32   XmlElementWriter(std::ostream& out,
33                    const std::string& tag,
34                    const XmlAttributes& attributes);
35   // Starts new XML element with specified indentation.
36   XmlElementWriter(std::ostream& out,
37                    const std::string& tag,
38                    const XmlAttributes& attributes,
39                    int indent);
40   // Starts new XML element with specified indentation. Specialized constructor
41   // that allows writing XML element with single attribute without copying
42   // attribute value.
43   template <class Writer>
44   XmlElementWriter(std::ostream& out,
45                    const std::string& tag,
46                    const std::string& attribute_name,
47                    const Writer& attribute_value_writer,
48                    int indent);
49   // Ends XML element. All sub-elements should be ended at this point.
50   ~XmlElementWriter();
51 
52   // Writes arbitrary XML element text.
53   void Text(std::string_view content);
54 
55   // Starts new XML sub-element. Caller must ensure that parent element outlives
56   // its children.
57   std::unique_ptr<XmlElementWriter> SubElement(const std::string& tag);
58   std::unique_ptr<XmlElementWriter> SubElement(const std::string& tag,
59                                                const XmlAttributes& attributes);
60   template <class Writer>
61   std::unique_ptr<XmlElementWriter> SubElement(
62       const std::string& tag,
63       const std::string& attribute_name,
64       const Writer& attribute_value_writer);
65 
66   // Finishes opening tag if it isn't finished yet and optionally starts new
67   // document line. Returns the stream where XML element content can be written.
68   // This is an alternative to Text() and SubElement() methods.
69   std::ostream& StartContent(bool start_new_line);
70 
71  private:
72   // Output stream. XmlElementWriter objects for XML element and its
73   // sub-elements share the same output stream.
74   std::ostream& out_;
75 
76   // XML element tag name.
77   std::string tag_;
78 
79   // XML element indentation in the document.
80   int indent_;
81 
82   // Flag indicating if opening tag is finished with '>' character already.
83   bool opening_tag_finished_;
84 
85   // Flag indicating if XML element should be written in one document line.
86   bool one_line_;
87 
88   XmlElementWriter(const XmlElementWriter&) = delete;
89   XmlElementWriter& operator=(const XmlElementWriter&) = delete;
90 };
91 
92 template <class Writer>
XmlElementWriter(std::ostream & out,const std::string & tag,const std::string & attribute_name,const Writer & attribute_value_writer,int indent)93 XmlElementWriter::XmlElementWriter(std::ostream& out,
94                                    const std::string& tag,
95                                    const std::string& attribute_name,
96                                    const Writer& attribute_value_writer,
97                                    int indent)
98     : out_(out),
99       tag_(tag),
100       indent_(indent),
101       opening_tag_finished_(false),
102       one_line_(true) {
103   out << std::string(indent, ' ') << '<' << tag;
104   out << ' ' << attribute_name << "=\"";
105   attribute_value_writer(out);
106   out << '\"';
107 }
108 
109 template <class Writer>
SubElement(const std::string & tag,const std::string & attribute_name,const Writer & attribute_value_writer)110 std::unique_ptr<XmlElementWriter> XmlElementWriter::SubElement(
111     const std::string& tag,
112     const std::string& attribute_name,
113     const Writer& attribute_value_writer) {
114   StartContent(true);
115   return std::make_unique<XmlElementWriter>(
116       out_, tag, attribute_name, attribute_value_writer, indent_ + 2);
117 }
118 
119 std::string XmlEscape(const std::string& value);
120 
121 #endif  // TOOLS_GN_XML_ELEMENT_WRITER_H_
122