-
Notifications
You must be signed in to change notification settings - Fork 2
/
xml.cpp
88 lines (71 loc) · 1.89 KB
/
xml.cpp
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
#include "xml.h"
#include <string_view>
#include <iostream>
using namespace std;
namespace Xml{
pair<string_view, string_view> Split(string_view line, char by) {
size_t pos = line.find(by);
string_view left = line.substr(0, pos);
if (pos < line.size() && pos + 1 < line.size()) {
return {left, line.substr(pos + 1)};
} else {
return {left, string_view()};
}
}
string_view Lstrip(string_view line) {
while (!line.empty() && isspace(line[0])) {
line.remove_prefix(1);
}
return line;
}
string_view Unquote(string_view value) {
if (!value.empty() && value.front() == '"') {
value.remove_prefix(1);
}
if (!value.empty() && value.back() == '"') {
value.remove_suffix(1);
}
return value;
}
Node LoadNode(istream& input) {
string root_name;
getline(input, root_name);
Node root(root_name.substr(1, root_name.size() - 2), {});
for (string line; getline(input, line) && Lstrip(line)[1] != '/'; ) {
auto [node_name, attrs] = Split(Lstrip(line), ' ');
attrs = Split(attrs, '>').first;
unordered_map<string, string> node_attrs;
while (!attrs.empty()) {
auto [head, tail] = Split(attrs, ' ');
auto [name, value] = Split(head, '=');
if (!name.empty() && !value.empty()) {
node_attrs[string(Unquote(name))] = string(Unquote(value));
}
attrs = tail;
}
root.AddChild(Node(string(node_name.substr(1)), move(node_attrs)));
}
return root;
}
Document Load(istream& input) {
return Document{LoadNode(input)};
}
Node::Node(
string name, unordered_map<string, string> attrs
) : name(move(name)), attrs(move(attrs)) {
}
const vector<Node>& Node::Children() const {
return children;
}
Document::Document(Node root) : root(move(root)) {
}
const Node& Document::GetRoot() const {
return root;
}
void Node::AddChild(Node node) {
children.push_back(move(node));
}
string_view Node::Name() const {
return name;
}
}