diff options
author | Daniel Pfeifer <daniel@pfeifer-mail.de> | 2015-05-23 21:04:50 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2015-05-26 15:09:20 (GMT) |
commit | f6413400a00362cf307d0fbb85daf96265091686 (patch) | |
tree | bd293e2de2a1b847951803199a4d049248e5bed2 | |
parent | b26e5b552a53521ba06d27835cac2a6f72d70dfc (diff) | |
download | CMake-f6413400a00362cf307d0fbb85daf96265091686.zip CMake-f6413400a00362cf307d0fbb85daf96265091686.tar.gz CMake-f6413400a00362cf307d0fbb85daf96265091686.tar.bz2 |
Add cmXMLWriter class to consolidate XML generation
Explicitly track XML generation state (indentation, element closure,
etc.) so that clients can avoid manually/implicitly maintaining it.
-rw-r--r-- | Source/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Source/cmXMLWriter.cxx | 134 | ||||
-rw-r--r-- | Source/cmXMLWriter.h | 120 |
3 files changed, 256 insertions, 0 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 9624401..a7adb51 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -347,6 +347,8 @@ set(SRCS cmXMLParser.h cmXMLSafe.cxx cmXMLSafe.h + cmXMLWriter.cxx + cmXMLWriter.h cmake.cxx cmake.h diff --git a/Source/cmXMLWriter.cxx b/Source/cmXMLWriter.cxx new file mode 100644 index 0000000..f9b3b49 --- /dev/null +++ b/Source/cmXMLWriter.cxx @@ -0,0 +1,134 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2015 Daniel Pfeifer <daniel@pfeifer-mail.de> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmXMLWriter.h" +#include "cmXMLSafe.h" + +#include <cassert> +#include <fstream> + +cmXMLWriter::cmXMLWriter(std::ostream& output, std::size_t level) +: Output(output) +, Level(level) +, ElementOpen(false) +, BreakAttrib(false) +, IsContent(false) +{ +} + +cmXMLWriter::~cmXMLWriter() +{ + assert(this->Elements.empty()); +} + +void cmXMLWriter::StartDocument(const char* encoding) +{ + this->Output << "<?xml version=\"1.0\" encoding=\"" << encoding << "\"?>"; +} + +void cmXMLWriter::EndDocument() +{ + assert(this->Elements.empty()); + this->Output << '\n'; +} + +void cmXMLWriter::StartElement(std::string const& name) +{ + this->CloseStartElement(); + this->ConditionalLineBreak(!this->IsContent, this->Elements.size()); + this->Output << '<' << name; + this->Elements.push(name); + this->ElementOpen = true; + this->BreakAttrib = false; +} + +void cmXMLWriter::EndElement() +{ + assert(!this->Elements.empty()); + if (this->ElementOpen) + { + this->Output << "/>"; + } + else + { + this->ConditionalLineBreak(!this->IsContent, this->Elements.size() - 1); + this->IsContent = false; + this->Output << "</" << this->Elements.top() << '>'; + } + this->Elements.pop(); + this->ElementOpen = false; +} + +void cmXMLWriter::BreakAttributes() +{ + this->BreakAttrib = true; +} + +void cmXMLWriter::Comment(const char* comment) +{ + this->CloseStartElement(); + this->ConditionalLineBreak(!this->IsContent, this->Elements.size()); + this->Output << "<!-- " << comment << " -->"; +} + +void cmXMLWriter::CData(std::string const& data) +{ + this->PreContent(); + this->Output << "<![CDATA[" << data << "]]>"; +} + +void cmXMLWriter::ProcessingInstruction(const char* target, const char* data) +{ + this->CloseStartElement(); + this->ConditionalLineBreak(!this->IsContent, this->Elements.size()); + this->Output << "<?" << target << ' ' << data << "?>"; +} + +void cmXMLWriter::FragmentFile(const char* fname) +{ + this->CloseStartElement(); + std::ifstream fin(fname, std::ios::in | std::ios::binary); + this->Output << fin.rdbuf(); +} + +void cmXMLWriter::ConditionalLineBreak(bool condition, std::size_t indent) +{ + if (condition) + { + this->Output << '\n' << std::string(indent + this->Level, '\t'); + } +} + +void cmXMLWriter::PreAttribute() +{ + assert(this->ElementOpen); + this->ConditionalLineBreak(this->BreakAttrib, this->Elements.size()); + if (!this->BreakAttrib) + { + this->Output << ' '; + } +} + +void cmXMLWriter::PreContent() +{ + this->CloseStartElement(); + this->IsContent = true; +} + +void cmXMLWriter::CloseStartElement() +{ + if (this->ElementOpen) + { + this->ConditionalLineBreak(this->BreakAttrib, this->Elements.size()); + this->Output << '>'; + this->ElementOpen = false; + } +} diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h new file mode 100644 index 0000000..c38c0de --- /dev/null +++ b/Source/cmXMLWriter.h @@ -0,0 +1,120 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2015 Daniel Pfeifer <daniel@pfeifer-mail.de> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmXMLWiter_h +#define cmXMLWiter_h + +#include "cmStandardIncludes.h" +#include "cmXMLSafe.h" + +#include <ostream> +#include <stack> +#include <string> +#include <vector> + +class cmXMLWriter +{ +public: + cmXMLWriter(std::ostream& output, std::size_t level = 0); + ~cmXMLWriter(); + + void StartDocument(const char* encoding = "UTF-8"); + void EndDocument(); + + void StartElement(std::string const& name); + void EndElement(); + + void BreakAttributes(); + + template <typename T> + void Attribute(const char* name, T const& value) + { + this->PreAttribute(); + this->Output << name << "=\"" << SafeAttribute(value) << '"'; + } + + template <typename T> + void Element(std::string const& name, T const& value) + { + this->StartElement(name); + this->Content(value); + this->EndElement(); + } + + template <typename T> + void Content(T const& content) + { + this->PreContent(); + this->Output << SafeContent(content); + } + + void Comment(const char* comment); + + void CData(std::string const& data); + + void ProcessingInstruction(const char* target, const char* data); + + void FragmentFile(const char* fname); + +private: + cmXMLWriter(const cmXMLWriter&); + cmXMLWriter& operator=(const cmXMLWriter&); + + void ConditionalLineBreak(bool condition, std::size_t indent); + + void PreAttribute(); + void PreContent(); + + void CloseStartElement(); + +private: + static cmXMLSafe SafeAttribute(const char* value) + { + return cmXMLSafe(value); + } + + static cmXMLSafe SafeAttribute(std::string const& value) + { + return cmXMLSafe(value); + } + + template <typename T> + static T SafeAttribute(T value) + { + return value; + } + + static cmXMLSafe SafeContent(const char* value) + { + return cmXMLSafe(value).Quotes(false); + } + + static cmXMLSafe SafeContent(std::string const& value) + { + return cmXMLSafe(value).Quotes(false); + } + + template <typename T> + static T SafeContent(T value) + { + return value; + } + +private: + std::ostream& Output; + std::stack<std::string, std::vector<std::string> > Elements; + std::size_t Level; + bool ElementOpen; + bool BreakAttrib; + bool IsContent; +}; + +#endif |