MUSX Document Model
Loading...
Searching...
No Matches
XmlInterface.h
1/*
2 * Copyright (C) 2025, Robert Patterson
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22#pragma once
23
24#include <string>
25#include <memory>
26#include <vector>
27#include <sstream>
28#include <stdexcept>
29#include <algorithm>
30#include <functional>
31#include <type_traits>
32#include <utility>
33
34// Do not add header dependencies from musx.
35
36namespace musx {
37
38namespace factory {
39class ConstructionContext;
40} // factory
41
46namespace xml {
47
51class load_error : public std::runtime_error
52{
53public:
54 using std::runtime_error::runtime_error;
55};
56
57#ifndef DOXYGEN_SHOULD_IGNORE_THIS
59inline std::string trim(const std::string& str)
60{
61 auto start = std::find_if_not(str.begin(), str.end(), ::isspace);
62 auto end = std::find_if_not(str.rbegin(), str.rend(), ::isspace).base();
63 return (start < end) ? std::string(start, end) : std::string();
64}
65#endif // DOXYGEN_SHOULD_IGNORE_THIS
66
71{
72public:
73 virtual ~IXmlAttribute() = default;
74
79 virtual std::string getName() const = 0;
80
85 virtual std::string getValue() const = 0;
86
90 std::string getValueTrimmed() const { return trim(getValue()); }
91
98 template <typename T>
99 T getValueAs() const {
100 std::istringstream iss(getValueTrimmed());
101 T value;
102 if constexpr (std::is_same_v<T, bool>) {
103 std::string str;
104 iss >> str;
105 std::transform(str.begin(), str.end(), str.begin(), ::tolower); // Ensure case insensitivity
106 if (str == "true") {
107 return true;
108 }
109 else if (str == "false") {
110 return false;
111 }
112 }
113 if (!(iss >> value)) {
114 throw std::invalid_argument("Failed to convert attribute value [" + iss.str() + "] to the specified type");
115 }
116 return value;
117 }
118
123 virtual std::shared_ptr<IXmlAttribute> nextAttribute() const = 0;
124};
125
126class IXmlElement;
127using XmlElementPtr = std::shared_ptr<IXmlElement>;
128template <typename T>
129using XmlElementPopulator = std::function<void(factory::ConstructionContext&, const XmlElementPtr&, const std::shared_ptr<T>&)>;
130template <typename T>
131using XmlElementDescriptor = std::tuple<const std::string_view, XmlElementPopulator<T>>;
132template <typename T>
133using XmlElementArray = std::vector<XmlElementDescriptor<T>>;
134
139{
140public:
141 virtual ~IXmlElement() = default;
142
147 virtual std::string getTagName() const = 0;
148
153 virtual std::string getText() const = 0;
154
158 std::string getTextTrimmed() const { return trim(getText()); }
159
167 template <typename T>
168 T getTextAs(T defaultValue = {}) const
169 {
170 static_assert(std::is_arithmetic_v<T>,
171 "getTextAs requires a numeric type. Use getText for string content.");
172 static_assert(!std::is_same_v<T, bool>, "Do not use getTextAs with bool type. Simply assign true. (The presence of the node means true.)");
173
174 std::istringstream iss(getTextTrimmed());
175 if (iss.str().empty()) {
176 return defaultValue;
177 }
178
179 using ValueType = std::conditional_t<
180 std::is_same_v<T, char>
181 || std::is_same_v<T, uint8_t>
182 || std::is_same_v<T, char16_t>
183 || std::is_same_v<T, char32_t>, int, T>;
184 ValueType value = ValueType(defaultValue);
185
186 if (!(iss >> value)) {
187 throw std::invalid_argument("Failed to convert text content [" + iss.str() + "] to the specified type");
188 }
189
190 return T(value);
191 }
192
197 virtual std::shared_ptr<IXmlAttribute> getFirstAttribute() const = 0;
198
204 virtual std::shared_ptr<IXmlAttribute> findAttribute(const std::string& name) const = 0;
205
211 virtual XmlElementPtr getFirstChildElement(const std::string& tagName = {}) const = 0;
212
218 virtual XmlElementPtr getNextSibling(const std::string& tagName = {}) const = 0;
219
225 virtual XmlElementPtr getPreviousSibling(const std::string& tagName = {}) const = 0;
226
231 virtual XmlElementPtr getParent() const = 0;
232};
233
238{
239public:
240 virtual ~IXmlDocument() = default;
241
248 virtual void loadFromBuffer(const char * data, size_t size) = 0;
249
255 virtual void loadFromString(const std::string& xmlContent) = 0;
256
262 void loadFromString(const std::vector<char>& xmlContent)
263 {
264 loadFromBuffer(xmlContent.data(), xmlContent.size());
265 }
266
271 virtual std::shared_ptr<IXmlElement> getRootElement() const = 0;
272};
273
274} // namespace xml
275} // namespace musx
State shared by all factories during one document construction.
Definition ConstructionContext.h:12
Interface for an XML attribute.
Definition XmlInterface.h:71
std::string getValueTrimmed() const
Gets the text content of the attribute with whitespace trimmed.
Definition XmlInterface.h:90
virtual std::string getValue() const =0
Gets the value of the attribute.
virtual std::shared_ptr< IXmlAttribute > nextAttribute() const =0
Advances to the next attribute.
T getValueAs() const
Gets the value of the attribute, converted to the specified type.
Definition XmlInterface.h:99
virtual std::string getName() const =0
Gets the name of the attribute.
Interface for an XML document.
Definition XmlInterface.h:238
virtual std::shared_ptr< IXmlElement > getRootElement() const =0
Gets the root element of the document.
virtual void loadFromString(const std::string &xmlContent)=0
Loads XML content from a string.
virtual void loadFromBuffer(const char *data, size_t size)=0
Loads XML content from buffer.
void loadFromString(const std::vector< char > &xmlContent)
Loads XML content from a vector of characters.
Definition XmlInterface.h:262
Interface for an XML element.
Definition XmlInterface.h:139
virtual XmlElementPtr getPreviousSibling(const std::string &tagName={}) const =0
Gets the previous sibling element.
virtual XmlElementPtr getParent() const =0
Gets the parent element.
virtual XmlElementPtr getNextSibling(const std::string &tagName={}) const =0
Gets the next sibling element.
virtual std::shared_ptr< IXmlAttribute > getFirstAttribute() const =0
Gets the first attribute.
virtual std::string getText() const =0
Gets the text content of the element.
std::string getTextTrimmed() const
Gets the text content of the element with whitespace trimmed.
Definition XmlInterface.h:158
T getTextAs(T defaultValue={}) const
Gets the text content of the element, converted to the specified type.
Definition XmlInterface.h:168
virtual XmlElementPtr getFirstChildElement(const std::string &tagName={}) const =0
Finds the first child element.
virtual std::shared_ptr< IXmlAttribute > findAttribute(const std::string &name) const =0
Finds the first attribute.
virtual std::string getTagName() const =0
Gets the tag name of the element.
Exception for load xml error.
Definition XmlInterface.h:52
std::tuple< const std::string_view, XmlElementPopulator< T > > XmlElementDescriptor
associates an xml node name with and XmlElementPopulator
Definition XmlInterface.h:131
std::vector< XmlElementDescriptor< T > > XmlElementArray
an array type for XmlElementDescriptor instances.
Definition XmlInterface.h:133
std::function< void(factory::ConstructionContext &, const XmlElementPtr &, const std::shared_ptr< T > &)> XmlElementPopulator
function type for populating a field from an IXmlElement
Definition XmlInterface.h:129
std::shared_ptr< IXmlElement > XmlElementPtr
shared pointer to IXmlElement
Definition XmlInterface.h:127
object model for musx file (enigmaxml)
Definition BaseClasses.h:38