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 #include "gn/xml_element_writer.h"
6
7 #include <memory>
8
9 XmlAttributes::XmlAttributes() = default;
10
XmlAttributes(std::string_view attr_key,std::string_view attr_value)11 XmlAttributes::XmlAttributes(std::string_view attr_key,
12 std::string_view attr_value) {
13 add(attr_key, attr_value);
14 }
15
add(std::string_view attr_key,std::string_view attr_value)16 XmlAttributes& XmlAttributes::add(std::string_view attr_key,
17 std::string_view attr_value) {
18 push_back(std::make_pair(attr_key, attr_value));
19 return *this;
20 }
21
XmlElementWriter(std::ostream & out,const std::string & tag,const XmlAttributes & attributes)22 XmlElementWriter::XmlElementWriter(std::ostream& out,
23 const std::string& tag,
24 const XmlAttributes& attributes)
25 : XmlElementWriter(out, tag, attributes, 0) {}
26
XmlElementWriter(std::ostream & out,const std::string & tag,const XmlAttributes & attributes,int indent)27 XmlElementWriter::XmlElementWriter(std::ostream& out,
28 const std::string& tag,
29 const XmlAttributes& attributes,
30 int indent)
31 : out_(out),
32 tag_(tag),
33 indent_(indent),
34 opening_tag_finished_(false),
35 one_line_(true) {
36 out << std::string(indent, ' ') << '<' << tag;
37 for (auto attribute : attributes)
38 out << ' ' << attribute.first << "=\"" << attribute.second << '"';
39 }
40
~XmlElementWriter()41 XmlElementWriter::~XmlElementWriter() {
42 if (!opening_tag_finished_) {
43 // The XML spec does not require a space before the closing slash. However,
44 // Eclipse is unable to parse XML settings files if there is no space.
45 out_ << " />" << std::endl;
46 } else {
47 if (!one_line_)
48 out_ << std::string(indent_, ' ');
49 out_ << "</" << tag_ << '>' << std::endl;
50 }
51 }
52
Text(std::string_view content)53 void XmlElementWriter::Text(std::string_view content) {
54 StartContent(false);
55 out_ << content;
56 }
57
SubElement(const std::string & tag)58 std::unique_ptr<XmlElementWriter> XmlElementWriter::SubElement(
59 const std::string& tag) {
60 return SubElement(tag, XmlAttributes());
61 }
62
SubElement(const std::string & tag,const XmlAttributes & attributes)63 std::unique_ptr<XmlElementWriter> XmlElementWriter::SubElement(
64 const std::string& tag,
65 const XmlAttributes& attributes) {
66 StartContent(true);
67 return std::make_unique<XmlElementWriter>(out_, tag, attributes, indent_ + 2);
68 }
69
StartContent(bool start_new_line)70 std::ostream& XmlElementWriter::StartContent(bool start_new_line) {
71 if (!opening_tag_finished_) {
72 out_ << '>';
73 opening_tag_finished_ = true;
74
75 if (start_new_line && one_line_) {
76 out_ << std::endl;
77 one_line_ = false;
78 }
79 }
80
81 return out_;
82 }
83
XmlEscape(const std::string & value)84 std::string XmlEscape(const std::string& value) {
85 std::string result;
86 for (char c : value) {
87 switch (c) {
88 case '\n':
89 result += " ";
90 break;
91 case '\r':
92 result += " ";
93 break;
94 case '\t':
95 result += "	";
96 break;
97 case '"':
98 result += """;
99 break;
100 case '<':
101 result += "<";
102 break;
103 case '>':
104 result += ">";
105 break;
106 case '&':
107 result += "&";
108 break;
109 default:
110 result += c;
111 }
112 }
113 return result;
114 }
115