First commit
[anna.git] / source / xml / Node.cpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #include <anna/core/functions.hpp>
38
39 #include <anna/xml/Node.hpp>
40 #include <anna/xml/Attribute.hpp>
41 #include <anna/xml/Text.hpp>
42
43 using namespace std;
44 using namespace anna;
45 using namespace anna::xml;
46
47 /*
48  * Si el nodo no tiene padre => debe crear los pool de datos en los que sus descendientes irán
49  * creando los objetos que vayan siendo necesarios.
50  *
51  * Éste es el constructor que se usará para instanciar al nodo ROOT.
52  */
53 Node::Node(const char* name) : a_name(name), a_parent(NULL), a_text(NULL), a_namespace(NULL) {
54   a_node_pool = new node_pool;
55   a_attribute_pool = new attribute_pool;
56   a_text_pool = new text_pool;
57   a_namespace_pool = new namespace_pool;
58   a_namespaces = new namespace_container;
59   a_root = this;
60 }
61
62 /*
63  * Si el nodo tiene padre => copiará las instancias de los pools de datos.
64  */
65 Node::Node() :  a_parent(NULL), a_text(NULL),  a_namespace(NULL) {
66   a_node_pool = NULL;
67   a_attribute_pool = NULL;
68   a_text_pool = NULL;
69   a_namespace_pool = NULL;
70   a_namespaces = NULL;
71   a_root = NULL;
72 }
73
74 Node::~Node() {
75   clear();
76
77   if(a_parent == NULL) {
78     delete a_node_pool;
79     delete a_attribute_pool;
80     delete a_text_pool;
81     delete a_namespace_pool;
82     delete a_namespaces;
83   }
84 }
85
86 void Node::clear()
87 throw() {
88   for(attribute_iterator aa = a_attributes.begin(), maxaa = a_attributes.end(); aa != maxaa; aa ++)
89     a_attribute_pool->release(attribute(aa));
90
91   a_attributes.clear();
92
93   for(Children::iterator cc = a_children.begin(), maxcc = a_children.end(); cc != maxcc; cc ++) {
94     Node* aux = node(cc);
95     aux->clear();
96     a_node_pool->release(aux);
97   }
98
99   a_children.clear();
100
101   if(a_text != NULL) {
102     a_text_pool->release(a_text);
103     a_text = NULL;
104   }
105
106   // Si es el nodo root ....
107   if(a_parent == NULL) {
108     a_namespaces->clear();
109     a_namespace_pool->clear();
110   }
111
112   a_namespace = NULL;
113 }
114
115 const Attribute* Node::getAttribute(const char* name, const bool exceptionWhenNotFound) const
116 throw(RuntimeException) {
117   const Attribute* result(NULL);
118   result = find(name, attribute_begin(), attribute_end());
119
120   if(result == NULL && exceptionWhenNotFound == true) {
121     string msg = asString();
122     msg += " | Attribute: ";
123     msg += name;
124     msg += " | Not found";
125     throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
126   }
127
128   return result;
129 }
130
131 xml::Attribute* Node::createAttribute(const char* name, const char* value, const Namespace* _namespace)
132 throw() {
133   Attribute* attribute = a_attribute_pool->create();
134   attribute->setNode(this);
135   attribute->setName(name);
136   attribute->setValue(value);
137   attribute->setNamespace(_namespace);
138   a_attributes.push_back(attribute);
139   return attribute;
140 }
141
142 xml::Text* Node::createText(const char* text)
143 throw(RuntimeException) {
144   if(a_text != NULL) {
145     string msg = asString();
146     msg += " | ";
147     msg += a_text->asString();
148     msg += " | Node has already text assigned";
149     throw RuntimeException(msg, ANNA_FILE_LOCATION);
150   }
151
152   a_text = a_text_pool->create();
153   a_text->setNode(this);
154   a_text->setValue(text);
155   return a_text;
156 }
157
158 Node* Node::createChild(const char* name)
159 throw() {
160   Node* result = a_node_pool->create();
161   result->a_parent = this;
162   result->setName(name);
163   result->a_node_pool = a_node_pool;
164   result->a_attribute_pool = a_attribute_pool;
165   result->a_text_pool = a_text_pool;
166   result->a_root = a_root;
167   a_children.push_back(result);
168   return result;
169 }
170
171 /*
172  * Recordar que todos los namespaces se crean sólo en el nodo ROOT.
173  */
174 const Namespace* Node::createNamespace(const std::string& name, const char* reference)
175 throw(RuntimeException) {
176   const Namespace* result = NULL;
177
178   if((result = namespace_find(name, false)) != NULL) {
179     if(result->getReference() != reference) {
180       string msg(result->asString());
181       msg += " | New reference: ";
182       msg += reference;
183       msg += " | Namespace already defined";
184       throw RuntimeException(msg, ANNA_FILE_LOCATION);
185     }
186   } else {
187     if(a_root == this) {
188       Namespace* newns = a_namespace_pool->create();
189       newns->setName(name);
190       newns->setReference(reference);
191       a_namespaces->add(newns);
192       result = newns;
193     } else
194       result = a_root->createNamespace(name, reference);
195   }
196
197   return result;
198 }
199
200 const Node* Node::find(const char* childName, const bool exceptionWhenNotFound) const
201 throw(RuntimeException) {
202   const Node* child;
203
204   for(Node::Children::const_iterator ii = a_children.begin(), maxii = a_children.end(); ii != maxii; ii ++) {
205     child = *ii;
206
207     if(anna_strcmp(child->a_name.c_str(), childName) == 0)
208       return child;
209   }
210
211   if(exceptionWhenNotFound == true) {
212     std::string msg("Successor '");
213     msg += childName;
214     msg += "' not found at node '";
215     msg += a_name;
216     msg += "'";
217     throw RuntimeException(msg, ANNA_FILE_LOCATION);
218   }
219
220   return NULL;
221 }
222
223 Namespace* Node::namespace_find(const std::string& name, const bool exceptionWhenNotFound)
224 throw(RuntimeException) {
225   Namespace* result = a_root->a_namespaces->find(name);
226
227   if(result == NULL && exceptionWhenNotFound == true) {
228     string msg(asString());
229     msg += " | Namespace: ";
230     msg += name;
231     msg += " | Namespace is not defined";
232     throw RuntimeException(msg, ANNA_FILE_LOCATION);
233   }
234
235   return  result;
236 }
237
238 string Node::asString() const
239 throw() {
240   string result("xml::Node { Name: ");
241   result += a_name;
242
243   if(a_namespace != NULL) {
244     result += " | ";
245     result += a_namespace->asString();
246   }
247
248   return result += " }";
249 }
250
251 const Attribute* Node::find(const char* attrName, const_attribute_iterator begin, const_attribute_iterator end)
252 throw() {
253   Attribute* attribute;
254
255   for(; begin != end; begin ++) {
256     attribute = *begin;
257
258     if(anna_strcmp(attribute->getName(), attrName) == 0)
259       return attribute;
260   }
261
262   return NULL;
263 }
264