| // 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; |
| } |