aboutsummaryrefslogtreecommitdiff
path: root/include/cru/xml/XmlNode.h
blob: a7d1bf38e3cb48c2bd826c4fd752c2b3e4e4fe4b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#pragma once

#include "Base.h"

#include "cru/base/String.h"

#include <algorithm>
#include <optional>
#include <unordered_map>
#include <vector>

namespace cru::xml {
class XmlElementNode;
class XmlTextNode;
class XmlCommentNode;

class CRU_XML_API XmlNode {
  friend XmlElementNode;

 public:
  enum class Type { Text, Element, Comment };

 protected:
  explicit XmlNode(Type type) : type_(type) {}

 public:
  CRU_DELETE_COPY(XmlNode)
  CRU_DELETE_MOVE(XmlNode)

  virtual ~XmlNode() = default;

  Type GetType() const { return type_; }
  XmlElementNode* GetParent() const { return parent_; }

  virtual XmlNode* Clone() const = 0;

  bool IsTextNode() const { return type_ == Type::Text; }
  bool IsElementNode() const { return type_ == Type::Element; }
  bool IsCommentNode() const { return type_ == Type::Comment; }

  XmlElementNode* AsElement();
  XmlTextNode* AsText();
  XmlCommentNode* AsComment();
  const XmlElementNode* AsElement() const;
  const XmlTextNode* AsText() const;
  const XmlCommentNode* AsComment() const;

 private:
  const Type type_;
  XmlElementNode* parent_ = nullptr;
};

class CRU_XML_API XmlTextNode : public XmlNode {
 public:
  XmlTextNode() : XmlNode(Type::Text) {}
  explicit XmlTextNode(String text)
      : XmlNode(Type::Text), text_(std::move(text)) {}

  CRU_DELETE_COPY(XmlTextNode)
  CRU_DELETE_MOVE(XmlTextNode)

  ~XmlTextNode() override = default;

 public:
  String GetText() const { return text_; }
  void SetText(String text) { text_ = std::move(text); }

  XmlNode* Clone() const override { return new XmlTextNode(text_); }

 private:
  String text_;
};

class CRU_XML_API XmlElementNode : public XmlNode {
 public:
  XmlElementNode() : XmlNode(Type::Element) {}
  explicit XmlElementNode(String tag,
                          std::unordered_map<String, String> attributes = {})
      : XmlNode(Type::Element),
        tag_(std::move(tag)),
        attributes_(std::move(attributes)) {}

  CRU_DELETE_COPY(XmlElementNode)
  CRU_DELETE_MOVE(XmlElementNode)

  ~XmlElementNode() override;

 public:
  String GetTag() const { return tag_; }
  void SetTag(String tag) { tag_ = std::move(tag); }
  const std::unordered_map<String, String>& GetAttributes() const {
    return attributes_;
  }
  void SetAttributes(std::unordered_map<String, String> attributes) {
    attributes_ = std::move(attributes);
  }
  const std::vector<XmlNode*> GetChildren() const { return children_; }

  Index GetChildCount() const { return children_.size(); }
  String GetAttributeValue(const String& key) const {
    return attributes_.at(key);
  }
  String GetAttributeValueCaseInsensitive(const String& key) const {
    return *GetOptionalAttributeValueCaseInsensitive(key);
  }
  std::optional<String> GetOptionalAttributeValue(const String& key) const {
    auto it = attributes_.find(key);
    if (it == attributes_.end()) {
      return std::nullopt;
    }

    return it->second;
  }
  std::optional<String> GetOptionalAttributeValueCaseInsensitive(
      const String& key) const {
    for (auto it = attributes_.begin(); it != attributes_.end(); ++it) {
      if (it->first.CaseInsensitiveCompare(key) == 0) {
        return it->second;
      }
    }

    return std::nullopt;
  }

  XmlNode* GetChildAt(Index index) const { return children_[index]; }

  void AddAttribute(String key, String value);
  void AddChild(XmlNode* child);

  Index GetChildElementCount() const;
  XmlElementNode* GetFirstChildElement() const;

  XmlNode* Clone() const override;

 private:
  String tag_;
  std::unordered_map<String, String> attributes_;
  std::vector<XmlNode*> children_;
};

class CRU_XML_API XmlCommentNode : public XmlNode {
 public:
  XmlCommentNode() : XmlNode(Type::Comment) {}
  explicit XmlCommentNode(String text)
      : XmlNode(Type::Comment), text_(std::move(text)) {}

  CRU_DELETE_COPY(XmlCommentNode)
  CRU_DELETE_MOVE(XmlCommentNode)

  ~XmlCommentNode() override;

  String GetText() const { return text_; }
  void SetText(String text) { text_ = std::move(text); }

  XmlNode* Clone() const override;

 private:
  String text_;
};
}  // namespace cru::xml