Update date in Doxyfile
[anna.git] / source / xml / Node.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <anna/core/functions.hpp>
10
11 #include <anna/xml/Node.hpp>
12 #include <anna/xml/Attribute.hpp>
13 #include <anna/xml/Text.hpp>
14
15 using namespace std;
16 using namespace anna;
17 using namespace anna::xml;
18
19 /*
20  * Si el nodo no tiene padre => debe crear los pool de datos en los que sus descendientes irán
21  * creando los objetos que vayan siendo necesarios.
22  *
23  * Éste es el constructor que se usará para instanciar al nodo ROOT.
24  */
25 Node::Node(const char* name) : a_name(name), a_parent(NULL), a_text(NULL), a_namespace(NULL) {
26   a_node_pool = new node_pool;
27   a_attribute_pool = new attribute_pool;
28   a_text_pool = new text_pool;
29   a_namespace_pool = new namespace_pool;
30   a_namespaces = new namespace_container;
31   a_root = this;
32 }
33
34 /*
35  * Si el nodo tiene padre => copiará las instancias de los pools de datos.
36  */
37 Node::Node() :  a_parent(NULL), a_text(NULL),  a_namespace(NULL) {
38   a_node_pool = NULL;
39   a_attribute_pool = NULL;
40   a_text_pool = NULL;
41   a_namespace_pool = NULL;
42   a_namespaces = NULL;
43   a_root = NULL;
44 }
45
46 Node::~Node() {
47   clear();
48
49   if(a_parent == NULL) {
50     delete a_node_pool;
51     delete a_attribute_pool;
52     delete a_text_pool;
53     delete a_namespace_pool;
54     delete a_namespaces;
55   }
56 }
57
58 void Node::clear()
59 throw() {
60   for(attribute_iterator aa = a_attributes.begin(), maxaa = a_attributes.end(); aa != maxaa; aa ++)
61     a_attribute_pool->release(attribute(aa));
62
63   a_attributes.clear();
64
65   for(Children::iterator cc = a_children.begin(), maxcc = a_children.end(); cc != maxcc; cc ++) {
66     Node* aux = node(cc);
67     aux->clear();
68     a_node_pool->release(aux);
69   }
70
71   a_children.clear();
72
73   if(a_text != NULL) {
74     a_text_pool->release(a_text);
75     a_text = NULL;
76   }
77
78   // Si es el nodo root ....
79   if(a_parent == NULL) {
80     a_namespaces->clear();
81     a_namespace_pool->clear();
82   }
83
84   a_namespace = NULL;
85 }
86
87 const Attribute* Node::getAttribute(const char* name, const bool exceptionWhenNotFound) const
88 throw(RuntimeException) {
89   const Attribute* result(NULL);
90   result = find(name, attribute_begin(), attribute_end());
91
92   if(result == NULL && exceptionWhenNotFound == true) {
93     string msg = asString();
94     msg += " | Attribute: ";
95     msg += name;
96     msg += " | Not found";
97     throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
98   }
99
100   return result;
101 }
102
103 xml::Attribute* Node::createAttribute(const char* name, const char* value, const Namespace* _namespace)
104 throw() {
105   Attribute* attribute = a_attribute_pool->create();
106   attribute->setNode(this);
107   attribute->setName(name);
108   attribute->setValue(value);
109   attribute->setNamespace(_namespace);
110   a_attributes.push_back(attribute);
111   return attribute;
112 }
113
114 xml::Text* Node::createText(const char* text)
115 throw(RuntimeException) {
116   if(a_text != NULL) {
117     string msg = asString();
118     msg += " | ";
119     msg += a_text->asString();
120     msg += " | Node has already text assigned";
121     throw RuntimeException(msg, ANNA_FILE_LOCATION);
122   }
123
124   a_text = a_text_pool->create();
125   a_text->setNode(this);
126   a_text->setValue(text);
127   return a_text;
128 }
129
130 Node* Node::createChild(const char* name)
131 throw() {
132   Node* result = a_node_pool->create();
133   result->a_parent = this;
134   result->setName(name);
135   result->a_node_pool = a_node_pool;
136   result->a_attribute_pool = a_attribute_pool;
137   result->a_text_pool = a_text_pool;
138   result->a_root = a_root;
139   a_children.push_back(result);
140   return result;
141 }
142
143 /*
144  * Recordar que todos los namespaces se crean sólo en el nodo ROOT.
145  */
146 const Namespace* Node::createNamespace(const std::string& name, const char* reference)
147 throw(RuntimeException) {
148   const Namespace* result = NULL;
149
150   if((result = namespace_find(name, false)) != NULL) {
151     if(result->getReference() != reference) {
152       string msg(result->asString());
153       msg += " | New reference: ";
154       msg += reference;
155       msg += " | Namespace already defined";
156       throw RuntimeException(msg, ANNA_FILE_LOCATION);
157     }
158   } else {
159     if(a_root == this) {
160       Namespace* newns = a_namespace_pool->create();
161       newns->setName(name);
162       newns->setReference(reference);
163       a_namespaces->add(newns);
164       result = newns;
165     } else
166       result = a_root->createNamespace(name, reference);
167   }
168
169   return result;
170 }
171
172 const Node* Node::find(const char* childName, const bool exceptionWhenNotFound) const
173 throw(RuntimeException) {
174   const Node* child;
175
176   for(Node::Children::const_iterator ii = a_children.begin(), maxii = a_children.end(); ii != maxii; ii ++) {
177     child = *ii;
178
179     if(anna_strcmp(child->a_name.c_str(), childName) == 0)
180       return child;
181   }
182
183   if(exceptionWhenNotFound == true) {
184     std::string msg("Successor '");
185     msg += childName;
186     msg += "' not found at node '";
187     msg += a_name;
188     msg += "'";
189     throw RuntimeException(msg, ANNA_FILE_LOCATION);
190   }
191
192   return NULL;
193 }
194
195 Namespace* Node::namespace_find(const std::string& name, const bool exceptionWhenNotFound)
196 throw(RuntimeException) {
197   Namespace* result = a_root->a_namespaces->find(name);
198
199   if(result == NULL && exceptionWhenNotFound == true) {
200     string msg(asString());
201     msg += " | Namespace: ";
202     msg += name;
203     msg += " | Namespace is not defined";
204     throw RuntimeException(msg, ANNA_FILE_LOCATION);
205   }
206
207   return  result;
208 }
209
210 string Node::asString() const
211 throw() {
212   string result("xml::Node { Name: ");
213   result += a_name;
214
215   if(a_namespace != NULL) {
216     result += " | ";
217     result += a_namespace->asString();
218   }
219
220   return result += " }";
221 }
222
223 const Attribute* Node::find(const char* attrName, const_attribute_iterator begin, const_attribute_iterator end)
224 throw() {
225   Attribute* attribute;
226
227   for(; begin != end; begin ++) {
228     attribute = *begin;
229
230     if(anna_strcmp(attribute->getName(), attrName) == 0)
231       return attribute;
232   }
233
234   return NULL;
235 }
236