blob: 1bf9b469b430056d5eb3993e93db0d4ce9ad6c13 [file] [log] [blame]
// 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.
#ifndef TOOLS_GN_XML_ELEMENT_WRITER_H_
#define TOOLS_GN_XML_ELEMENT_WRITER_H_
#include <memory>
#include <ostream>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
// Vector of XML attribute key-value pairs.
class XmlAttributes
: public std::vector<std::pair<std::string_view, std::string_view>> {
public:
XmlAttributes();
XmlAttributes(std::string_view attr_key, std::string_view attr_value);
XmlAttributes& add(std::string_view attr_key, std::string_view attr_value);
};
// Helper class for writing XML elements. New XML element is started in
// XmlElementWriter constructor and ended in its destructor. XmlElementWriter
// handles XML file formatting in order to produce human-readable document.
class XmlElementWriter {
public:
// Starts new XML element. This constructor adds no indentation and is
// designed for XML root element.
XmlElementWriter(std::ostream& out,
const std::string& tag,
const XmlAttributes& attributes);
// Starts new XML element with specified indentation.
XmlElementWriter(std::ostream& out,
const std::string& tag,
const XmlAttributes& attributes,
int indent);
// Starts new XML element with specified indentation. Specialized constructor
// that allows writing XML element with single attribute without copying
// attribute value.
template <class Writer>
XmlElementWriter(std::ostream& out,
const std::string& tag,
const std::string& attribute_name,
const Writer& attribute_value_writer,
int indent);
// Ends XML element. All sub-elements should be ended at this point.
~XmlElementWriter();
// Writes arbitrary XML element text.
void Text(std::string_view content);
// Starts new XML sub-element. Caller must ensure that parent element outlives
// its children.
std::unique_ptr<XmlElementWriter> SubElement(const std::string& tag);
std::unique_ptr<XmlElementWriter> SubElement(const std::string& tag,
const XmlAttributes& attributes);
template <class Writer>
std::unique_ptr<XmlElementWriter> SubElement(
const std::string& tag,
const std::string& attribute_name,
const Writer& attribute_value_writer);
// Finishes opening tag if it isn't finished yet and optionally starts new
// document line. Returns the stream where XML element content can be written.
// This is an alternative to Text() and SubElement() methods.
std::ostream& StartContent(bool start_new_line);
private:
// Output stream. XmlElementWriter objects for XML element and its
// sub-elements share the same output stream.
std::ostream& out_;
// XML element tag name.
std::string tag_;
// XML element indentation in the document.
int indent_;
// Flag indicating if opening tag is finished with '>' character already.
bool opening_tag_finished_;
// Flag indicating if XML element should be written in one document line.
bool one_line_;
XmlElementWriter(const XmlElementWriter&) = delete;
XmlElementWriter& operator=(const XmlElementWriter&) = delete;
};
template <class Writer>
XmlElementWriter::XmlElementWriter(std::ostream& out,
const std::string& tag,
const std::string& attribute_name,
const Writer& attribute_value_writer,
int indent)
: out_(out),
tag_(tag),
indent_(indent),
opening_tag_finished_(false),
one_line_(true) {
out << std::string(indent, ' ') << '<' << tag;
out << ' ' << attribute_name << "=\"";
attribute_value_writer(out);
out << '\"';
}
template <class Writer>
std::unique_ptr<XmlElementWriter> XmlElementWriter::SubElement(
const std::string& tag,
const std::string& attribute_name,
const Writer& attribute_value_writer) {
StartContent(true);
return std::make_unique<XmlElementWriter>(
out_, tag, attribute_name, attribute_value_writer, indent_ + 2);
}
std::string XmlEscape(const std::string& value);
#endif // TOOLS_GN_XML_ELEMENT_WRITER_H_