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