1 // ANNA - Anna is Not 'N' Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // https://bitbucket.org/testillano/anna
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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
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.
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.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #ifndef anna_xml_Node_hpp
38 #define anna_xml_Node_hpp
42 #include <anna/core/Allocator.hpp>
43 #include <anna/core/RuntimeException.hpp>
44 #include <anna/core/functions.hpp>
45 #include <anna/core/util/Recycler.hpp>
46 #include <anna/core/util/SortedVector.hpp>
48 #include <anna/xml/Namespace.hpp>
61 Nodo de documento XML.
63 Cada nodo puede tener una serie indeterminada de atributos y nodos hijos. Por ejemplo:
67 <xvc HeartBeat="20000">
69 <INetAddress Address="204.152.65.15" Port="2000"/>
70 <INetAddress Address="204.152.65.47" Port="2002"/>
73 <ethernet Mode="raw" VirtualAddress="1.1.1.100">
74 <Input Device="/dev/qfe" PhysicalAccessPoint="2" MAC="8:0:20:9e:ee:21"/>
75 <Output Device="/dev/qfe" PhysicalAccessPoint="2" MAC="8:0:20:9e:ee:c9"/>
81 El nodo \em xvc tiene un atributo (ver Attribute) llamado \em HeartBeat y dos nodos
82 hijos (\em broadcast y \em ethernet).
85 struct NamespaceByName {
86 static const std::string& value(const Namespace* ns) throw() { return ns->getName(); }
90 typedef std::vector <Node*> Children; /**< Estructura usada para guardar los nodos hijos */
91 typedef Children::iterator child_iterator; /**< Iterador sobre lista de nodos */
92 typedef Children::const_iterator const_child_iterator; /**< Iterador sobre lista de nodos no modificables */
94 typedef std::vector <Attribute*> Attributes; /**< Estructura usada para guardar los attributos */
95 typedef Attributes::iterator attribute_iterator; /**< Iterador sobre la lista de atributos no modificables. */
96 typedef Attributes::const_iterator const_attribute_iterator; /**< Iterador sobre la lista de atributos no modificables */
98 typedef SortedVector <Namespace, NamespaceByName, std::string> namespace_container;
99 typedef namespace_container::iterator namespace_iterator;
100 typedef namespace_container::const_iterator const_namespace_iterator;
104 \param name Nombre del nodo.
106 Node(const char* name);
114 Devuelve el nombre del nodo.
115 \return El nombre del nodo.
117 const char* getName() const throw() { return a_name.c_str(); }
120 * Devuelve el nombre del nodo.
121 * \return El nombre del nodo.
123 const std::string& getNameAsString() const throw() { return a_name; }
126 Devuelve la referencia al nodo predecesor de este nodo. Pueder ser NULL.
127 \return La referencia al nodo predecesor de este nodo. Pueder ser NULL.
129 const Node* getParent() const throw() { return a_parent; }
132 Devuelve la referencia al nodo predecesor de este nodo. Pueder ser NULL.
133 \return La referencia al nodo predecesor de este nodo. Pueder ser NULL.
135 Node* getParent() throw() { return const_cast <Node*>(a_parent); }
138 Devuelve la referencia al atributo que coincide con el nombre dado, si no existe lanzara
139 una excepcion de ejecucion.
140 \param name Nombre del atributo buscado.
141 \param exceptionWhenNotFound Indica el comportamiento en caso de no encontrar el atributo que
142 coincida con el nombre buscado.
143 \return La referencia al atributo que coincide con el nombre dado.
145 const Attribute* getAttribute(const char* name, const bool exceptionWhenNotFound = true) const throw(anna::RuntimeException);
148 Devuelve la referencia al texto asociado a este nodo. Pueder ser NULL.
149 \return La referencia al texto asociado a este nodo. Pueder ser NULL.
151 const Text* getText() const throw() { return a_text; }
154 * Devuelve el namespace asociado a este nodo. Puede ser NULL.
155 * \return el namespace asociado a este nodo. Puede ser NULL.
157 const Namespace* getNamespace() const throw() { return a_namespace; }
160 Devuelve un iterador al comienzo de la lista de nodo hijos.
162 A continuacion presentamos un ejemplo de como se recorreria lista de nodos
163 hijos de una determinado nodo.
167 using namespace anna::xml;
169 Node* theNode = ... <establece un valor correcto> ...
172 for (Node::iterator ii = theNode->begin (), maxii = theNode->end (); ii != maxii; ii ++) {
173 theChild = Node::node (ii);
175 .... <Procesar el hijo> ....
180 \return Un iterador al comienzo de la lista de nodo hijos.
182 child_iterator child_begin() throw() { return a_children.begin(); }
185 Devuelve un iterador al comienzo de la lista de nodos hijos no modificables.
187 A continuacion presentamos un ejemplo de como se recorreria lista de nodos
188 hijos de una determinado nodo no modificable.
192 using namespace anna::xml;
194 const Node* theNode = ... <establece un valor correcto> ...
195 const Node* theChild;
197 for (Node::const_iterator ii = theNode->begin (), maxii = theNode->end (); ii != maxii; ii ++) {
198 theChild = Node::node (ii);
200 .... <Procesar el hijo> ....
205 \return Un iterador al comienzo de la lista de nodo hijos no modificables.
207 const_child_iterator child_begin() const throw() { return a_children.begin(); }
210 Devuelve un iterador al comienzo de la lista de atributos no modificables.
211 \return Un iterador al comienzo de la lista de atributos no modificables.
213 const_attribute_iterator attribute_begin() const throw() { return a_attributes.begin(); }
216 Devuelve un iterador al comienzo de la lista de namespaces no modificables.
217 \return Un iterador al comienzo de la lista de namespaces no modificables.
219 const_namespace_iterator namespace_begin() const throw() { return a_root->a_namespaces->begin(); }
223 Devuelve un iterador al final de la lista de nodo hijos.
224 \return Un iterador al final de la lista de nodo hijos.
227 child_iterator child_end() throw() { return a_children.end(); }
230 Devuelve un iterador al final de la lista de nodo hijos no modificables.
231 \return Un iterador al final de la lista de nodo hijos no modificables.
234 const_child_iterator child_end() const throw() { return a_children.end(); }
237 * Devuelve el número de hijos definidos.
238 * \return el número de hijos definidos.
240 int child_size() const throw() { return a_children.size(); }
243 Devuelve un iterador al final de la lista de atributos no modificables.
244 \return Un iterador al final de la lista de atributos no modificables.
246 const_attribute_iterator attribute_end() const throw() { return a_attributes.end(); }
249 Devuelve un iterador al comienzo de la lista de namespaces no modificables.
250 \return Un iterador al comienzo de la lista de namespaces no modificables.
252 const_namespace_iterator namespace_end() const throw() { return a_root->a_namespaces->end(); }
255 * Devuelve el número de namespace definidos.
256 * \return el número de namespace definidos.
258 int namespace_size() const throw() { return a_root->a_namespaces->size(); }
261 Busca un nodo sucesor directo de este cuyo nombre coincida con el nombre recibido
264 \param childName Nombre del nodo hijo que estamos buscando.
265 \param exceptionWhenNotFound Indica el comportamiento en caso de no encontrar ningun nodo hijo que
266 coincida con el nombre buscado.
268 \return Referencia al nodo hijo que coincide con el nombre buscado. Si exceptionWhenNotFound es \em false
269 y ninguno de los hijos cumple con la busqueda sera NULL.
271 const Node* find(const char* childName, const bool exceptionWhenNotFound = true) const
272 throw(RuntimeException);
275 Crea un atributo que depende de este nodo.
276 \param name Nombre del atributo.
277 \param value Valor asociado al atributo.
278 \param _namespace Referencia al namespace al que pertenece el atributo. Puede ser NULL.
279 \return La instancia del nuevo atributo.
281 xml::Attribute* createAttribute(const char* name, const char* value, const Namespace* _namespace = NULL) throw();
284 Crea un atributo que depende de este nodo.
285 \param name Nombre del atributo.
286 \param value Valor asociado al atributo.
287 \param _namespace Referencia al namespace al que pertenece el atributo. Puede ser NULL.
288 \return La instancia del nuevo atributo.
290 xml::Attribute* createAttribute(const char* name, const std::string& value, const Namespace* _namespace = NULL) throw() {
291 return createAttribute(name, value.c_str(), _namespace);
295 Crea un atributo que depende de este nodo.
296 \param name Nombre del atributo.
297 \param value Valor asociado al atributo.
298 \param _namespace Referencia al namespace al que pertenece el atributo. Puede ser NULL.
299 \return La instancia del nuevo atributo.
301 xml::Attribute* createAttribute(const char* name, const int value, const Namespace* _namespace = NULL) throw() {
302 return createAttribute(name, anna::functions::asString(value), _namespace);
306 Crea un atributo que depende de este nodo.
307 \param name Nombre del atributo.
308 \param value Valor asociado al atributo. Pasamos como puntero para que no se creen ambiguedades
309 con el codigo escrito hasta ahora.
310 \param _namespace Referencia al namespace al que pertenece el atributo. Puede ser NULL.
311 \return La instancia del nuevo atributo.
313 xml::Attribute* createAttribute(const char* name, const Integer64* value, const Namespace* _namespace = NULL) throw() {
314 return createAttribute(name, anna::functions::asString(*value), _namespace);
318 Crea un atributo que depende de este nodo.
319 \param name Nombre del atributo.
320 \param value Valor asociado al atributo. Pasamos como puntero para que no se creen ambiguedades
321 con el codigo escrito hasta ahora.
322 \param _namespace Referencia al namespace al que pertenece el atributo. Puede ser NULL.
323 \return La instancia del nuevo atributo.
325 xml::Attribute* createAttribute(const char* name, const Unsigned64* value, const Namespace* _namespace = NULL) throw() {
326 return createAttribute(name, anna::functions::asString(*value), _namespace);
330 Crea el texto asociado a este nodo.
331 \param text contain Valor del texto asociado a este nodo.
332 \return La instancia del nuevo texto.
334 xml::Text* createText(const char* text) throw(RuntimeException);
337 Crea el texto asociado a este nodo.
338 \param text contain Valor del texto asociado a este nodo.
339 \return La instancia del nuevo texto.
341 xml::Text* createText(const std::string& text) throw(RuntimeException) { return createText(text.c_str()); }
344 Crea un nuevo nodo que depende de este.
345 \param name Nombre del nodo hijo.
347 Node* createChild(const char* name) throw();
350 * Crea un nuevo namespace (si procede) que podemos usar para asignar a los distintos nodos. Si el nodo ya existe y la referencia no coincide
351 * con la registrada se obtendrá una excepción.
353 * \param name Nombre del nuevo namespace.
354 * \param reference URI de la que obtener las definiciones.
355 * \return La instancia de un namespace con los parámetros indicados.
357 const Namespace* createNamespace(const char* name, const char* reference) throw(RuntimeException) {
358 std::string _name(name);
359 return createNamespace(_name, reference);
363 * Crea un nuevo namespace (si procede) que podemos usar para asignar a los distintos nodos. Si el nodo ya existe y la referencia no coincide
364 * con la registrada se obtendrá una excepción.
366 * \param name Nombre del nuevo namespace.
367 * \param reference URI de la que obtener las definiciones.
368 * \return La instancia de un namespace con los parámetros indicados.
370 const Namespace* createNamespace(const std::string& name, const char* reference) throw(RuntimeException);
373 * Establece el namespace asociado a este nodo.
374 * \param _namespace Instancia del namespace que vamos a asociar al nodo.
376 void setNamespace(const Namespace* _namespace) throw() { a_namespace = _namespace; }
379 * Devuelve la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL.
380 * \return la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL.
382 Namespace* namespace_find(const char* name, const bool exceptionWhenNotFound = true) throw(RuntimeException) {
383 const std::string _name(name);
384 return namespace_find(_name, exceptionWhenNotFound);
388 * Devuelve la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL.
389 * \return la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL.
391 Namespace* namespace_find(const std::string& name, const bool exceptionWhenNotFound = true) throw(RuntimeException);
394 * Devuelve la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL.
395 * \return la instancia del namespace que coincide con el nombre recibido como parámetro. Pueder ser NULL.
397 const Namespace* namespace_find(const char* name, const bool exceptionWhenNotFound = true) const throw(RuntimeException) {
398 return const_cast <Node*>(this)->namespace_find(name, exceptionWhenNotFound);
402 * Devuelve la instancia del namespace que coincide con el nombre recibido como parámetro. Puede ser NULL.
403 * \return la instancia del namespace que coincide con el nombre recibido como parámetro. Pueder ser NULL.
405 const Namespace* namespace_find(const std::string& name, const bool exceptionWhenNotFound = true) const throw(RuntimeException) {
406 return const_cast <Node*>(this)->namespace_find(name, exceptionWhenNotFound);
410 * Libera todos los componentes (atributos, namespaces y nodos hijos) asociados a este nodo.
412 void clear() throw();
415 Devuelve una cadena con toda la información relevante de esta instancia.
416 \return Una cadena con toda la información relevante de esta instancia.
418 std::string asString() const throw();
421 Devuelve la refencia al nodo sobre el que se encuentra el iterador pasado como
423 \param ii Iterador que estamos recorriendo.
424 \return La refencia al nodo sobre el que se encuentra el iterador pasado como
427 static Node* node(child_iterator& ii) throw() { return *ii; }
430 Devuelve la refencia al nodo sobre el que se encuentra el iterador pasado como parámetro.
431 \param ii Iterador que estamos recorriendo.
432 \return La refencia al nodo sobre el que se encuentra el iterador pasado como parámetro.
434 static const Node* node(const_child_iterator& ii) throw() { return *ii; }
437 Devuelve la refencia al atributo sobre el que se encuentra el iterador pasado como parámetro.
438 \param ii Iterador que estamos recorriendo.
439 \return La refencia al atributo sobre el que se encuentra el iterador pasado como parámetro.
441 static const Attribute* attribute(const_attribute_iterator& ii) throw() { return *ii; }
444 Devuelve la refencia al namespace sobre el que se encuentra el iterador pasado como parámetro.
445 \param ii Iterador que estamos recorriendo.
446 \return La refencia al namespace sobre el que se encuentra el iterador pasado como parámetro.
448 static const Namespace* xnamespace(const_namespace_iterator& ii) throw() { return namespace_container::data(ii);; }
452 Devuelve la refencia al atributo sobre el que se encuentra el iterador pasado como parámetro.
453 \param ii Iterador que estamos recorriendo.
454 \return La refencia al atributo sobre el que se encuentra el iterador pasado como parámetro.
456 static Attribute* attribute(attribute_iterator& ii) throw() { return *ii; }
460 const Node* a_parent;
463 Attributes a_attributes;
465 const Namespace* a_namespace;
467 // Esta instancia sólo la creará el nodo root.
468 namespace_container* a_namespaces;
470 typedef Recycler <Node> node_pool;
471 typedef Recycler <Attribute> attribute_pool;
472 typedef Recycler <Text> text_pool;
474 typedef Recycler <Namespace> namespace_pool;
476 node_pool* a_node_pool;
477 attribute_pool* a_attribute_pool;
478 text_pool* a_text_pool;
479 namespace_pool* a_namespace_pool;
481 /* Para evitar que se pueda crear desde el exterior */
484 void setRoot(Node* root) throw() { a_root = root; }
485 void setName(const char* name) throw() { a_name = name; }
487 static const Attribute* find(const char* attrName, const_attribute_iterator, const_attribute_iterator) throw();
490 friend class Allocator<Node>;
492 friend class Decompressor;