• 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 #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