Updated license
[anna.git] / include / anna / xml / Node.hpp
1 // ANNA - Anna is Not Nothingness 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 #ifndef anna_xml_Node_hpp
38 #define anna_xml_Node_hpp
39
40 #include <vector>
41
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>
47
48 #include <anna/xml/Namespace.hpp>
49
50 namespace anna {
51
52 namespace xml {
53
54 class Parser;
55 class Attribute;
56 class Text;
57 class XPath;
58 class Decompressor;
59
60 /**
61    Nodo de documento XML.
62
63    Cada nodo puede tener una serie indeterminada de atributos y nodos hijos. Por ejemplo:
64
65    \code
66
67    <xvc HeartBeat="20000">
68       <broadcast>
69          <INetAddress Address="204.152.65.15" Port="2000"/>
70          <INetAddress Address="204.152.65.47" Port="2002"/>
71       </broadcast>
72
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"/>
76       </ethernet>
77    </xvc>
78
79    \endcode
80
81    El nodo \em xvc tiene un atributo (ver Attribute) llamado \em HeartBeat y dos nodos
82    hijos (\em broadcast y \em ethernet).
83 */
84 class Node {
85   struct NamespaceByName {
86     static const std::string& value(const Namespace* ns) throw() { return ns->getName(); }
87   };
88
89 public:
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 */
93
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 */
97
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;
101
102   /**
103      Constructor.
104      \param name Nombre del nodo.
105   */
106   Node(const char* name);
107
108   /**
109      Destructor.
110   */
111   virtual ~Node();
112
113   /**
114      Devuelve el nombre del nodo.
115      \return El nombre del nodo.
116   */
117   const char* getName() const throw() { return a_name.c_str(); }
118
119   /**
120    * Devuelve el nombre del nodo.
121    * \return El nombre del nodo.
122    */
123   const std::string& getNameAsString() const throw() { return a_name; }
124
125   /**
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.
128   */
129   const Node* getParent() const throw() { return a_parent; }
130
131   /**
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.
134   */
135   Node* getParent() throw() { return const_cast <Node*>(a_parent); }
136
137   /**
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.
144   */
145   const Attribute* getAttribute(const char* name, const bool exceptionWhenNotFound = true) const throw(anna::RuntimeException);
146
147   /**
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.
150   */
151   const Text* getText() const throw() { return a_text; }
152
153   /**
154    * Devuelve el namespace asociado a este nodo. Puede ser NULL.
155    * \return el namespace asociado a este nodo. Puede ser NULL.
156    */
157   const Namespace* getNamespace() const throw() { return a_namespace; }
158
159   /**
160      Devuelve un iterador al comienzo de la lista de nodo hijos.
161
162      A continuacion presentamos un ejemplo de como se recorreria lista de nodos
163      hijos de una determinado nodo.
164
165      \code
166
167      using namespace anna::xml;
168
169      Node* theNode = ... <establece un valor correcto> ...
170      Node* theChild;
171
172      for (Node::iterator ii = theNode->begin (), maxii = theNode->end (); ii != maxii; ii ++) {
173         theChild = Node::node (ii);
174
175         .... <Procesar el hijo> ....
176      }
177
178      \endcode
179
180      \return Un iterador al comienzo de la lista de nodo hijos.
181   */
182   child_iterator child_begin() throw() { return a_children.begin(); }
183
184   /**
185      Devuelve un iterador al comienzo de la lista de nodos hijos no modificables.
186
187      A continuacion presentamos un ejemplo de como se recorreria lista de nodos
188      hijos de una determinado nodo no modificable.
189
190      \code
191
192      using namespace anna::xml;
193
194      const Node* theNode = ... <establece un valor correcto> ...
195      const Node* theChild;
196
197      for (Node::const_iterator ii = theNode->begin (), maxii = theNode->end (); ii != maxii; ii ++) {
198         theChild = Node::node (ii);
199
200         .... <Procesar el hijo> ....
201      }
202
203      \endcode
204
205      \return Un iterador al comienzo de la lista de nodo hijos no modificables.
206   */
207   const_child_iterator child_begin() const throw() { return a_children.begin(); }
208
209   /**
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.
212   */
213   const_attribute_iterator attribute_begin() const throw() { return a_attributes.begin(); }
214
215   /**
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.
218   */
219   const_namespace_iterator namespace_begin() const throw() { return a_root->a_namespaces->begin(); }
220
221
222   /**
223      Devuelve un iterador al final de la lista de nodo hijos.
224      \return Un iterador al final de la lista de nodo hijos.
225      \see #child_begin
226   */
227   child_iterator child_end() throw() { return a_children.end(); }
228
229   /**
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.
232      \see #begin
233   */
234   const_child_iterator child_end() const throw() { return a_children.end(); }
235
236   /**
237    * Devuelve el número de hijos definidos.
238    * \return el número de hijos definidos.
239    */
240   int child_size() const throw() { return a_children.size(); }
241
242   /**
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.
245   */
246   const_attribute_iterator attribute_end() const throw() { return a_attributes.end(); }
247
248   /**
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.
251   */
252   const_namespace_iterator namespace_end() const throw() { return a_root->a_namespaces->end(); }
253
254   /**
255    * Devuelve el número de namespace definidos.
256    * \return el número de namespace definidos.
257    */
258   int namespace_size() const throw() { return a_root->a_namespaces->size(); }
259
260   /**
261      Busca un nodo sucesor directo de este cuyo nombre coincida con el nombre recibido
262      como parámetro.
263
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.
267
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.
270   */
271   const Node* find(const char* childName, const bool exceptionWhenNotFound = true) const
272   throw(RuntimeException);
273
274   /**
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.
280   */
281   xml::Attribute* createAttribute(const char* name, const char* value, const Namespace* _namespace = NULL) throw();
282
283   /**
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.
289   */
290   xml::Attribute* createAttribute(const char* name, const std::string& value, const Namespace* _namespace = NULL) throw() {
291     return createAttribute(name, value.c_str(), _namespace);
292   }
293
294   /**
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.
300   */
301   xml::Attribute* createAttribute(const char* name, const int value, const Namespace* _namespace = NULL) throw() {
302     return createAttribute(name, anna::functions::asString(value), _namespace);
303   }
304
305   /**
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.
312   */
313   xml::Attribute* createAttribute(const char* name, const S64* value, const Namespace* _namespace = NULL) throw() {
314     return createAttribute(name, anna::functions::asString(*value), _namespace);
315   }
316
317   /**
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.
324   */
325   xml::Attribute* createAttribute(const char* name, const U64* value, const Namespace* _namespace = NULL) throw() {
326     return createAttribute(name, anna::functions::asString(*value), _namespace);
327   }
328
329   /**
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.
333   */
334   xml::Text* createText(const char* text) throw(RuntimeException);
335
336   /**
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.
340   */
341   xml::Text* createText(const std::string& text) throw(RuntimeException) { return createText(text.c_str()); }
342
343   /**
344      Crea un nuevo nodo que depende de este.
345      \param name Nombre del nodo hijo.
346   */
347   Node* createChild(const char* name) throw();
348
349   /**
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.
352    *
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.
356    */
357   const Namespace* createNamespace(const char* name, const char* reference) throw(RuntimeException) {
358     std::string _name(name);
359     return createNamespace(_name, reference);
360   }
361
362   /**
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.
365    *
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.
369    */
370   const Namespace* createNamespace(const std::string& name, const char* reference) throw(RuntimeException);
371
372   /**
373    * Establece el namespace asociado a este nodo.
374    * \param _namespace Instancia del namespace que vamos a asociar al nodo.
375    */
376   void setNamespace(const Namespace* _namespace) throw() { a_namespace = _namespace; }
377
378   /**
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.
381    */
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);
385   }
386
387   /**
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.
390    */
391   Namespace* namespace_find(const std::string& name,  const bool exceptionWhenNotFound = true) throw(RuntimeException);
392
393   /**
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.
396    */
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);
399   }
400
401   /**
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.
404    */
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);
407   }
408
409   /**
410    * Libera todos los componentes (atributos, namespaces y nodos hijos) asociados a este nodo.
411    */
412   void clear() throw();
413
414   /**
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.
417   */
418   std::string asString() const throw();
419
420   /**
421      Devuelve la refencia al nodo sobre el que se encuentra el iterador pasado como
422      parámetro.
423      \param ii Iterador que estamos recorriendo.
424      \return La refencia al nodo sobre el que se encuentra el iterador pasado como
425      parámetro.
426   */
427   static Node* node(child_iterator& ii) throw() { return *ii; }
428
429   /**
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.
433   */
434   static const Node* node(const_child_iterator& ii) throw() { return *ii; }
435
436   /**
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.
440   */
441   static const Attribute* attribute(const_attribute_iterator& ii) throw() { return *ii; }
442
443   /**
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.
447   */
448   static const Namespace* xnamespace(const_namespace_iterator& ii) throw() { return namespace_container::data(ii);; }
449
450 protected:
451   /**
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.
455   */
456   static Attribute* attribute(attribute_iterator& ii) throw() { return *ii; }
457
458 private:
459   std::string a_name;
460   const Node* a_parent;
461   Node* a_root;
462   Children a_children;
463   Attributes a_attributes;
464   Text* a_text;
465   const Namespace* a_namespace;
466
467   // Esta instancia sólo la creará el nodo root.
468   namespace_container* a_namespaces;
469
470   typedef Recycler <Node> node_pool;
471   typedef Recycler <Attribute> attribute_pool;
472   typedef Recycler <Text> text_pool;
473
474   typedef Recycler <Namespace> namespace_pool;
475
476   node_pool* a_node_pool;
477   attribute_pool* a_attribute_pool;
478   text_pool* a_text_pool;
479   namespace_pool* a_namespace_pool;
480
481   /* Para evitar que se pueda crear desde el exterior */
482   Node();
483
484   void setRoot(Node* root) throw() { a_root = root; }
485   void setName(const char* name) throw() { a_name = name; }
486
487   static const Attribute* find(const char* attrName, const_attribute_iterator, const_attribute_iterator) throw();
488
489   friend class Parser;
490   friend class Allocator<Node>;
491   friend class XPath;
492   friend class Decompressor;
493 };
494
495 }
496 }
497
498 #endif