| // Copyright 2016 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "tools/gn/xml_element_writer.h" | |
| #include <memory> | |
| XmlAttributes::XmlAttributes() = default; | |
| XmlAttributes::XmlAttributes(const base::StringPiece& attr_key, | |
| const base::StringPiece& attr_value) { | |
| add(attr_key, attr_value); | |
| } | |
| XmlAttributes& XmlAttributes::add(const base::StringPiece& attr_key, | |
| const base::StringPiece& attr_value) { | |
| push_back(std::make_pair(attr_key, attr_value)); | |
| return *this; | |
| } | |
| XmlElementWriter::XmlElementWriter(std::ostream& out, | |
| const std::string& tag, | |
| const XmlAttributes& attributes) | |
| : XmlElementWriter(out, tag, attributes, 0) {} | |
| XmlElementWriter::XmlElementWriter(std::ostream& out, | |
| const std::string& tag, | |
| const XmlAttributes& attributes, | |
| int indent) | |
| : out_(out), | |
| tag_(tag), | |
| indent_(indent), | |
| opening_tag_finished_(false), | |
| one_line_(true) { | |
| out << std::string(indent, ' ') << '<' << tag; | |
| for (auto attribute : attributes) | |
| out << ' ' << attribute.first << "=\"" << attribute.second << '"'; | |
| } | |
| XmlElementWriter::~XmlElementWriter() { | |
| if (!opening_tag_finished_) { | |
| // The XML spec does not require a space before the closing slash. However, | |
| // Eclipse is unable to parse XML settings files if there is no space. | |
| out_ << " />" << std::endl; | |
| } else { | |
| if (!one_line_) | |
| out_ << std::string(indent_, ' '); | |
| out_ << "</" << tag_ << '>' << std::endl; | |
| } | |
| } | |
| void XmlElementWriter::Text(const base::StringPiece& content) { | |
| StartContent(false); | |
| out_ << content; | |
| } | |
| std::unique_ptr<XmlElementWriter> XmlElementWriter::SubElement( | |
| const std::string& tag) { | |
| return SubElement(tag, XmlAttributes()); | |
| } | |
| std::unique_ptr<XmlElementWriter> XmlElementWriter::SubElement( | |
| const std::string& tag, | |
| const XmlAttributes& attributes) { | |
| StartContent(true); | |
| return std::make_unique<XmlElementWriter>(out_, tag, attributes, indent_ + 2); | |
| } | |
| std::ostream& XmlElementWriter::StartContent(bool start_new_line) { | |
| if (!opening_tag_finished_) { | |
| out_ << '>'; | |
| opening_tag_finished_ = true; | |
| if (start_new_line && one_line_) { | |
| out_ << std::endl; | |
| one_line_ = false; | |
| } | |
| } | |
| return out_; | |
| } | |
| std::string XmlEscape(const std::string& value) { | |
| std::string result; | |
| for (char c : value) { | |
| switch (c) { | |
| case '\n': | |
| result += " "; | |
| break; | |
| case '\r': | |
| result += " "; | |
| break; | |
| case '\t': | |
| result += "	"; | |
| break; | |
| case '"': | |
| result += """; | |
| break; | |
| case '<': | |
| result += "<"; | |
| break; | |
| case '>': | |
| result += ">"; | |
| break; | |
| case '&': | |
| result += "&"; | |
| break; | |
| default: | |
| result += c; | |
| } | |
| } | |
| return result; | |
| } |