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
|
/*
* This is a very simple, hard-coded and limited XML parser, which parses XML from file into local variable.
* Made for illustrative purposes.
*/
#include <fstream>
#include <iostream>
#include <cstring>
class Tag {
public: // щото да не се занимавам с гетъри и сетъри
char name[64];
// char id[64];
char value[64];
Tag* children;
unsigned length;
unsigned count;
private:
void copyFrom(const Tag& other) {
strncpy(name, other.name, 64);
strncpy(value, other.value, 64);
children = new Tag[other.length];
for (unsigned i = 0; i < other.count; i++)
children[i] = other.children[i];
length = other.length;
count = other.count;
}
void free() {
delete[] children;
}
void resize() {
if (length == 0) length = 4;
Tag* tmp = new Tag[length <<= 1];
for (unsigned i = 0; i < count; i++)
tmp[i] = children[i];
delete[] children;
children = tmp;
}
public:
void addChild(const Tag& child) {
if (length == count)
resize();
children[count++] = child;
}
Tag() {
children = nullptr;
length = count = 0;
}
Tag(const Tag& other) {
copyFrom(other);
}
Tag& operator=(const Tag& other) {
if (this != &other) {
free();
copyFrom(other);
}
return *this;
}
~Tag() {
free();
}
};
void parseTag(Tag& root, std::ifstream& file) {
Tag newTag;
// Вземаме името на тага (все едно всичко между < и >)
// важно: предполагаме, че вече сме минали < и от сега до > е само името на тага
char buffer = '<';
for (unsigned i = 0; i < 63 && file.peek() != '>'; i++) {
buffer = file.get();
newTag.name[i] = buffer;
newTag.name[i + 1] = '\0';
}
file.get(); // ние сме на знак >, затова отиваме на следващия
// ако следващия не е <, то имаме някаква стойност, която ще запазим
for (unsigned i = 0; i < 63 && file.peek() != '<'; i++) {
buffer = file.get();
newTag.value[i] = buffer;
newTag.value[i + 1] = '\0';
}
file.get(); // ние сме на знак <, затова отиваме на следващия
// предишния знак е <, тоест, ако сегашния е /, то имаме </ и значи край на обекта
// иначе, означава, че четем името на някое дете
while (file.peek() != '/') {
parseTag(newTag, file);
}
// значи, намираме се в затварящ таг (</ ... >), сега просто ще скипнем името му
for (unsigned i = 0; file.peek() != '>'; i++)
file.get();
file.get(); // знаем, че сме на >, затова отиваме на следващия
file.get(); // ако има съседни тагове, то в момента ще сме на <, затова и него го скипваме
root.addChild(newTag);
}
void printTag(Tag& tag, unsigned level = 0) {
for (unsigned i = 0; i < level; i++)
std::cout << " ";
std::cout << "<" << tag.name << ">" << " " << tag.value << std::endl;
level++;
for (unsigned i = 0; i < tag.count; i++)
printTag(tag.children[i], level);
}
int main() {
std::ifstream inFile("test.xml");
inFile.get();
Tag root;
parseTag(root, inFile);
printTag(root);
inFile.close();
}
|