File indexing completed on 2025-09-16 08:52:13
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef CATCH_XMLWRITER_HPP_INCLUDED
0009 #define CATCH_XMLWRITER_HPP_INCLUDED
0010
0011 #include <catch2/internal/catch_reusable_string_stream.hpp>
0012 #include <catch2/internal/catch_stringref.hpp>
0013
0014 #include <iosfwd>
0015 #include <vector>
0016 #include <cstdint>
0017
0018 namespace Catch {
0019 enum class XmlFormatting : std::uint8_t {
0020 None = 0x00,
0021 Indent = 0x01,
0022 Newline = 0x02,
0023 };
0024
0025 constexpr XmlFormatting operator|( XmlFormatting lhs, XmlFormatting rhs ) {
0026 return static_cast<XmlFormatting>( static_cast<std::uint8_t>( lhs ) |
0027 static_cast<std::uint8_t>( rhs ) );
0028 }
0029
0030 constexpr XmlFormatting operator&( XmlFormatting lhs, XmlFormatting rhs ) {
0031 return static_cast<XmlFormatting>( static_cast<std::uint8_t>( lhs ) &
0032 static_cast<std::uint8_t>( rhs ) );
0033 }
0034
0035
0036
0037
0038
0039
0040
0041
0042 class XmlEncode {
0043 public:
0044 enum ForWhat { ForTextNodes, ForAttributes };
0045
0046 constexpr XmlEncode( StringRef str, ForWhat forWhat = ForTextNodes ):
0047 m_str( str ), m_forWhat( forWhat ) {}
0048
0049
0050 void encodeTo( std::ostream& os ) const;
0051
0052 friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
0053
0054 private:
0055 StringRef m_str;
0056 ForWhat m_forWhat;
0057 };
0058
0059 class XmlWriter {
0060 public:
0061
0062 class ScopedElement {
0063 public:
0064 ScopedElement( XmlWriter* writer, XmlFormatting fmt );
0065
0066 ScopedElement( ScopedElement&& other ) noexcept;
0067 ScopedElement& operator=( ScopedElement&& other ) noexcept;
0068
0069 ~ScopedElement();
0070
0071 ScopedElement&
0072 writeText( StringRef text,
0073 XmlFormatting fmt = XmlFormatting::Newline |
0074 XmlFormatting::Indent );
0075
0076 ScopedElement& writeAttribute( StringRef name,
0077 StringRef attribute );
0078 template <typename T,
0079
0080
0081
0082
0083 typename = typename std::enable_if_t<
0084 !std::is_convertible<T, StringRef>::value>>
0085 ScopedElement& writeAttribute( StringRef name,
0086 T const& attribute ) {
0087 m_writer->writeAttribute( name, attribute );
0088 return *this;
0089 }
0090
0091 private:
0092 XmlWriter* m_writer = nullptr;
0093 XmlFormatting m_fmt;
0094 };
0095
0096 XmlWriter( std::ostream& os );
0097 ~XmlWriter();
0098
0099 XmlWriter( XmlWriter const& ) = delete;
0100 XmlWriter& operator=( XmlWriter const& ) = delete;
0101
0102 XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
0103
0104 ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
0105
0106 XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
0107
0108
0109 XmlWriter& writeAttribute( StringRef name, StringRef attribute );
0110
0111
0112 XmlWriter& writeAttribute( StringRef name, bool attribute );
0113
0114
0115 XmlWriter& writeAttribute( StringRef name, char const* attribute );
0116
0117
0118
0119 template <typename T,
0120
0121
0122
0123
0124 typename = typename std::enable_if_t<
0125 !std::is_convertible<T, StringRef>::value>>
0126 XmlWriter& writeAttribute( StringRef name, T const& attribute ) {
0127 ReusableStringStream rss;
0128 rss << attribute;
0129 return writeAttribute( name, rss.str() );
0130 }
0131
0132
0133 XmlWriter& writeText( StringRef text,
0134 XmlFormatting fmt = XmlFormatting::Newline |
0135 XmlFormatting::Indent );
0136
0137
0138 XmlWriter& writeComment( StringRef text,
0139 XmlFormatting fmt = XmlFormatting::Newline |
0140 XmlFormatting::Indent );
0141
0142 void writeStylesheetRef( StringRef url );
0143
0144 void ensureTagClosed();
0145
0146 private:
0147
0148 void applyFormatting(XmlFormatting fmt);
0149
0150 void writeDeclaration();
0151
0152 void newlineIfNecessary();
0153
0154 bool m_tagIsOpen = false;
0155 bool m_needsNewline = false;
0156 std::vector<std::string> m_tags;
0157 std::string m_indent;
0158 std::ostream& m_os;
0159 };
0160
0161 }
0162
0163 #endif