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