Add missing files
[gmpc-magnatune.git] / src / axl / axl_node.c
blobe15545e8cd51a5a552aaf37cd872a2d53d8bb0a2
1 /**
2 * LibAxl: Another XML library
3 * Copyright (C) 2006 Advanced Software Production Line, S.L.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free
17 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 * 02111-1307 USA
20 * You may find a copy of the license under this software is released
21 * at COPYING file. This is LGPL software: you are welcome to
22 * develop proprietary applications using this library without any
23 * royalty or fee but returning back any change, improvement or
24 * addition in the form of source code, project image, documentation
25 * patches, etc.
27 * For commercial support on build XML enabled solutions contact us:
29 * Postal address:
30 * Advanced Software Production Line, S.L.
31 * C/ Dr. Michavila NÂș 14
32 * Coslada 28820 Madrid
33 * Spain
35 * Email address:
36 * info@aspl.es - http://fact.aspl.es
39 #include <axl.h>
40 #define LOG_DOMAIN "axl-node"
42 /**
43 * \defgroup axl_node_module Axl Node: Xml node interface functions to use and manipulate xml nodes inside documents.
46 /**
47 * \addtogroup axl_node_module
48 * @{
51 struct _axlAttrCursor {
52 axlPointer data;
53 int count;
54 axlNode * node;
57 /**
58 * @internal Axl content representation used to store comments, xml
59 * content, CDATA content and entity references.
61 typedef struct _axlNodeContent axlNodeContent;
63 struct _axlNodeContent {
64 /**
65 * @internal
67 * @brief Pointer which holds current content inside the xml
68 * node.
70 char * content;
71 /**
72 * @internal
74 * @brief Current content size stored on the given axlNode.
76 int content_size;
80 /**
81 * @internal Type representation to hold node attributes while they
82 * are fewer.
84 typedef struct _axlNodeAttr axlNodeAttr;
86 struct _axlNodeAttr {
87 /**
88 * @internal Node attribute name.
90 char * attribute;
92 /**
93 * @internal Node attribute value.
95 char * value;
97 /**
98 * @internal Flags the attribute pair to be considered from a
99 * factory.
101 bool from_factory;
103 /**
104 * @internal Next attribute.
106 axlNodeAttr * next;
109 /**
110 * @internal Function that allows to copy all attributes found on the
111 * list received.
113 * @param list The attribute list to copy.
115 * @return A newly allocated attribute list.
117 axlNodeAttr * __axl_node_copy_attr_list (axlNodeAttr * list)
119 axlNodeAttr * result = NULL;
121 /* if the list isn't defined, return NULL */
122 if (list == NULL)
123 return NULL;
125 /* alloc memory to hold attribute name and value, and
126 * copy it from the list */
127 result = axl_new (axlNodeAttr, 1);
128 result->attribute = axl_strdup (list->attribute);
129 result->value = axl_strdup (list->value);
131 /* call to copy the rest of the list */
132 result->next = __axl_node_copy_attr_list (list->next);
134 /* return result created */
135 return result;
138 /**
139 * @internal Deallocs the attribute list received.
141 * @param list The attribute list to copy.
143 * @return A newly allocated attribute list.
145 void __axl_node_free_attr_list (axlNodeAttr * attr)
147 axlNodeAttr * next;
149 /* if the list isn't defined, return NULL */
150 if (attr == NULL)
151 return;
153 /* copy all nodes */
154 while (attr != NULL) {
155 /* get the next attribute */
156 next = attr->next;
158 /* free attribute description */
159 if (! attr->from_factory) {
160 axl_free (attr->attribute);
161 axl_free (attr->value);
162 axl_free (attr);
163 } /* end if */
165 /* get the next */
166 attr = next;
168 } /* end while */
170 /* return result created */
171 return;
174 /**
175 * @internal Function that allows to now if both lists represents the
176 * same set of attributes, even if they aren't ordered using the same.
178 * @param attr The first attribute pointing to the rest of the
179 * attribute list.
181 * @param attr2 The second attribute pointing to the rest of the
182 * attribute list.
184 * @return \ref true if both lists are equal, otherwise \ref false is
185 * returned.
187 bool __axl_node_attr_list_is_equal (axlNodeAttr * attr, axlNodeAttr * attr2)
189 axlNodeAttr * attrAux;
190 bool found;
192 /* for each attribute found in the attribute list, check it on
193 * the second list */
194 while (attr != NULL) {
196 attrAux = attr2;
197 found = false;
198 while (attrAux != NULL) {
200 /* check attribute */
201 if (axl_cmp (attrAux->attribute, attr->attribute) &&
202 axl_cmp (attrAux->value, attr->value)) {
203 /* attribute found, break the loop */
204 found = true;
205 break;
208 /* next attribute */
209 attrAux = attrAux->next;
211 } /* end while */
213 /* check if the attribute was found */
214 if (! found )
215 return false;
217 /* get the next */
218 attr = attr->next;
220 } /* end while */
222 /* all attributes was found, including its values, so, the
223 * list is equal */
224 return true;
227 typedef enum {
228 /**
229 * @internal Signal axl library that the node was allocated by
230 * a factory not by the system alloc.
232 NODE_FROM_FACTORY = 1,
234 /**
235 * @internal Signal axl library that the node node was
236 * allocated by a factory not by the system alloc.
238 NODE_NAME_FROM_FACTORY = 1 << 2
239 } axlNodeConf;
241 struct _axlNode {
242 /**
243 * @internal
245 * Node name that is the value found at the very begining of
246 * the node definition <name.../>
248 char * name;
250 /**
251 * @internal Number of attributes stored. This value is used
252 * to now if the attributes are stored using a hash or a
253 * linked list. In the case it is equal or greater than 11, a
254 * hash is used to store attribute. Otherwise, a linked list
255 * (using axlAttrNode) is used.
257 int attr_num;
259 /**
260 * @internal
261 * @brief The attributes this node has.
263 axlPointer * attributes;
266 * @internal A reference to the frist child.
268 axlItem * first;
270 /**
271 * @internal A reference to the last child.
273 axlItem * last;
276 * @internal A hash used to store arbitrary data associated to
277 * the node.
279 axlHash * annotate_data;
281 /**
282 * @internal Internal reference to the holder axlItem
283 * containing the axl node reference.
285 axlItem * holder;
287 /**
288 * @internal Value that contains flags for configuration.
290 int conf;
293 struct _axlItem {
294 /**
295 * @internal A reference to the type that is being hold by the
296 * encapsulation reference.
298 AxlItemType type;
300 /**
301 * @internal The reference to the pointer that is actually
302 * stored.
304 axlPointer data;
306 /**
307 * @internal
308 * A pointer to the parent node.
310 axlNode * parent;
312 /**
313 * @internal
315 * A pointer to the brother node, the node that is found on
316 * the next position.
318 axlItem * next;
320 /**
321 * @internal Stores a reference to the previous node inside
322 * the same level.
324 axlItem * previous;
326 /**
327 * @internal
329 * Internal reference to the whole xml document where the node
330 * is contained.
332 axlDoc * doc;
335 /**
336 * @internal
338 * @brief Internal position function which ensures that nodes added
339 * will be added at the end of the list.
341 int __axl_node_equal (axlPointer a, axlPointer b)
343 return 1;
346 /**
347 * @internal
349 * Internal function which allocates the enough memory to copy
350 * received content changing all escape sequences.
352 char * __axl_node_content_copy_and_escape (const char * content,
353 int content_size,
354 int additional_size)
356 int iterator = 0;
357 int iterator2 = 0;
358 char * result;
359 axl_return_val_if_fail (content, false);
361 /* allocate the memory to be returned */
362 result = axl_new (char, content_size + additional_size + 1);
364 /* iterate over all content defined */
365 while (iterator2 < content_size) {
366 /* check for &apos; */
367 if (content [iterator2] == '\'') {
368 memcpy (result + iterator, "&apos;", 6);
369 iterator += 6;
370 iterator2++;
371 continue;
374 /* check for &quot; */
375 if (content [iterator2] == '"') {
376 memcpy (result + iterator, "&quot;", 6);
377 iterator += 6;
378 iterator2++;
379 continue;
382 /* check for &amp; */
383 if (content [iterator2] == '&') {
384 memcpy (result + iterator, "&amp;", 5);
385 iterator += 5;
386 iterator2++;
387 continue;
390 /* check for &gt; */
391 if (content [iterator2] == '>') {
392 memcpy (result + iterator, "&gt;", 4);
393 iterator += 4;
394 iterator2++;
395 continue;
398 /* check for &lt; */
399 if (content [iterator2] == '<') {
400 memcpy (result + iterator, "&lt;", 4);
401 iterator += 4;
402 iterator2++;
403 continue;
406 /* copy value received because it is not an escape
407 * sequence */
408 memcpy (result + iterator, content + iterator2, 1);
410 /* update the iterator */
411 iterator++;
412 iterator2++;
415 /* return results */
416 return result;
419 /**
420 * @internal
423 * Internal function which replaces all entity references to its
424 * corresponding values. Initially, this function only implements
425 * translation for default recognized entities (&, <, >, ' and ").
427 * Because the pattern substitution applied on this operation makes
428 * not necessary to allocate memory, the function return the same
429 * string received, but with all values replaced.
431 char * __axl_node_content_translate_defaults (char * content,
432 int * content_size)
434 int iterator = 0;
435 int iterator2 = 0;
437 axl_return_val_if_fail (content, false);
439 /* iterate over all content defined */
440 while (iterator < (*content_size)) {
442 /* check for &apos; */
443 if (axl_stream_cmp (content + iterator, "&apos;", 6)) {
444 content [iterator2] = '\'';
445 iterator2++;
447 iterator += 6;
448 continue;
451 /* check for &quot; */
452 if (axl_stream_cmp (content + iterator, "&quot;", 6)) {
453 content [iterator2] = '"';
454 iterator2++;
456 iterator += 6;
457 continue;
460 /* check for &amp; */
461 if (axl_stream_cmp (content + iterator, "&amp;", 5)) {
462 content [iterator2] = '&';
463 iterator2++;
465 iterator += 5;
466 continue;
469 /* check for &gt; */
470 if (axl_stream_cmp (content + iterator, "&gt;", 4)) {
471 content [iterator2] = '>';
472 iterator2++;
474 iterator += 4;
475 continue;
478 /* check for &lt; */
479 if (axl_stream_cmp (content + iterator, "&lt;", 4)) {
480 content [iterator2] = '<';
481 iterator2++;
483 iterator += 4;
484 continue;
487 /* copy move the content */
488 if (iterator2 != iterator)
489 content [iterator2] = content [iterator];
491 /* update the iterator */
492 iterator++;
493 iterator2++;
496 /* return results, setting the new content size */
497 *content_size = iterator2;
498 content [iterator2] = 0;
499 return content;
504 /**
505 * @brief Creates a new \ref axlNode with the provided name.
507 * The function will perform a new local copy for the reference
508 * received. See also \ref axl_node_create_ref for an explanation
509 * about saving memory.
511 * @param name The name to be used for the node be created. The
512 * function doesn't check if the paramater received is null.
514 * @return A newly allocate \ref axlNode reference, that must be
515 * deallocated by \ref axl_node_free.
517 axlNode * axl_node_create (const char * name)
520 axlNode * node;
522 /* init the node */
523 node = axl_new (axlNode, 1);
524 node->name = axl_strdup (name);
526 return node;
529 /**
530 * @brief This function allows to create a xml node from the provided
531 * xml content.
533 * This function is useful if it is required to create a node with a
534 * particular complex content, without going into the detail of
535 * creating all childs, attributes and content.
537 * Here is an example:
538 * \code
539 * axlError * error = NULL;
540 * axlNode * node = NULL;
542 * // parse document
543 * root = axl_node_parse_strings (error,
544 * "<child>",
545 * " <widget class=\"GtkLabel\" id=\"label4\">",
546 * " <property name=\"visible\">True</property>",
547 * " <property name=\"label\" translatable=\"yes\">&lt;b&gt;1. Seleccione el sistema:&lt;/b&gt;</property>",
548 * " <property name=\"use_underline\">False</property>",
549 * " <property name=\"use_markup\">True</property>",
550 * " <property name=\"justify\">GTK_JUSTIFY_LEFT</property>",
551 * " <property name=\"wrap\">False</property>",
552 * " <property name=\"selectable\">False</property>",
553 * " <property name=\"xalign\">0</property>",
554 * " <property name=\"yalign\">0.5</property>",
555 * " <property name=\"xpad\">0</property>",
556 * " <property name=\"ypad\">0</property>",
557 * " <property name=\"ellipsize\">PANGO_ELLIPSIZE_NONE</property>",
558 * " <property name=\"width_chars\">-1</property>",
559 * " <property name=\"single_line_mode\">False</property>",
560 * " <property name=\"angle\">0</property>",
561 * " </widget>",
562 * " <packing>",
563 * " <property name=\"padding\">0</property>",
564 * " <property name=\"expand\">False</property>",
565 * " <property name=\"fill\">False</property>",
566 * " </packing>",
567 * "</child>",
568 * NULL);
569 * if (root == NULL) {
570 * printf ("Error: unable to parse content, error: %s\n", axl_error_get (error));
571 * axl_error_free (error);
572 * return;
575 * // once finished, free the node
576 * axl_node_free (root);
577 * \endcode
579 * @param error Optional error reference to report parsing error problems that can be found.
581 * The function receives a set of strings, separate by comma, ended by
582 * NULL.
584 * @return A newly allocated reference to the \ref axlNode or NULL if
585 * it fails. In such case, the error variable is filled with the error
586 * found.
588 axlNode * axl_node_parse_strings (axlError ** error, ...)
590 axlDoc * doc;
591 axlNode * root;
592 va_list args;
593 char * string = NULL;
594 char * stream = NULL;
595 char * stream_aux = NULL;
597 /* check incoming data */
598 axl_return_val_if_fail (error, NULL);
600 /* open the stdargs */
601 va_start (args, error);
603 while ((string = va_arg (args, char *)) != NULL) {
604 stream_aux = stream;
605 stream = axl_stream_concat (stream, string);
606 if (stream_aux != NULL) {
607 axl_free (stream_aux);
608 stream_aux = NULL;
612 /* close the stdargs */
613 va_end (args);
615 /* check that we have received, at least, an string
616 * parseable */
617 if (stream == NULL)
618 return NULL;
620 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "string to parse: %s", stream);
622 /* parse the string */
623 doc = axl_doc_parse (stream, -1, error);
624 if (doc == NULL) {
625 /* free document */
626 axl_free (stream);
627 return NULL;
630 /* free the stream */
631 axl_free (stream);
633 /* deattach the root node */
634 root = axl_doc_get_root (doc);
635 axl_node_deattach (root);
637 /* do not free the document, rather, store it to be
638 * deallocated by the node just after it is deallocated. */
639 axl_node_annotate_data_full (root, "__root_document", NULL, doc, (axlDestroyFunc) axl_doc_free);
641 /* return the node created */
642 return root;
645 /**
646 * @brief Allows to create a complete node configuring not only the
647 * node but its content, using a printf-like format.
649 * This handy function, like \ref axl_node_parse_strings, allows to
650 * create complex xml structures providing the inline content.
652 * Here is an example:
653 * \code
654 * axlNode * node = axl_node_parse (NULL, "<content attr='value' attr2='value'>This is content</content>");
655 * \endcode
657 * The previous call will create a node called <b>content</b> with the
658 * provided attributes and content, in one step.
660 * The node returned can be integrated into a xml document using usual
661 * API, for example: \ref axl_node_set_child or \ref axl_doc_set_root.
663 * @param error The optional error reference holding the returned
664 * result.
666 * @param content The content to be used to create the node.
668 * @return A reference to a newly allocated \ref axlNode or NULL if it
669 * fails. The \ref axlError is filled with the error found if provided
670 * by the caller.
672 axlNode * axl_node_parse (axlError ** error, const char * content, ...)
674 char * _content;
675 va_list args;
676 axlDoc * doc;
677 axlNode * root;
679 /* open the stdargs */
680 va_start (args, content);
682 /* create the content */
683 _content = axl_strdup_printfv (content, args);
685 /* close the stdargs */
686 va_end (args);
688 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "parsing document:\n %s", _content);
690 /* parse the string */
691 doc = axl_doc_parse (_content, -1, error);
692 if (doc == NULL) {
693 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "failed to parse document:\n %s", _content);
695 /* free document */
696 axl_free (_content);
698 return NULL;
701 /* free the content */
702 axl_free (_content);
704 /* deattach the root node */
705 root = axl_doc_get_root (doc);
706 axl_node_deattach (root);
708 /* do not free the document, rather, store it to be
709 * deallocated by the node just after it is deallocated. */
710 axl_node_annotate_data_full (root, "__root_document", NULL, doc, (axlDestroyFunc) axl_doc_free);
712 /* return the node created */
713 return root;
717 /**
718 * @brief Creates a new \ref axlNode but using the memory passed in by
719 * the name reference.
721 * This function works the same way like \ref axl_node_create, but
722 * previous one makes a local copy for the name provided. This means
723 * that, if you have allocated the reference being passed, the
724 * previous function will allocate again memory for the name
725 * reference.
727 * Obviously, for a few xml nodes this have none or little effect but,
728 * if your xml document have 100.000 nodes you save 100.000 extra
729 * memory allocations and deallocations. This have a great impact in
730 * the long term impact of your programm because memory fragmentation
731 * is kept as low as possible.
733 * Keep in mind that this function should not be used for static names
734 * declared on the code. Example:
735 * \code
736 * // propery node creation
737 * axlNode * node = axl_node_create ("test");
739 * // NOT PROPER node creation
740 * axlNode * node = axl_node_create_ref ("test");
741 * \endcode
743 * @param name A reference to the node name that is hold by
744 * dinamically allocated memory from the user space code. The function
745 * doesn't check if the parameter received is null.
747 * @return A newly created \ref axlNode reference that must be
748 * deallocated by \ref axl_node_free.
750 axlNode * axl_node_create_ref (char * name)
752 axlNode * node;
754 /* init the node */
755 node = axl_new (axlNode, 1);
756 node->name = name;
758 /* return a reference to a new axlNode */
759 return node;
762 /**
763 * @brief Allows to configure the node name, using the value provided.
765 * The function will dealloc the previous name stored, if found.
767 * @param node The node to be configured with a new name.
769 * @param name The new name to configure to the node. The value
770 * provided will be allocated, to create a local copy. The function
771 * won't check the name parameter received to be a non-null pointer.
773 void axl_node_set_name (axlNode * node, const char * name)
775 /* check the name to be already configured and dealloc it */
776 if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
777 axl_free (node->name);
779 /* alloc the new name */
780 node->name = axl_strdup (name);
782 return;
785 /**
786 * @brief Allows to configure the node name, using the value provided
787 * as a reference allocated and to be owned by the node.
789 * The function will dealloc the previous name stored, if found.
791 * @param node The node to be configured with a new name.
793 * @param name The new name to configure to the node. The value
794 * provided will be owned by the node. The function won't check the
795 * name parameter received to be a non-null pointer.
797 void axl_node_set_name_ref (axlNode * node, char * name)
799 /* check the name to be already configured and dealloc it */
800 if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
801 axl_free (node->name);
803 /* alloc the new name */
804 node->name = name;
806 return;
809 /**
810 * @internal Allows to configure the xml node, flaging the string
811 * received to be owned by a factory. Do not use this API from your
812 * application. This is only useful for Axl Library internals.
814 * @param node The xml node that is going to be configured.
816 * @param name The xml node name to be configured. Previous
817 * configuration won't be deallocated as it is supposed that this
818 * function is only used from inside axl library.
820 void axl_node_set_name_from_factory (axlNode * node, char * name)
822 /* set node name */
823 node->name = name;
825 /* update configuration */
826 node->conf |= NODE_NAME_FROM_FACTORY;
828 return;
831 axlPointer __axl_node_copy_key (axlPointer key, axlDestroyFunc key_destroy,
832 axlPointer data, axlDestroyFunc data_destroy)
834 /* copy the key */
835 return axl_strdup (key);
838 axlPointer __axl_node_copy_value (axlPointer key, axlDestroyFunc key_destroy,
839 axlPointer data, axlDestroyFunc data_destroy)
841 /* copy data */
842 return axl_strdup (data);
845 /**
846 * @brief Allows to perform a copy operation for the provided node.
848 * The function can perform a simple copy, without attributes and
849 * childs, if both attributes are false. If the copy attributes and
850 * copy childs are activated, childs copied will have attributes
851 * copied.
853 * @param node The node source of information.
855 * @param copy_attributes Signals the function to copy node attributes
856 * into the newly created node.
858 * @param copy_childs Signals the function to copy childs for the
859 * source node.
861 * @return A newly created node copy or null if it fails. The function
862 * will fail if the node reference provided is null.
864 axlNode * axl_node_copy (axlNode * node,
865 bool copy_attributes,
866 bool copy_childs)
868 axlNode * result;
869 axlItem * child;
870 axlItem * copy;
873 axl_return_val_if_fail (node, NULL);
875 /* create the copy */
876 result = axl_node_create (axl_node_get_name (node));
878 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node=<%s> (copy operation)",
879 result->name);
881 /* check for attributes */
882 if (node->attributes != NULL && copy_attributes) {
884 /* copy attribute configuration and attributes */
885 result->attr_num = node->attr_num;
886 if (node->attr_num >= 11) {
887 /* copy attribute list supposing it is a
888 * hash */
889 result->attributes = (axlPointer) axl_hash_copy ((axlHash *) node->attributes,
890 /* key copy function */
891 __axl_node_copy_key,
892 /* value copy function */
893 __axl_node_copy_value);
894 } else {
895 /* copy attribute list */
896 result->attributes = (axlPointer) __axl_node_copy_attr_list ((axlNodeAttr *) node->attributes);
900 /* check if child nodes must be also copied */
901 if (copy_childs && (node->first != NULL)) {
903 /* copy all content inside */
904 child = node->first;
905 while (child != NULL) {
907 /* copy the child found */
908 copy = axl_item_copy (child, result);
910 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, " new item created (copy operation) with parent=<%s> and type=%d",
911 copy->parent->name,
912 axl_item_get_type (copy));
914 /* set the content */
915 axl_item_set_child_ref (result, copy);
917 /* get the next element */
918 child = child->next;
920 } /* end while */
921 } /* end if */
924 /* return the node created */
925 return result;
928 /**
929 * @brief Allows to get the xml document (\ref axlDoc) where the
930 * provided xml node is stored.
932 * @param node The node that is being requested to return is xml
933 * document reference.
935 * @return The xml document reference or NULL if it is not already
936 * set. Once a xml node is created, it must be added to the xml
937 * document either because it is the parent node, in that case \ref
938 * axl_doc_set_root must be used, or either because the node is being
939 * added as a child of a xml node that is the already added root node
940 * or a child of it.
942 axlDoc * axl_node_get_doc (axlNode * node)
944 axl_return_val_if_fail (node, NULL);
946 /* return the internal reference */
947 return axl_item_get_doc (node->holder);
950 /**
951 * @internal
953 * This function is not provided to the public API because it is used
954 * by the Axl internals to set the root node for a provided xml node,
955 * that is usually the root document xml node.
957 * @param node The node that is being configured to have, or being contained in, the provided xml document.
959 * @param doc The xml document that holds the node.
961 void axl_node_set_doc (axlNode * node, axlDoc * doc)
963 axlItem * item;
965 axl_return_if_fail (node);
966 axl_return_if_fail (doc);
968 /* get the item reference */
969 item = node->holder;
971 if (item == NULL) {
973 /* create an empty reference */
974 item = axl_item_factory_get (axl_doc_get_item_factory (doc));
975 item->type = ITEM_NODE | ITEM_FROM_FACTORY;
976 item->data = node;
977 node->holder = item;
979 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node received doesn't have a holder reference, creating ref=0x%x, node=0x%x, type=%d",
980 item, node, item->type);
981 } /* end if */
983 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting doc to the item node");
985 /* call to set item at the document */
986 item->doc = doc;
988 return;
992 /**
993 * @internal
995 * Support function to install attribute information provided into the
996 * \ref axlNode provided.
998 void __axl_node_set_attribute (axlFactory * factory,
999 axlNode * node,
1000 char * attribute,
1001 char * value,
1002 bool from_factory)
1004 axlNodeAttr * attr;
1005 axlNodeAttr * next;
1007 /* init attribute list */
1008 /* do not init attribute list twice */
1009 if (node->attributes == NULL) {
1010 /* configure default axl attribute list */
1011 node->attr_num = 1;
1013 /* create the node */
1014 if (from_factory)
1015 attr = axl_factory_get (factory);
1016 else
1017 attr = axl_new (axlNodeAttr, 1);
1018 attr->from_factory = from_factory;
1019 attr->attribute = attribute;
1020 attr->value = value;
1022 /* store the node */
1023 node->attributes = (axlPointer) attr;
1025 return;
1028 /* store the attribute using the general case */
1029 if (node->attr_num < 10) {
1031 /* create the node */
1032 if (from_factory)
1033 attr = axl_factory_get (factory);
1034 else
1035 attr = axl_new (axlNodeAttr, 1);
1036 attr->from_factory = from_factory;
1037 attr->attribute = attribute;
1038 attr->value = value;
1040 /* set the next to the new item to be the current first */
1041 attr->next = (axlNodeAttr *) node->attributes;
1043 /* set the new first */
1044 node->attributes = (axlPointer) attr;
1046 } else if (node->attr_num >= 10) {
1048 /* check if we have to translate current attributes */
1049 if (node->attr_num == 10) {
1050 /* get a reference to current attribute list */
1051 attr = (axlNodeAttr *) node->attributes;
1053 /* create the hash */
1054 node->attributes = (axlPointer) axl_hash_new_full (axl_hash_string, axl_hash_equal_string, 1);
1056 while (attr != NULL) {
1057 /* add the attribute */
1058 axl_hash_insert_full ((axlHash *) node->attributes,
1059 /* attribute name */
1060 attr->attribute, attr->from_factory ? NULL : axl_free,
1061 /* attribute value */
1062 attr->value, attr->from_factory ? NULL : axl_free);
1063 /* free current node */
1064 next = attr->next;
1065 if (! attr->from_factory)
1066 axl_free (attr);
1068 /* get the next item to store */
1069 attr = next;
1070 } /* end while */
1072 } /* end if */
1074 /* add the attribute */
1075 axl_hash_insert_full ((axlHash *) node->attributes,
1076 attribute, from_factory ? NULL : axl_free,
1077 value, from_factory ? NULL : axl_free);
1079 } /* end if */
1081 /* update attribute count */
1082 node->attr_num++;
1084 return;
1087 /**
1088 * @brief Allows to configure an xml attribute to the given node.
1090 * Attributes are that piece of the xml node definition that is
1091 * defined the by pair attr=value. Here is an example of an xml node
1092 * with an attribute:
1094 * \code
1095 * <complex attr1='value'>
1096 * ..
1097 * </complex>
1098 * \endcode
1100 * It is not permited to store the same attributes several times
1101 * inside the same node. If the function detects that a node is being
1102 * set to have the same attribute name several times, the attribute
1103 * will not be added.
1105 * Values for the attribute name (<b>attribute</b>) and its value can
1106 * be deallocated once the function finish. This function will perform
1107 * a local copy.
1109 * @param node The \ref axlNode where the attribute will be installed
1111 * @param attribute The attribute name to configure. This value can't
1112 * be NULL.
1114 * @param value The value associated to the attribute to be
1115 * configured. This value can't be NULL.
1117 void axl_node_set_attribute (axlNode * node,
1118 const char * attribute,
1119 const char * value)
1121 int additional_size = 0;
1122 char * _attr;
1123 char * _value;
1125 axl_return_if_fail (node);
1126 axl_return_if_fail (attribute);
1127 axl_return_if_fail (value);
1129 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting attribute: %s='%s'", attribute, value);
1131 /* check attribute name */
1132 if (axl_node_has_invalid_chars (attribute, strlen (attribute),
1133 &additional_size)) {
1135 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found attribute content with escapable, non-valid content");
1136 _attr = __axl_node_content_copy_and_escape (attribute,
1137 strlen (attribute),
1138 additional_size);
1139 }else {
1141 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "'%s' is a valid string..", attribute);
1142 _attr = axl_strdup (attribute);
1145 /* check attribute value */
1146 additional_size = 0;
1147 if (axl_node_has_invalid_chars (value, strlen (value),
1148 &additional_size)) {
1150 _value = __axl_node_content_copy_and_escape (value,
1151 strlen (value),
1152 additional_size);
1153 }else {
1155 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "'%s' is a valid string..", value);
1156 _value = axl_strdup (value);
1159 /* insert the attribute */
1160 __axl_node_set_attribute (NULL, node, _attr, _value, false);
1161 return;
1164 /**
1165 * @brief Allows to install a new attribute pair, based on the
1166 * attribute name and the attribute value, without allocating memory
1167 * for them.
1169 * This function works the same way like \ref axl_node_set_attribute
1170 * but reusing memory allocated by the user space to avoid allocating
1171 * information twice.
1173 * @param node The \ref axlNode where the attributes will be
1174 * installed.
1176 * @param attribute The attribute name to be installed.
1178 * @param value The attribute value to be installed.
1180 void axl_node_set_attribute_ref (axlNode * node, char * attribute, char * value)
1183 axl_return_if_fail (node);
1184 axl_return_if_fail (attribute);
1185 axl_return_if_fail (value);
1187 /* insert the attribute */
1188 __axl_node_set_attribute (NULL, node, attribute, value, false);
1190 return;
1193 /**
1194 * @internal Function that allows configuring attributes to the
1195 * selected node, notifying that they come from a factory and
1196 * shouldn't be deallocated in the usual way. This function shouldn't
1197 * be used by API consumers. This is only useful for Axl Library
1198 * internals.
1200 * @param node The node to be configured with the attribute values.
1202 * @param attribute The attribute to configure.
1203 * @param value The attribute value to configure.
1205 void axl_node_set_attribute_from_factory (axlFactory * factory,
1206 axlNode * node,
1207 char * attribute,
1208 char * value)
1210 /* insert the attribute */
1211 __axl_node_set_attribute (factory, node, attribute, value, true);
1213 return;
1216 /**
1217 * @brief Allows to check if a particular attribute is installed on
1218 * the given node.
1220 * @param node The node where the attribute will be checked to be
1221 * configured.
1223 * @param attribute The attribute to check.
1225 * @return A \ref true if the attribute value is set, otherwise
1226 * \ref false is returned.
1228 bool axl_node_has_attribute (axlNode * node, const char * attribute)
1230 axlNodeAttr * attr;
1232 axl_return_val_if_fail (node, false);
1233 axl_return_val_if_fail (attribute, false);
1235 /* check for empty hash */
1236 if (node->attributes == NULL)
1237 return false;
1239 if (node->attr_num <= 10) {
1240 /* linked configuration */
1241 attr = (axlNodeAttr *) node->attributes;
1242 while (attr != NULL) {
1243 /* check that the attribute is equal */
1244 if (axl_cmp (attr->attribute, attribute))
1245 return true;
1247 /* get the next attribute */
1248 attr = attr->next;
1249 } /* end while */
1251 /* attribute not found */
1252 return false;
1253 } /* end if */
1255 /* hashed configuration */
1256 return axl_hash_exists ((axlHash *) node->attributes, (axlPointer) attribute);
1259 /**
1260 * @brief Allows to remove the attribute provided, from the node
1261 * provided.
1263 * @param node The node that will be updated by removing the attribute
1264 * provided.
1266 * @param attribute The attribute to locate and remove.
1268 void axl_node_remove_attribute (axlNode * node,
1269 const char * attribute)
1271 axlNodeAttr * attr;
1272 axlNodeAttr * previous;
1274 axl_return_if_fail (node);
1275 axl_return_if_fail (attribute);
1277 /* check for empty hash */
1278 if (node->attributes == NULL)
1279 return;
1281 if (node->attr_num <= 10) {
1282 /* linked configuration */
1283 attr = (axlNodeAttr *) node->attributes;
1284 previous = NULL;
1285 while (attr != NULL) {
1286 /* check that the attribute is equal */
1287 if (axl_cmp (attr->attribute, attribute)) {
1288 /* attribute found */
1289 if (previous == NULL)
1290 node->attributes = (axlPointer) attr->next;
1291 else
1292 previous->next = attr->next;
1294 /* do not decrease attribute number
1295 * since it is used to know the kind
1296 * of store used. */
1298 /* now dealloc the attribute */
1299 if (! attr->from_factory) {
1300 axl_free (attr->attribute);
1301 axl_free (attr->value);
1302 axl_free (attr);
1303 } /* end if */
1305 return;
1308 /* get the next attribute */
1309 previous = attr;
1310 attr = attr->next;
1311 } /* end while */
1313 /* attribute not found */
1314 return;
1315 } /* end if */
1317 /* hashed configuration */
1318 axl_hash_remove ((axlHash *) node->attributes, (axlPointer) attribute);
1320 /* do not decrease attribute number
1321 * since it is used to know the kind
1322 * of store used. */
1324 return;
1327 /**
1328 * @brief Allows to get the number of attributes installed on the
1329 * provided node.
1331 * @param node The node that is requested to return the number of
1332 * attributes installed.
1334 * @return Attributes installed, or -1 if it fails.
1336 int axl_node_num_attributes (axlNode * node)
1338 int result = 0;
1339 axlNodeAttr * attr;
1341 axl_return_val_if_fail (node, -1);
1343 if (node->attr_num <= 10) {
1344 /* linked configuration */
1345 attr = (axlNodeAttr *) node->attributes;
1346 while (attr != NULL) {
1347 /* update sum */
1348 result++;
1350 /* get the next attribute */
1351 attr = attr->next;
1352 } /* end while */
1354 /* attribute not found */
1355 return result;
1356 } /* end if */
1358 /* hashed configuration */
1359 return axl_hash_items ((axlHash *) node->attributes);
1362 /**
1363 * @brief Allows to check if the provided has any attribute installed.
1365 * @param node The node to be checked for attributes.
1367 * @return \ref true if the node has attributes, otherwise \ref false
1368 * is returned. The function also returns \ref false if a null
1369 * reference for the node is provided.
1371 bool axl_node_has_attributes (axlNode * node)
1373 axl_return_val_if_fail (node, false);
1375 /* return if the attributes reference is configured */
1376 return (node->attributes != NULL);
1379 /**
1380 * @brief Allows to get current content of the provided attribute
1381 * inside the given node.
1383 * It is recomended to call first to \ref axl_node_has_attribute to
1384 * ensure that the attribute to be reported its value already exists.
1386 * @param node The \ref axlNode the the attribute value associated
1387 * will be returned.
1389 * @param attribute The attribute that is being required its value.
1391 * @return A string containing the attribute value or NULL if
1392 * fails. Returned value must not be deallocated, it is a reference to
1393 * a local copy. Use \ref axl_strdup function to get a persistent
1394 * copy.
1396 const char * axl_node_get_attribute_value (axlNode * node, const char * attribute)
1398 axlNodeAttr * attr;
1400 /* check values received */
1401 axl_return_val_if_fail (node, NULL);
1402 axl_return_val_if_fail (attribute, NULL);
1404 /* check for empty hash */
1405 if (node->attributes == NULL)
1406 return NULL;
1408 if (node->attr_num <= 10) {
1409 /* linked configuration */
1410 attr = (axlNodeAttr *) node->attributes;
1411 while (attr != NULL) {
1412 /* check that the attribute is equal */
1413 if (axl_cmp (attr->attribute, attribute))
1414 return attr->value;
1416 /* get the next attribute */
1417 attr = attr->next;
1418 } /* end while */
1420 /* attribute not found */
1421 return NULL;
1422 } /* end if */
1424 /* return value stored for the provided key */
1425 return axl_hash_get ((axlHash *) node->attributes, (axlPointer) attribute);
1428 /**
1429 * @brief Gets an allocated copy for the value associated to the given
1430 * attribute.
1432 * See \ref axl_node_get_attribute_value for more information. This
1433 * function works the same way but returning an already allocated
1434 * attribute value.
1436 * @param node The node where the attribute value is requested.
1438 * @param attribute The attribute that is being requested.
1440 * @return A newly allocated reference that must be deallocated when
1441 * no longer needed calling to axl_free.
1443 char * axl_node_get_attribute_value_copy (axlNode * node,
1444 const char * attribute)
1446 const char * _value;
1448 /* get the attribute */
1449 _value = axl_node_get_attribute_value (node, attribute);
1450 axl_return_val_if_fail (_value, NULL);
1452 /* return a copy */
1453 return axl_strdup (_value);
1456 /**
1457 * @brief Gets the attribute content for the provided attribute name,
1458 * at the provided node, but translating entity references.
1460 * This function works the same way like \ref
1461 * axl_node_get_attribute_value_copy, in the sense it returns a
1462 * dinamically allocated copy for the attribute value requested but,
1463 * at the same time, it returns the content with all entity references
1464 * already translated.
1466 * If the attribute content has <b>&amp;</b>, <b>&lt;</b>, etc, this
1467 * function will translate them into the corresponding values.
1469 * @param node The \ref axlNode instance where the attribute content
1470 * will be returned.
1472 * @param attribute The attribute name that is being requested.
1474 * @return The attribute content, already translated, for those
1475 * entities found. The function returns a dinamilly allocated string
1476 * so \ref axl_free must be used.
1478 char * axl_node_get_attribute_value_trans (axlNode * node,
1479 const char * attribute)
1481 char * _value;
1482 int size;
1484 /* get the attribute */
1485 _value = (char *) axl_node_get_attribute_value (node, attribute);
1486 axl_return_val_if_fail (_value, NULL);
1488 /* perform a local copy */
1489 _value = axl_strdup (_value);
1491 /* return a copy */
1492 size = strlen (_value);
1493 return __axl_node_content_translate_defaults (_value, &size);
1496 /**
1497 * @brief Allows to get the value associated to the attributed
1498 * provided, inside the node selected, removing trailing and ending
1499 * white spaces (in the W3C sence: \\n, \\t, \\r, ' ').
1501 * See \ref ATTR_VALUE_TRIMMED for a convenience macro.
1503 * @param node The node that is requested to return the associated
1504 * value to the attributed.
1506 * @param attribute The attribute that is being requested.
1508 * @return A reference to the attribute value or NULL if it fails. The
1509 * function doesn't return a copy, it returns a reference to the
1510 * internal value.
1512 const char * axl_node_get_attribute_value_trimmed (axlNode * node,
1513 const char * attribute)
1515 char * _value;
1517 /* get the attribute */
1518 _value = (char *) axl_node_get_attribute_value (node, attribute);
1519 axl_return_val_if_fail (_value, NULL);
1521 /* trim the value */
1522 axl_stream_trim (_value);
1524 /* return value */
1525 return _value;
1528 /**
1529 * @brief Convenience function that allows to check if a particular
1530 * attribute with a particular value is found at the provided node.
1532 * This function will check if the attribute provided in the node is
1533 * found and in such case, if the value that is contained inside the
1534 * node is actually the same as the one provide to this function.
1536 * You can also use hits macro associated: \ref HAS_ATTR_VALUE.
1538 * @param node The node that will be checked.
1539 * @param attribute The attribute to be checked.
1540 * @param value The value to checked if the attribute is found.
1542 * @return \ref true if the node has the attribute with the provided
1543 * value.
1545 bool axl_node_has_attribute_value (axlNode * node,
1546 const char * attribute,
1547 const char * value)
1549 axl_return_val_if_fail (node, false);
1550 axl_return_val_if_fail (attribute, false);
1551 axl_return_val_if_fail (value, false);
1553 /* return if the attribute value found is the same */
1554 return axl_cmp (axl_node_get_attribute_value (node, attribute), value);
1558 * @}
1562 * \defgroup axl_node_annotate Axl Node Annotate: An interface that allows associate arbitrary data to a particular node, indexed as a hash.
1565 /**
1566 * \addtogroup axl_node_annotate
1567 * @{
1570 /**
1571 * @internal function which checks and initializes the hash used for
1572 * annotated data.
1574 void __init_node_annotation (axlNode * node)
1576 if (node->annotate_data == NULL)
1577 node->annotate_data = axl_hash_new (axl_hash_string, axl_hash_equal_string);
1578 return;
1581 /**
1582 * @brief Allows to store user defined data associated to the node
1583 * that is not visible from an XML perspective.
1585 * This function allows to store data associated to the node that is
1586 * accesible in an inherired fashion that allows to store semantic
1587 * information while parsing xml documents.
1589 * This function stores the given key using a hashing storage,
1590 * associating the data provided on the given node. You can also check
1591 * the \ref axl_node_annotate_data_full which performs the same task
1592 * but allowing to provide key and data destroy functions.
1594 * Once data is stored, it could be inherited by child nodes because
1595 * the access to it is done using \ref axl_node_annotate_get.
1597 * Additionally, you can also perform annotation using native types:
1598 * int, string and double. Check the following functions to do so.
1600 * - \ref axl_node_annotate_int
1601 * - \ref axl_node_annotate_double
1602 * - \ref axl_node_annotate_string
1604 * @param node The node where the annotated data will be stored.
1606 * @param key The key under which the annotated data will be stored
1607 * (and indexed).
1609 * @param data The data to be stored associated to the key provided.
1611 void axl_node_annotate_data (axlNode * node,
1612 const char * key,
1613 axlPointer data)
1615 axl_return_if_fail (node);
1617 /* check and init node annotation */
1618 __init_node_annotation (node);
1620 /* insert data */
1621 axl_hash_insert (node->annotate_data, (axlPointer) key, data);
1623 /* nothing more to do */
1624 return;
1627 /**
1628 * @brief Allows to store user defined data associated to the node
1629 * that is not visible from an XML perspective.
1631 * See \ref axl_node_annotate_data for a long explanation. This
1632 * function performs the same task as \ref axl_node_annotate_data_full
1633 * but allowing to store a destroy key and a destroy data associated
1634 * to the annotated data to be stored.
1636 * @param node The node where the annotated data will be stored.
1638 * @param key The key under which the annotated data will be stored
1639 * (and indexed).
1641 * @param key_destroy The destroy function to be called to deallocate
1642 * the key stored.
1644 * @param data The data to be stored associated to the key provided.
1646 * @param data_destroy The destroy function to be called to deallocate
1647 * the data provided.
1649 void axl_node_annotate_data_full (axlNode * node,
1650 const char * key,
1651 axlDestroyFunc key_destroy,
1652 axlPointer data,
1653 axlDestroyFunc data_destroy)
1655 axl_return_if_fail (node);
1657 /* check and init node annotation */
1658 __init_node_annotation (node);
1660 /* insert data */
1661 axl_hash_insert_full (node->annotate_data, (axlPointer) key, key_destroy, data, data_destroy);
1663 /* nothing more to do */
1664 return;
1667 /**
1668 * @brief Allows to perform lookups for annotated data stored on the
1669 * provided node, configure how data is looked up if it fails to find
1670 * on the provided node.
1672 * @param node The node where the lookup will be performed.
1674 * @param key The key to lookup in the \ref axlNode reference.
1676 * @param lookup_in_parent Once the lookup fails, this variable allows
1677 * to signal the function to also lookup the value in the parent
1678 * nodes. This mechanism allows to store data on parent nodes that are
1679 * shared by child nodes.
1681 * @return The data associated to the key according to the lookup
1682 * configuration (lookup_in_parent and lookup_in_doc).
1684 axlPointer axl_node_annotate_get (axlNode * node,
1685 const char * key,
1686 bool lookup_in_parent)
1688 axlPointer result = NULL;
1689 axlNode * parent;
1691 /* check node received before nothing */
1692 axl_return_val_if_fail (node, NULL);
1693 axl_return_val_if_fail (key, NULL);
1695 /* lookup the data in the current node */
1696 if (node->annotate_data != NULL) {
1697 /* lookup the data */
1698 result = axl_hash_get (node->annotate_data, (axlPointer) key);
1700 /* check result returned */
1701 if (result != NULL)
1702 return result;
1703 } /* end if */
1705 /* check if we have to lookup the data in parent nodes */
1706 if (lookup_in_parent) {
1707 /* get the first parent reference */
1708 parent = axl_item_get_parent (node->holder);
1710 /* for each parent, try to lookup the data */
1711 while (parent != NULL) {
1712 /* lookup the data */
1713 if (parent->annotate_data)
1714 result = axl_hash_get (parent->annotate_data, (axlPointer) key);
1716 /* check result returned */
1717 if (result != NULL)
1718 return result;
1720 /* get the next parent */
1721 parent = axl_item_get_parent (parent->holder);
1725 /* no node was found */
1726 return result;
1729 /**
1730 * @internal definition to clasify node annotation.
1732 typedef enum {
1733 /**
1734 * @internal definition to clasify int elements.
1736 ANNOTATE_INT = 0,
1737 /**
1738 * @internal definition to clasify string elements.
1740 ANNOTATE_STRING = 1,
1741 /**
1742 * @internal definition to clasify int elements.
1744 ANNOTATE_DOUBLE = 2
1745 } AnnotateType;
1747 typedef struct _AnnotateNodeData {
1748 /**
1749 * @internal type annotated.
1751 AnnotateType type;
1753 /**
1754 * @internal Value annotated: int, string or double.
1756 union {
1757 int int_value;
1758 char * string_value;
1759 double double_value;
1760 } value;
1761 } AnnotateNodeData;
1763 void __axl_annotate_data_free (AnnotateNodeData * data)
1765 if (data == NULL)
1766 return;
1768 /* free the string */
1769 if (data->type == ANNOTATE_STRING)
1770 axl_free (data->value.string_value);
1772 /* free the data */
1773 axl_free (data);
1775 return;
1778 /**
1779 * @brief Allows to perform an annotation to the node at runtime,
1780 * storing a integer value.
1782 * While using xml documents loaded into memory, each node could be
1783 * processed and annotated with particular information, indexed with a
1784 * key, that could be retrieved later for faster process.
1786 * This data annotation doesn't perform any modification to the xml
1787 * document in any form. It is just a programming support that allows
1788 * developers to avoid created complex and independent structures to
1789 * the xml document while developing.
1791 * While using annotation support, you can use low level functions that
1792 * provide a simple way to store pointers associated to particular
1793 * nodes and retrieve them using:
1795 * - \ref axl_node_annotate_data_full
1796 * - \ref axl_node_annotate_data
1797 * - \ref axl_node_annotate_get
1799 * However, additional functions are provided to store and retreive
1800 * easily integers, strings and double data annotated. See the
1801 * following:
1803 * - \ref axl_node_annotate_int
1804 * - \ref axl_node_annotate_string
1805 * - \ref axl_node_annotate_double
1807 * If you use this function to store an integer data you must use \ref
1808 * axl_node_annotate_get_int to retreive data stored. You can't use \ref axl_node_annotate_get.
1810 * @param node The node where the annotation will be aplied.
1812 * @param key The key to index the data annotated to the node.
1814 * @param int_value An integer value that will be annotated to the node
1815 * received under the key provided.
1817 void axl_node_annotate_int (axlNode * node,
1818 const char * key,
1819 int int_value)
1821 AnnotateNodeData * data;
1823 /* check received values */
1824 axl_return_if_fail (node);
1825 axl_return_if_fail (key);
1827 /* allocate the node */
1828 data = axl_new (AnnotateNodeData, 1);
1829 data->type = ANNOTATE_INT;
1830 data->value.int_value = int_value;
1832 /* annotate the value */
1833 axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
1835 return;
1838 /**
1839 * @brief Allows to perform an annotation to the node at runtime,
1840 * storing a string value.
1842 * While using xml documents loaded into memory, each node could be
1843 * processed and annotated with particular information, indexed with a
1844 * key, that could be retrieved later for faster process.
1846 * This data annotation doesn't perform any modification to the xml
1847 * document in any form. It is just a programming support that allows
1848 * developers to avoid created complex and independent structures to
1849 * the xml document while developing.
1851 * While using annotation support, you can use low level functions that
1852 * provide a simple way to store pointers associated to particular
1853 * nodes and retrieve them using:
1855 * - \ref axl_node_annotate_data_full
1856 * - \ref axl_node_annotate_data
1857 * - \ref axl_node_annotate_get
1859 * However, additional functions are provided to store and retreive
1860 * easily integers, strings and double data annotated. See the
1861 * following:
1863 * - \ref axl_node_annotate_int
1864 * - \ref axl_node_annotate_string
1865 * - \ref axl_node_annotate_double
1867 * If you use this function to store a string data you must use \ref
1868 * axl_node_annotate_get_string to retreive data stored. You can't use \ref axl_node_annotate_get.
1870 * @param node The node where the annotation will be aplied.
1872 * @param key The key to index the data annotated to the node.
1874 * @param string_value A string value that will be annotated to the
1875 * node received under the key provided. This value will be copied and
1876 * released once the node is deallocated.
1878 void axl_node_annotate_string (axlNode * node,
1879 const char * key,
1880 const char * string_value)
1882 AnnotateNodeData * data;
1884 /* check received values */
1885 axl_return_if_fail (node);
1886 axl_return_if_fail (key);
1887 axl_return_if_fail (string_value);
1889 /* allocate the node */
1890 data = axl_new (AnnotateNodeData, 1);
1891 data->type = ANNOTATE_STRING;
1892 data->value.string_value = axl_strdup (string_value);
1894 /* annotate the value */
1895 axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
1897 return;
1900 /**
1901 * @brief Allows to perform an annotation to the node at runtime,
1902 * storing a double value.
1904 * While using xml documents loaded into memory, each node could be
1905 * processed and annotated with particular information, indexed with a
1906 * key, that could be retrieved later for faster process.
1908 * This data annotation doesn't perform any modification to the xml
1909 * document in any form. It is just a programming support that allows
1910 * developers to avoid created complex and independent structures to
1911 * the xml document while developing.
1913 * While using annotation support, you can use low level functions that
1914 * provide a simple way to store pointers associated to particular
1915 * nodes and retrieve them using:
1917 * - \ref axl_node_annotate_data_full
1918 * - \ref axl_node_annotate_data
1919 * - \ref axl_node_annotate_get
1921 * However, additional functions are provided to store and retreive
1922 * easily integers, strings and double data annotated. See the
1923 * following:
1925 * - \ref axl_node_annotate_int
1926 * - \ref axl_node_annotate_string
1927 * - \ref axl_node_annotate_double
1929 * If you use this function to store a double data you must use \ref
1930 * axl_node_annotate_get_double to retreive data stored. You can't use \ref axl_node_annotate_get.
1932 * @param node The node where the annotation will be aplied.
1934 * @param key The key to index the data annotated to the node.
1936 * @param double_value A string value that will be annotated to the node
1937 * received under the key provided.
1939 void axl_node_annotate_double (axlNode * node,
1940 const char * key,
1941 double double_value)
1943 AnnotateNodeData * data;
1945 /* check received values */
1946 axl_return_if_fail (node);
1947 axl_return_if_fail (key);
1949 /* allocate the node */
1950 data = axl_new (AnnotateNodeData, 1);
1951 data->type = ANNOTATE_DOUBLE;
1952 data->value.double_value = double_value;
1954 /* annotate the value */
1955 axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
1957 return;
1960 /**
1961 * @brief Allows to retreive the annotated int value stored on the
1962 * particular node, under the provided key.
1964 * @param node The node that is required to return the annotated data.
1966 * @param key The key to be used to lookup for the data annotated.
1968 * @param lookup_in_parent Once the lookup fails, this variable allows
1969 * to signal the function to also lookup the value in the parent
1970 * nodes. This mechanism allows to store data on parent nodes that are
1971 * shared by child nodes.
1973 * NOTE: To make this function work properly you must store double
1974 * values using \ref axl_node_annotate_int. Storing values using
1975 * other functions will lead to unpredictable results.
1977 * @return The integer value stored using \ref
1978 * axl_node_annotate_int. If the key provided doesn't exists, the
1979 * function returns 0.
1981 int axl_node_annotate_get_int (axlNode * node,
1982 const char * key,
1983 bool lookup_in_parent)
1985 AnnotateNodeData * data;
1987 /* check received values */
1988 axl_return_val_if_fail (node, 0);
1989 axl_return_val_if_fail (key, 0);
1991 /* get the annotated data */
1992 data = axl_node_annotate_get (node, key, lookup_in_parent);
1994 /* check for null value. */
1995 if (data == NULL)
1996 return 0;
1998 if (data->type != ANNOTATE_INT) {
1999 /* drop a log */
2000 __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as integer");
2001 return 0;
2004 /* return the integer value inside */
2005 return data->value.int_value;
2008 /**
2009 * @brief Allows to retreive the annotated string value stored on the
2010 * particular node, under the provided key.
2012 * @param node The node that is required to return the annotated data.
2014 * @param key The key to be used to lookup for the data annotated.
2016 * @param lookup_in_parent Once the lookup fails, this variable allows
2017 * to signal the function to also lookup the value in the parent
2018 * nodes. This mechanism allows to store data on parent nodes that are
2019 * shared by child nodes.
2021 * NOTE: To make this function work properly you must store double
2022 * values using \ref axl_node_annotate_string. Storing values using
2023 * other functions will lead to unpredictable results.
2025 * @return The string value stored using \ref
2026 * axl_node_annotate_string. If the key provided doesn't exists, the
2027 * function returns NULL.
2029 char * axl_node_annotate_get_string (axlNode * node,
2030 const char * key,
2031 bool lookup_in_parent)
2033 AnnotateNodeData * data;
2035 /* check received values */
2036 axl_return_val_if_fail (node, NULL);
2037 axl_return_val_if_fail (key, NULL);
2039 /* get the annotated data */
2040 data = axl_node_annotate_get (node, key, lookup_in_parent);
2042 /* check for null value. */
2043 if (data == NULL)
2044 return NULL;
2046 if (data->type != ANNOTATE_STRING) {
2047 /* drop a log */
2048 __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as string");
2049 return NULL;
2052 /* return the string value inside */
2053 return data->value.string_value;
2056 /**
2057 * @brief Allows to retreive the annotated double value stored on the
2058 * particular node, under the provided key.
2060 * @param node The node that is required to return the annotated data.
2062 * @param key The key to be used to lookup for the data annotated.
2064 * @param lookup_in_parent Once the lookup fails, this variable allows
2065 * to signal the function to also lookup the value in the parent
2066 * nodes. This mechanism allows to store data on parent nodes that are
2067 * shared by child nodes.
2069 * NOTE: To make this function work properly you must store double
2070 * values using \ref axl_node_annotate_double. Storing values using
2071 * other functions will lead to unpredictable results.
2073 * @return The double value stored using \ref
2074 * axl_node_annotate_double. If the key provided doesn't exists, the
2075 * function returns 0.0.
2077 double axl_node_annotate_get_double (axlNode * node,
2078 const char * key,
2079 bool lookup_in_parent)
2081 AnnotateNodeData * data;
2083 /* check received values */
2084 axl_return_val_if_fail (node, 0.0);
2085 axl_return_val_if_fail (key, 0.0);
2087 /* get the annotated data */
2088 data = axl_node_annotate_get (node, key, lookup_in_parent);
2090 /* check for null value. */
2091 if (data == NULL)
2092 return 0.0;
2094 if (data->type != ANNOTATE_DOUBLE) {
2095 /* drop a log */
2096 __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as double");
2097 return 0.0;
2100 /* return the double value inside */
2101 return data->value.double_value;
2105 * @}
2108 /**
2109 * \addtogroup axl_node_module
2110 * @{
2113 /**
2114 * @brief Allows to configure the given node to be empty.
2116 * A \ref axlNode is empty when it is known that the node doesn't have
2117 * any content inside it as a child element. If the node has content,
2118 * and the value provided to this function is \ref true, the function
2119 * will deallocate the content inside.
2121 * You can use this function to clear all the node content (\ref
2122 * ITEM_CONTENT and \ref ITEM_CDATA) found inside the node, as follows:
2123 * \code
2124 * // clear all content inside
2125 * axl_node_set_is_empty (node, true);
2126 * \endcode
2128 * @param node The node to configure as empty.
2130 * @param empty The value for emptyness to be used. false will
2131 * mean that the node is not empty.
2133 void axl_node_set_is_empty (axlNode * node, bool empty)
2135 axlItem * child;
2136 axlItem * aux;
2137 int removed = 0;
2138 int count = 0;
2140 axl_return_if_fail (node);
2142 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received set to empty node=<%s> is_empty=\"%s\"",
2143 node->name, empty ? "true" : "false");
2145 /* do no perform any operation if false is received */
2146 if (! empty)
2147 return;
2149 /* get the first child and eliminate all content */
2150 child = node->first;
2151 while (child != NULL) {
2153 /* count each item found */
2154 count++;
2156 /* get a reference to the next */
2157 aux = child->next;
2159 /* check item node that represents content, and
2160 * therefore, an emptyless state */
2161 if (axl_item_get_type (child) == ITEM_CONTENT ||
2162 axl_item_get_type (child) == ITEM_CDATA) {
2164 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found item content and item CDATA..");
2166 /* remove the node */
2167 axl_item_remove (child, true);
2169 /* count each item removed */
2170 removed++;
2172 } /* end if */
2174 /* update to the next */
2175 child = aux;
2177 } /* end while */
2179 /* now check if items removed are equal to items counted */
2180 if (removed == count) {
2181 /* then clear node references */
2182 node->first = NULL;
2183 node->last = NULL;
2186 return;
2189 /**
2190 * @brief Allows to get current xml node name (represented the xml node by \ref axlNode).
2192 * The name of a node is the label that identifies it at the start and
2193 * close tag. On the following example, the xml node name is
2194 * considered to be <b>"data"</b>.
2196 * \code
2197 * <data>...</data>
2198 * \endcode
2200 * If it is required to check if the given \ref axlNode have a
2201 * particular name you can use the macro \ref NODE_CMP_NAME.
2203 * Here is an example:
2204 * \code
2205 * void check_name (axlNode * node) {
2206 * if (NODE_CMP_NAME (node, "data")) {
2207 * // we got a xml node called "data"
2209 * // the node doesn't have that name
2211 * \endcode
2213 * @param node The \ref axlNode where the name will be returned.
2215 * @return A string reference containing the name. Returned value must
2216 * not deallocated. If a copy is required use \ref axl_strdup
2217 * function.
2219 const char * axl_node_get_name (axlNode * node)
2221 axl_return_val_if_fail (node, NULL);
2223 return node->name;
2226 /**
2227 * @brief Allows to get the parent xml node (\ref axlNode) that is holding
2228 * as child the provided xml node reference.
2230 * When a node holds childs, it is also created a parent relation from
2231 * the child to the parent. This function allows to return that
2232 * reference.
2234 * @param node The xml node that is requested to return its parent
2235 * node.
2237 * @return An internal reference to the parent node, that must not be
2238 * deallocated, or NULL if fails. The function will also return NULL
2239 * if the node provided is the document root. The function could only
2240 * fail if the provided reference is NULL.
2242 axlNode * axl_node_get_parent (axlNode * node)
2244 axl_return_val_if_fail (node, NULL);
2246 /* if holder is NULL, no parent is posible */
2247 if (node->holder == NULL) {
2248 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received a node without holder (an axlItem reference), unable to get the parent reference: %s",
2249 node->name);
2250 return NULL;
2253 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node has a holder reference, returning current parent");
2255 /* return the parent */
2256 return node->holder->parent;
2259 /**
2260 * @brief Allows to get the node that is located, at the same level,
2261 * on the next position of the child list.
2263 * When a parent node holds more node childs, all of them have the
2264 * same parent child, and at the same time, all of them have a brother
2265 * relation. This relation makes that to nodes that are childs for a
2266 * parent node, are positioned sequentially as childs for the parent.
2268 * This function allows to get the next childs that is stored at the
2269 * next position, inside the same level, for the given child node.
2271 * There are an alternative API that allows to get the next node,
2272 * following to the node selected, providing the name to match. See
2273 * \ref axl_node_get_next_called.
2275 * @param node The node to get the next xml node reference.
2277 * @return Returns an internal reference to the next xml node or NULL
2278 * if fails. The function will also return NULL if no next xml node is
2279 * found starting from the provided reference. The root node will
2280 * always returns a NULL reference.
2282 axlNode * axl_node_get_next (axlNode * node)
2284 axlItem * item;
2286 axl_return_val_if_fail (node, NULL);
2288 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next node for=<%s>", axl_node_get_name (node));
2290 if (node->holder == NULL) {
2291 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received a node without item holder (maybe it wasn't inserted into a xml document)");
2292 return NULL;
2295 /* get the next axlNode situated at the same level of the
2296 * provided axlNode reference */
2297 item = axl_item_get_next (node->holder);
2299 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "%s", (item != NULL) ? "next item is defined, check if it is a node" : "next item isn't defined");
2301 /* while the item is not null and different from item node,
2302 * get the next */
2303 while (item != NULL) {
2305 /* get the item found */
2306 if (axl_item_get_type (item) == ITEM_NODE)
2307 return item->data;
2309 /* get next item */
2310 item = item->next;
2312 } /* end while */
2314 /* or null if no reference is defined */
2315 return NULL;
2318 /**
2319 * @brief Allows to get the next node, following to the node provided,
2320 * matching the given name.
2322 * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must use \ref axl_ns_node_get_next_called instead. See \ref axl_ns_doc_validate. </i>
2324 * @param node The node that is requested to return its next sibling node.
2325 * @param name The name to match for the next node.
2327 * @return A reference to the next node or NULL if it fails. The
2328 * returned reference mustn't be deallocated.
2330 axlNode * axl_node_get_next_called (axlNode * node,
2331 char * name)
2333 axlNode * next;
2334 axl_return_val_if_fail (node, NULL);
2335 axl_return_val_if_fail (name, NULL);
2337 /* while there is a next node */
2338 next = axl_node_get_next (node);
2339 while (next != NULL) {
2340 /* check the node */
2341 if (NODE_CMP_NAME (next, name))
2342 return next;
2344 /* update to the next */
2345 next = axl_node_get_next (next);
2346 } /* end while */
2348 /* no node was found */
2349 return NULL;
2352 /**
2353 * @brief Allows to get the previous reference from the reference node
2354 * provided.
2356 * See \ref axl_node_get_next. Previous reference is the considered
2357 * the previous node to the referenced provided that shares the same
2358 * parent and it is situated in the same level.
2360 * @param node The node where the previous reference to the previous node will be returned.
2362 * @return The previous node reference or NULL if the node doesn't
2363 * have previous reference or NULL if the function fails (the function
2364 * only fails if the node reference provided is null).
2366 axlNode * axl_node_get_previous (axlNode * node)
2368 axlItem * item;
2370 axl_return_val_if_fail (node, NULL);
2372 /* get the previous axlNode situated at the same level of the
2373 * provided axlNode reference */
2374 item = axl_item_get_previous (node->holder);
2376 /* while the item is not null and different from item node,
2377 * get the previous */
2378 while ((item != NULL) && axl_item_get_type (item) !=ITEM_NODE)
2379 item = axl_item_get_previous (item);
2381 /* return the previous reference */
2382 if (item != NULL)
2383 return item->data;
2385 /* or null if no reference is defined */
2386 return NULL;
2389 /**
2390 * @brief Allows to get the previous node, preceding to the node
2391 * provided, matching the given name.
2393 * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must use \ref axl_ns_node_get_previous_called instead. See \ref axl_ns_doc_validate. </i>
2395 * @param node The node that is requested to return its previous sibling node.
2396 * @param name The name to match for the previous node.
2398 * @return A reference to the previous node or NULL if it fails. The
2399 * returned reference mustn't be deallocated.
2401 axlNode * axl_node_get_previous_called (axlNode * node,
2402 char * name)
2404 axlNode * previous;
2406 axl_return_val_if_fail (node, NULL);
2407 axl_return_val_if_fail (name, NULL);
2409 /* while there is a previous node */
2410 previous = axl_node_get_previous (node);
2411 while (previous != NULL) {
2412 /* check the node */
2413 if (NODE_CMP_NAME (previous, name))
2414 return previous;
2416 /* update to the next */
2417 previous = axl_node_get_previous (previous);
2418 } /* end while */
2420 /* no node was found */
2421 return NULL;
2426 /**
2427 * @brief Allows to get the first child that holds the node.
2429 * This function is considered inside the CHILDREN API, which is the
2430 * set of functions that are used to handle XML documents that have
2431 * node that contains more nodes or content, but not mixed.
2433 * This function allows to get the first child found that is an \ref
2434 * axlNode. In the case your application is handling a document that
2435 * don't mix nodes and content at the same level inside another xml
2436 * nodes, you'll get the expected results.
2438 * But, calling to this function on a node that contains content mixed
2439 * with another nodes, you will skip all items stored before the first
2440 * xml node found as child.
2442 * Let's see some examples to clarify this. Provided the following xml
2443 * document:
2445 * \code
2446 * <document>
2447 * <child>
2448 * Content
2449 * </child>
2450 * </document>
2451 * \endcode
2453 * If you want to get a reference to the <b>child</b> node you can do
2454 * the following:
2456 * \code
2457 * // supposing the document is already loaded in "doc"
2458 * axlNode * node = axl_doc_get_root (doc);
2460 * // get the first child
2461 * node = axl_node_get_first_child (node);
2463 * // now you have in "node" a reference to the child node.
2464 * \endcode
2466 * However, in the case the previous content mix node with content as
2467 * follows:
2469 * \code
2470 * <document>
2471 * Some content previous to the first child.
2472 * <child>
2473 * Content
2474 * </child>
2475 * </document>
2476 * \endcode
2478 * Using this function will make you to skip the first content, that
2479 * is, <i>"Some content previous to the first child"</i>, which is found
2480 * before the &lt;child> node. In the case you want to have full
2481 * access to all items stored as child for a particular node, check
2482 * \ref axl_item_get_first_child.
2484 * @param node The node that is requested to return its first child.
2486 * @return The first child node or NULL if it has no child node.
2488 axlNode * axl_node_get_first_child (axlNode * node)
2490 axlItem * item;
2492 /* check values */
2493 axl_return_val_if_fail (node, NULL);
2495 /* get first item child and lookup for the first child that is
2496 * a node */
2497 item = node->first;
2498 while (item != NULL) {
2499 /* check the item type */
2500 if (axl_item_get_type (item) == ITEM_NODE)
2501 return item->data;
2503 /* get the next */
2504 item = item->next;
2507 /* return NULL: no child axlNode was found */
2508 return NULL;
2511 /**
2512 * @brief Allows to get the last child that holds the node.
2514 * See also \ref axl_node_get_first_child and \ref axl_item_get_last_child.
2516 * @param node The node that is requested to return its last child.
2518 * @return The last child node or NULL if it has no child node.
2520 axlNode * axl_node_get_last_child (axlNode * node)
2522 axlItem * item;
2524 /* check values */
2525 axl_return_val_if_fail (node, NULL);
2527 /* get first item child and lookup for the first child that is
2528 * a node */
2529 item = node->last;
2530 while (item != NULL) {
2531 /* check the item type */
2532 if (axl_item_get_type (item) == ITEM_NODE)
2533 return item->data;
2535 /* get the next */
2536 item = item->previous;
2539 /* return NULL: no child axlNode was found */
2540 return NULL;
2543 /**
2544 * @brief Allows to get current emptyness configuration for the given
2545 * \ref axlNode.
2547 * An \ref axlNode, which is a representation of a xml node, is
2548 * considered to be empty only if it has no content inside it. The
2549 * following xml code snipet shows what is considered the content:
2551 * \code
2552 * <data>
2553 * Xml content, data node content
2554 * </data>
2555 * \endcode
2557 * If a node have content, this function will return \ref
2558 * false. The content must not be confused with the node childs. A
2559 * xml node (\ref axlNode) could be empty but have childs at the same
2560 * time (\ref axl_node_have_childs).
2562 * The following xml code snipet shows a xml &lt;data> node with
2563 * childs that have content, but the parent node, &lt;data> do not
2564 * have content, therefore is empty.
2566 * \code
2567 * <data>
2568 * <row>Some data</row>
2569 * <row>More content</row>
2570 * </data>
2571 * \endcode
2573 * A node that is empty will return NULL data once called to \ref axl_node_get_content.
2575 * @param node The node to check for its empty status.
2577 * @return \ref true if the node is empty or \ref false if
2578 * not.
2580 bool axl_node_is_empty (axlNode * node)
2582 axlItem * child;
2583 axl_return_val_if_fail (node, false);
2585 /* get the first child */
2586 child = node->first;
2587 while (child != NULL) {
2589 /* check item node that represents content, and
2590 * therefore, an emptyless state */
2591 if (axl_item_get_type (child) == ITEM_CONTENT ||
2592 axl_item_get_type (child) == ITEM_CDATA) {
2594 /* the node has content */
2595 return false;
2597 } /* end if */
2599 /* go to the next */
2600 child = child->next;
2602 } /* end while */
2604 return true;
2607 /**
2608 * @brief Allows to get current xml node content (\ref axlNode).
2610 * See \ref axl_node_is_empty for more details. This function allows
2611 * to get current xml node content, which is the free text enclosed by
2612 * the node.
2614 * Returned value is an internal reference to the content stored. So,
2615 * in the case a local copy is desired, you should check \ref
2616 * axl_node_get_content_copy.
2618 * Keep in mind that the content returned could have references like
2619 * "&amp;" or "&quot;" which are entities references not translated
2620 * into the application level values.
2622 * This is done because while using the content, you may be interested
2623 * on getting the raw content to be passed to another xml parser which
2624 * is also able to process that entities.
2626 * If you don't like this behaviour you can check \ref
2627 * axl_node_get_content_trans which returns a copy for the xml node
2628 * content with all entities references translated.
2630 * Here is a summary of functions available to get the content of a
2631 * node:
2633 * - \ref axl_node_get_content_copy (the same like this function but
2634 * producing an independent copy)
2636 * - \ref axl_node_get_content_trans (the same like this function but
2637 * translating all entity references and producing an indenpendent
2638 * copy).
2640 * - \ref axl_node_get_content_trim (the same like this function but
2641 * removing initial and trailing white spaces in the W3C: spaces,
2642 * tabulars, carry returns and line feed values).
2644 * @param node The \ref axlDoc node where the content will be retrieved.
2646 * @param content_size Optional pointer to an integer variable where
2647 * the content size will be reported. If the variable is not set, the
2648 * function will not report the content size. If this value is
2649 * configured, it will contain the content size starting from 0 up to
2650 * the content size.
2652 * @return Current xml node content. You must not deallocate reference
2653 * returned. If you want a permanet copy you should use \ref
2654 * axl_node_get_content_copy. Keep in mind that the function will always
2655 * return an string reference. In the case the node has no content, an
2656 * empty string will be returned, not NULL.
2658 const char * axl_node_get_content (axlNode * node, int * content_size)
2660 axlNodeContent * content;
2661 axlItem * child;
2663 axl_return_val_if_fail (node, NULL);
2665 /* get the first child */
2666 child = node->first;
2667 while (child != NULL) {
2669 /* check item node that represents content, and
2670 * therefore, an emptyless state */
2671 if (axl_item_get_type (child) == ITEM_CONTENT ||
2672 axl_item_get_type (child) == ITEM_CDATA) {
2673 /* cast a reference */
2674 content = child->data;
2676 /* return the content */
2677 if (content_size != NULL)
2678 *content_size = content->content_size;
2680 /* return a local reference */
2681 return content->content;
2682 } /* end if */
2684 /* get the next item */
2685 child = child->next;
2687 } /* end while */
2689 /* set content size to zero */
2690 if (content_size != NULL)
2691 *content_size = 0;
2692 return "";
2695 /**
2696 * @brief Allows to set content to the given \ref axlNode instance.
2698 * The xml node content is that part defined inside two xml starts,
2699 * using the same label, that are balanced. Here is an example:
2700 * \code
2701 * <data>
2702 * Content inside the xml node.
2703 * </data>
2704 * \endcode
2706 * Because the function will perform a local copy for the provided
2707 * data, it will also check for especial entities to be placed
2708 * properly.
2710 * The following characters represents the set of characters that
2711 * should be referenced by using its associated entity reference. But,
2712 * if provided as is, the function will translate them into the
2713 * appropiate entity reference.
2715 * <table>
2716 * <tr><td><b>Character</b></td><td>Entity name</td></tr>
2717 * <tr><td>'</td><td>&amp;apos;</td></tr>
2718 * <tr><td><</td><td>&amp;lt;</td></tr>
2719 * <tr><td>></td><td>&amp;gt;</td></tr>
2720 * <tr><td>&</td><td>&amp;amp;</td></tr>
2721 * <tr><td>"</td><td>&amp;quot;</td></tr>
2722 * </table>
2724 * In general it is a good idea to espace previous sequences by
2725 * providing the right entity value, avoding the additional
2726 * computation required to translate the value received.
2728 * Rembember that valid XML documents have these values escaped.
2730 * @param node The xml node, represented by an already initialized
2731 * \ref axlNode, where the node content will be set.
2733 * @param content The content to set to the \ref axlNode. The function
2734 * will perform a local copy. Provided value could be unreferenced
2735 * once the function finish.
2737 * @param content_size The content size that is being provided. If -1
2738 * is used, the function will use strlen function to get current
2739 * content size.
2741 void axl_node_set_content (axlNode * node,
2742 const char * content,
2743 int content_size)
2745 axlNodeContent * itemContent;
2746 int additional_size = 0;
2748 axl_return_if_fail (node);
2749 axl_return_if_fail (content);
2751 /* get current content in the case a -1 is provided */
2752 if (content_size == -1)
2753 content_size = strlen (content);
2755 /* allocate the content */
2756 itemContent = axl_new (axlNodeContent, 1);
2758 /* check if the string received have escapable characters */
2759 if (axl_node_has_invalid_chars (content, content_size,
2760 &additional_size)) {
2761 /* copy content */
2762 itemContent->content = __axl_node_content_copy_and_escape (content,
2763 content_size,
2764 additional_size);
2765 /* set node content size */
2766 itemContent->content_size = content_size + additional_size;
2767 }else {
2768 /* set current content */
2769 itemContent->content_size = content_size;
2770 itemContent->content = axl_new (char, content_size + 1);
2772 /* copy content */
2773 memcpy (itemContent->content, content, itemContent->content_size);
2776 /* add it to the current node */
2777 axl_item_set_child (node, ITEM_CONTENT, itemContent);
2780 /* job done */
2781 return;
2784 /**
2785 * @internal Common implementation for axl_node_set_content_ref and
2786 * axl_node_set_content_from_factory.
2788 void __axl_node_set_content_common_ref (axlFactory * factory,
2789 axlNode * node,
2790 char * content,
2791 int content_size,
2792 bool from_factory,
2793 bool cdata)
2796 axlNodeContent * itemContent;
2798 axl_return_if_fail (node);
2799 axl_return_if_fail (content);
2801 /* get current content in the case a -1 is provided */
2802 if (content_size == -1)
2803 content_size = strlen (content);
2805 /* create a content checking it it comes from the
2806 * factory. Because the string received could come from the
2807 * factory, already allocated, do not call to allocate */
2808 if (from_factory && factory)
2809 itemContent = axl_factory_get (factory);
2810 else
2811 itemContent = axl_new (axlNodeContent, 1);
2813 /* configure content size */
2814 itemContent->content_size = content_size;
2816 /* set current content */
2817 itemContent->content = content;
2819 if (from_factory) {
2820 if (cdata) {
2821 /* store it */
2822 axl_item_set_child (node, ITEM_CDATA | ITEM_CONTENT_FROM_FACTORY, itemContent);
2823 } else {
2824 /* store it */
2825 axl_item_set_child (node, ITEM_CONTENT | ITEM_CONTENT_FROM_FACTORY, itemContent);
2827 } else {
2828 /* store it */
2829 if (cdata) {
2830 /* store as cdata */
2831 axl_item_set_child (node, ITEM_CDATA, itemContent);
2832 } else {
2833 /* store as parsed xml content */
2834 axl_item_set_child (node, ITEM_CONTENT, itemContent);
2836 } /* end if */
2838 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting xml node (name: %s) content (size: %d) %s",
2839 node->name, itemContent->content_size, itemContent->content);
2841 return;
2844 /**
2845 * @brief Set the content for the provided node, reusing the reference
2846 * provided, without making a local copy.
2848 * This function works like \ref axl_node_set_content_ref but without
2849 * copy memory provided. This allows reduce memory allocations if the
2850 * memory was already allocated by the user space.
2852 * Because this function doesn't perform a copy, if the content
2853 * received has to be escaped, the function will fail. To use this
2854 * function the caller must ensure that entity references are used to
2855 * especify the &, ', ", < or >.
2857 * If the node have content already configured, it is deallocated,
2858 * configuring new content received.
2860 * @param node The \ref axlNode where the content will be set.
2862 * @param content The user space allocated content to be set to the
2863 * node.
2865 * @param content_size The content size.
2867 void axl_node_set_content_ref (axlNode * node,
2868 char * content,
2869 int content_size)
2872 /* call to set content without signaling that the content
2873 * wasn't allocated by a factory. */
2874 __axl_node_set_content_common_ref (NULL, node, content, content_size, false, false);
2876 /* job done */
2877 return;
2880 /**
2881 * @internal Internal API used by the axl doc module to signal that
2882 * the content was allocated though the string factory and shouldn't
2883 * be deallocated.
2885 void axl_node_set_content_from_factory (axlFactory * factory,
2886 axlNode * node,
2887 char * content,
2888 int content_size)
2890 /* call to set content without signaling that the content was
2891 * allocated by a factory. */
2892 __axl_node_set_content_common_ref (factory, node, content, content_size, true, false);
2894 /* job done */
2895 return;
2898 /**
2899 * @brief Allows to store data as content of the provided noe to be
2900 * enclosed as CDATA.
2902 * Some characters are not allowed to be stored "as is" inside a
2903 * parseable XML document. The basic set of them are: &, ', ", < or >.
2905 * In order to store content containing previous characters inside an
2906 * xml node, and to remain valid, functions like \ref
2907 * axl_node_set_content will translate those value, into the accepted
2908 * scape sequences. However, in the other hand, the entity parsing the
2909 * document produced must perform the translation back to the normal
2910 * state.
2912 * As an alternative, the XML node content could be stored enclosed as
2913 * a CDATA section: <![CDATA[..]]> allow to store "un-parsed"
2914 * characters, including those not allowed.
2916 * @param node The node where the CDATA will be stored.
2918 * @param content The content to store.
2920 * @param content_size The content size or -1 if required Axl to
2921 * figure out current sizes.
2923 void axl_node_set_cdata_content (axlNode * node,
2924 char * content,
2925 int content_size)
2927 axl_return_if_fail (node);
2928 axl_return_if_fail (content);
2930 /* reconfigure content_size if found -1 value */
2931 if (content_size == -1)
2932 content_size = strlen (content);
2934 /* call to set node content */
2935 content = axl_strdup (content);
2936 __axl_node_set_content_common_ref (NULL, node, content, content_size, false, true);
2938 return;
2941 /**
2942 * @internal Internal API used by the axl doc module to signal that
2943 * the content was allocated though the string factory and shouldn't
2944 * be deallocated, and the content was found inside cdata
2945 * declarations.
2947 void axl_node_set_cdata_content_from_factory (axlFactory * factory,
2948 axlNode * node,
2949 char * content,
2950 int content_size)
2952 /* call to set content without signaling that the content was
2953 * allocated by a factory. */
2954 __axl_node_set_content_common_ref (factory, node, content, content_size, true, true);
2956 /* job done */
2957 return;
2960 /**
2961 * @brief Allows to configure a new comment (&lt;!-- xml comment -->) that will be
2962 * stored as a child for the node provided.
2964 * The comment will be placed at the end of the current child
2965 * list. So, if you want to place a xml comment before a xml node,
2966 * call first to this function and the to \ref axl_node_set_child.
2968 * @param node The node that will contain the comment.
2970 * @param comment The comment to be stored. The function will perform
2971 * a copy from it.
2973 * @param comment_size The comment size or -1 to make the function to
2974 * calculate it.
2976 void axl_node_set_comment (axlNode * node,
2977 char * comment,
2978 int comment_size)
2980 axlNodeContent * content;
2982 axl_return_if_fail (node);
2983 axl_return_if_fail (comment);
2985 /* check current coment size */
2986 if (comment_size == -1)
2987 comment_size = strlen (comment);
2989 /* create the comment */
2990 content = axl_new (axlNodeContent, 1);
2991 content->content = axl_new (char, comment_size + 1);
2992 content->content_size = comment_size;
2994 /* copy the content */
2995 memcpy (content->content, comment, comment_size);
2997 /* now store it on the node */
2998 axl_item_set_child (node, ITEM_COMMENT, content);
3000 return;
3004 /**
3005 * @brief Allows to get a copy for the content stored inside the given
3006 * \ref axlNode reference.
3008 * This function works the same way than \ref axl_node_get_content but
3009 * returning a copy from the internal content, that the caller is
3010 * responsible of deallocating it.
3012 * @param node The \ref axlNode where the content is being required.
3014 * @param content_size An optinal reference to an integer variable
3015 * where the content size will be returned. The function will return
3016 * the content size (if the variable is defined) ranging from 0 up to
3017 * the content size.
3019 * @return A newly allocated string representing the node content.
3021 char * axl_node_get_content_copy (axlNode * node, int * content_size)
3023 int _content_size;
3024 char * result;
3025 const char * content;
3027 /* get the content and check if it is defined */
3028 if (content_size)
3029 content = axl_node_get_content (node, content_size);
3030 else
3031 content = axl_node_get_content (node, &_content_size);
3033 /* check result */
3034 if (content == NULL || strlen (content) == 0) {
3035 return axl_strdup ("");
3038 /* allocate enough memory for the result */
3039 if (content_size) {
3040 result = axl_new (char, (*content_size) + 1);
3041 memcpy (result, content, *content_size);
3042 }else {
3043 result = axl_new (char, _content_size + 1);
3044 memcpy (result, content, _content_size);
3047 /* return a newly allocated reference to the content */
3048 return result;
3051 /**
3052 * @brief Allows to get the content inside the provided node, trimming
3053 * the header and trailing white spaces found.
3055 * Note that calling to this function will modify the node content,
3056 * removing "white spaces" found. Once the function is called, the
3057 * node content will be returned by \ref axl_node_get_content already
3058 * trimmed.
3060 * @param node The node where the content will be trimmed and
3061 * returned.
3063 * @param content_size The node content size reference where the
3064 * content size will be reported.
3066 * @return The reference returned is an internal copy that must not be
3067 * deallocated. The function always return content. If the node has no
3068 * content, the function will return an empty string (but never a NULL
3069 * value).
3071 char * axl_node_get_content_trim (axlNode * node,
3072 int * content_size)
3074 int trimmed;
3076 axlNodeContent * content;
3077 axlItem * child;
3079 axl_return_val_if_fail (node, NULL);
3081 /* get the first child */
3082 child = node->first;
3083 while (child != NULL) {
3085 /* check item node that represents content, and
3086 * therefore, an emptyless state */
3087 if (axl_item_get_type (child) == ITEM_CONTENT ||
3088 axl_item_get_type (child) == ITEM_CDATA) {
3089 /* cast a reference */
3090 content = child->data;
3092 /* trim the content */
3093 axl_stream_trim_with_size (content->content, &trimmed);
3095 /* updates current internal content size */
3096 content->content_size -= trimmed;
3098 /* return the content */
3099 if (content_size != NULL)
3100 *content_size = content->content_size;
3102 /* return a local reference */
3103 return content->content;
3104 } /* end if */
3106 /* get the next item */
3107 child = child->next;
3109 } /* end while */
3111 /* set content size to zero */
3112 if (content_size != NULL)
3113 *content_size = 0;
3114 return "";
3117 /**
3118 * @brief Allows to the get node content, performing a memory
3119 * allocation for the returned result, translating default entities
3120 * values with its replacement text.
3122 * @param node The XML node where the content is being requested.
3125 * @param content_size An optional reference to an integer variable to
3126 * return the node content size.
3128 * @return A newly allocated string, representing the node content,
3129 * with all entities references already translated into the
3130 * replacement text.
3132 char * axl_node_get_content_trans (axlNode * node, int * content_size)
3134 char * result;
3135 int _content_size = 0;
3137 /* get a copy for the node content, getting the node content
3138 * size. If the user don't provide a reference, use a local
3139 * one. */
3140 if (content_size)
3141 result = axl_node_get_content_copy (node, content_size);
3142 else
3143 result = axl_node_get_content_copy (node, &_content_size);
3145 /* check result returned */
3146 if (result == NULL || strlen (result) == 0) {
3147 /* do not perform a copy here, it is already done by
3148 * get_content_copy, even in error */
3149 return result;
3152 /* translate all references that performs the entities to the
3153 * replacement text. */
3154 if (content_size)
3155 return __axl_node_content_translate_defaults (result, content_size);
3156 return __axl_node_content_translate_defaults (result, &_content_size);
3160 /**
3161 * @brief Allows to configure a child node to the given parent.
3163 * This is a fundamental function while building xml document inside
3164 * memory. The way the xml nodes are linked to conform the xml
3165 * document structure relay on this function.
3167 * The idea is that every call to this function makes the <b>child
3168 * </b> xml node to be placed at the end of the current item child
3169 * set, that represents current child list for the provided
3170 * <b>parent</b>.
3172 * One important question while using this function is that you must
3173 * not reuse the same xml node reference, adding it several time to
3174 * the same parent (or different parents). You must create a new xml
3175 * node reference (axl_node_create) for every call you do to this
3176 * function.
3178 * So, to build the following structure:
3179 * \code
3180 * <document>
3181 * <child1 />
3182 * <child2 />
3183 * </document>
3184 * \endcode
3186 * You must perform the following operations:
3187 * \code
3188 * axlNode * parent;
3189 * axlNode * child;
3191 * // create the parent node
3192 * parent = axl_node_create ("document");
3194 * // create the first child
3195 * child = axl_node_create ("child1");
3197 * // set it to the parent
3198 * axl_node_set_child (parent, child);
3200 * // create the second child
3201 * child = axl_node_create ("child2");
3203 * // set it to the parent
3204 * axl_node_set_child (parent, child);
3206 * \endcode
3208 * See also \ref axl_node_set_child_after which could help you adding
3209 * new nodes not using a parent node as a reference but a brother
3210 * node.
3212 * @param parent The parent node.
3214 * @param child The child node. The child node must be a deep
3215 * copy. Passing several references, pointing to the same value, will
3216 * cause to seg fault the program at the time the parent child is
3217 * deallocated.
3219 void axl_node_set_child (axlNode * parent, axlNode * child)
3221 axl_return_if_fail (parent);
3222 axl_return_if_fail (child);
3224 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received parent=0x%x and child=0x%x", parent, child);
3226 /* set a xml node child */
3227 axl_item_set_child (parent, ITEM_NODE, child);
3229 return;
3232 /**
3233 * @brief Sets a new child after the node provided as a reference.
3235 * This function is useful to allow configuring new childs placed
3236 * after some particular node. The child configured will be placed
3237 * after the reference and child of the reference's parent node.
3239 * @param reference The xml node acting as a reference.
3240 * @param child The new xml node child to configure.
3242 void axl_node_set_child_after (axlNode * reference,
3243 axlNode * child)
3245 /* call to the item implementation */
3246 axl_item_set_after (reference->holder, ITEM_NODE, child);
3248 return;
3252 /**
3253 * @brief Allows to replace a selected node, with the new reference
3254 * inside its context (updating all references: next, previous and
3255 * parent).
3257 * If the node replace is inserted in a document, the replace also
3258 * works. In fact, this function is designed to replace a node already
3259 * inserted in an xml document (\ref axlDoc). If the node being
3260 * replaced is the root one, this function will configured the new
3261 * root node.
3263 * Previous \ref axlNode will be unreference according to dealloc
3264 * value. This function will replace the node provided by the second
3265 * reference (no matter if the node is inside a document or not).
3267 * @param node The node to be replaced by the following reference.
3269 * @param new_node The node that will replace the previous value.
3271 * @param dealloc Signal if the previous node must be deallocated.
3273 void axl_node_replace (axlNode * node,
3274 axlNode * new_node,
3275 bool dealloc)
3277 axlItem * p_item;
3279 axl_return_if_fail (node);
3280 axl_return_if_fail (new_node);
3282 if (axl_item_get_parent (node->holder) == NULL) {
3283 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "replacing the root node=<%s> with <%s>..",
3284 axl_node_get_name (node), axl_node_get_name (new_node));
3285 /* seems to be a root document */
3286 if (axl_item_get_doc (node->holder) != NULL) {
3287 axl_doc_set_root (axl_item_get_doc (node->holder), new_node);
3289 } else {
3291 /* check for holder reference */
3292 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "replacing a non-root node=<%s> with <%s>..",
3293 axl_node_get_name (node), axl_node_get_name (new_node));
3294 if (node->holder != NULL) {
3296 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "axl item holder is defined for node=<%s>",
3297 axl_node_get_name (node));
3298 /* get a reference to the holder item */
3299 p_item = node->holder;
3301 /* configure the new node */
3302 p_item->data = new_node;
3304 /* nullify the holder reference, and configure
3305 * the holder reference in the node */
3306 node->holder = NULL;
3307 new_node->holder = p_item;
3309 } /* end if */
3312 /* dealloc node if configured so */
3313 if (dealloc) {
3314 /* free the node */
3315 axl_node_free (node);
3318 return;
3321 /**
3322 * @brief Allows to the remove the selected reference from the
3323 * document containing it.
3325 * The function remove the selected reference from the document. If
3326 * the node asked to be removed is the root one, the node won't be
3327 * removed because the \ref axl_doc_set_root doesn't accept to remove
3328 * the root node.
3330 * All childs hold by the node removed from the document whill also be
3331 * removed if dealloc is selected.
3333 * @param node The node to remove.
3335 * @param dealloc \ref true to not only unlink relations but also
3336 * remove the node.
3338 void axl_node_remove (axlNode * node,
3339 bool dealloc)
3341 axlItem * item;
3342 axl_return_if_fail (node);
3344 /* get a reference to the item element */
3345 item = node->holder;
3347 /* check if the node is the root node of its document */
3348 if (item != NULL && item->doc != NULL) {
3349 if (axl_doc_get_root (item->doc) == node) {
3350 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "attempting to dettach the root node from the document, nullify");
3351 axl_doc_set_root (item->doc, NULL);
3352 } /* end if */
3353 } /* end if */
3355 if (axl_item_get_parent (item) != NULL) {
3357 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "doing reference relocation (remove operation) for=<%s>",
3358 node->name);
3360 /* make previous node to point to the new node */
3361 if (item->previous != NULL) {
3362 item->previous->next = item->next;
3365 /* make next node to point to the new node */
3366 if (item->next != NULL) {
3367 item->next->previous = item->previous;
3370 /* now, update the parent reference */
3371 if (item->previous == NULL) {
3372 /* seems the node is the first child of the parent,
3373 * update the reference */
3374 item->parent->first = item->next;
3377 if (item->next == NULL) {
3378 /* seems the node is the last child of the parent,
3379 * update the reference */
3380 item->parent->last = item->previous;
3383 if (item != NULL) {
3384 /* disconnect the item */
3385 item->previous = NULL;
3386 item->next = NULL;
3387 } /* end if */
3389 } /* end if */
3391 /* dealloc node if configured so */
3392 if (dealloc) {
3393 /* free the node */
3394 axl_node_free (node);
3397 return;
3400 /**
3401 * @brief Supposing the node is attached to a xml document (\ref
3402 * axlDoc), this function allows to deattach the node from the
3403 * document that is holding it.
3405 * This function is useful while requiring to reallocate nodes from
3406 * parent to parent, making the parent node that is holding it to lost
3407 * references to the node, decreasing all internal counts to the node,
3408 * etc.
3410 * If the node isn't attached to any document, the function does
3411 * nothing.
3413 * @param node The node to deattach.
3415 void axl_node_deattach (axlNode * node)
3417 axl_return_if_fail (node);
3419 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "deattaching node..");
3421 /* call to remove */
3422 axl_node_remove (node, false);
3424 return;
3427 /**
3428 * @brief Allows to configure that the given node have child nodes.
3430 * <b>DEPRECATED:</b> The function doesn't perform any operation. See
3431 * \ref axl_node_have_childs.
3433 * @param node The node to configure.
3435 * @param childs The child configuration, true to notify that the
3436 * node have childs, otherwise, false is returned.
3438 void axl_node_set_have_childs (axlNode * node, bool childs)
3440 /* do nothing */
3441 return;
3444 /**
3445 * @brief Allows to get current childs configuration for the given xml
3446 * node (\ref axlNode).
3448 * An xml node (represented by an \ref axlNode) is considered to have
3449 * childs only if it has more xml child nodes. The content is not
3450 * considered be a child. See \ref axl_node_is_empty for more
3451 * information.
3453 * @param node The \ref axlNode reference.
3455 * @return An \ref true if the \ref axlNode have childs or \ref
3456 * false if not.
3458 bool axl_node_have_childs (axlNode * node)
3460 axlItem * item;
3462 axl_return_val_if_fail (node, false);
3464 item = node->first;
3465 while (item != NULL) {
3466 /* check item type */
3467 if (axl_item_get_type (item) == ITEM_NODE)
3468 return true;
3470 /* go to the next */
3471 item = item->next;
3473 } /* end while */
3475 /* return false because no item was found with ITEM_NODE
3476 * type */
3477 return false;
3480 /**
3481 * @brief Allows to get a particular child node for the given node (\ref axlNode).
3483 * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must use \ref axl_ns_node_get_child_called instead. See \ref axl_ns_doc_validate. </i>
3485 * @param parent The parent node where the child will be looked up.
3487 * @param name The name for the child to search.
3489 * @return A refernce to a \ref axlNode or NULL if no child exists
3490 * called by the name provided, inside the node provided.
3492 axlNode * axl_node_get_child_called (axlNode * parent, char * name)
3494 axlNode * node;
3495 axlItem * item;
3497 axl_return_val_if_fail (parent, NULL);
3498 axl_return_val_if_fail (name, NULL);
3500 /* if the child list is not defined, assume there is no node
3501 * called the name requested */
3502 if (parent->first == NULL)
3503 return NULL;
3505 /* if no childs, no result */
3506 item = parent->first;
3507 while (item != NULL) {
3508 /* check item type */
3509 if (axl_item_get_type (item) == ITEM_NODE) {
3510 /* get a reference to the node */
3511 node = item->data;
3513 /* compare for find the child */
3514 if (NODE_CMP_NAME (node, name))
3515 return node;
3517 } /* end if */
3519 /* next child */
3520 item = axl_item_get_next (item);
3523 /* no child was found */
3524 return NULL;
3527 /**
3528 * @brief Allows to find the first child called as provided inside the
3529 * childs (including its descendants) hold by the parent provided.
3531 * This function is similar to \ref axl_node_get_child_called but it
3532 * will look for a child node called as provided not only in direct
3533 * childs hold by the parent but also on its all descendants.
3535 * If you are looking for a function to search for a particular child
3536 * node inside direct childs stored for the provided parent, then you
3537 * must use \ref axl_node_get_child_called.
3539 * There is also a convenience function that allows to perform a
3540 * lookup using as a reference a document (using the root node from
3541 * it): \ref axl_doc_find_called.
3543 * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must use \ref axl_ns_node_find_called instead. See \ref axl_ns_doc_validate. </i>
3545 * @param parent The parent where the lookup will be produced.
3547 * @param name The name of the child to be looked up.
3549 * @return A reference to the node found (first instaned matching the
3550 * name) or NULL if it fails to find a child.
3552 axlNode * axl_node_find_called (axlNode * parent, char * name)
3554 axlNode * node;
3555 axlNode * child;
3557 /* for the first child found */
3558 node = axl_node_get_first_child (parent);
3559 while (node != NULL) {
3560 /* check and return the node found */
3561 if (NODE_CMP_NAME (node, name))
3562 return node;
3564 /* get next */
3565 node = axl_node_get_next (node);
3566 } /* end while */
3568 /* now, for all childs, try to look for the node */
3569 node = axl_node_get_first_child (parent);
3570 while (node != NULL) {
3571 /* make the search */
3572 child = axl_node_find_called (node, name);
3574 /* child found, return the reference */
3575 if (child != NULL)
3576 return child;
3578 /* get next */
3579 node = axl_node_get_next (node);
3580 } /* end while */
3582 /* child note found */
3583 return NULL;
3586 /**
3587 * @brief Allows to get the child that is located at the given
3588 * position, for the given parent node.
3590 * @param parent The parent node where the child will be looked up.
3592 * @param position The position where the child will be looked up. The
3593 * values for the position ranges from 0 up to (N - 1).
3595 * @return A reference to the child node \ref axlNode or NULL if fails.
3597 axlNode * axl_node_get_child_nth (axlNode * parent, int position)
3599 int iterator;
3600 axlItem * item;
3602 /* perform some environment checks */
3603 axl_return_val_if_fail (parent, NULL);
3605 /* check for first reference */
3606 if (parent->first == NULL) {
3607 return NULL;
3610 /* get the first item */
3611 item = parent->first;
3613 /* get the first node found */
3614 iterator = 0;
3615 while (item != NULL) {
3616 /* check the item type */
3617 if (axl_item_get_type (item) == ITEM_NODE) {
3618 if (iterator == position) {
3619 return item->data;
3620 } else
3621 iterator++;
3622 } /* end if */
3624 /* get the next */
3625 item = item->next;
3627 } /* end while */
3629 /* no first child found */
3630 return NULL;
3633 /**
3634 * @brief Allows to get the number of childs the provided node has.
3636 * @param parent The node where the number of childs is being queried.
3638 * @return The number of childs or -1 if fails.
3640 int axl_node_get_child_num (axlNode * parent)
3642 int count;
3643 axlItem * item;
3645 /* perform some environment checks */
3646 axl_return_val_if_fail (parent, -1);
3648 /* init values */
3649 count = 0;
3650 item = parent->first;
3652 /* for each child inside the parent node */
3653 while (item != NULL) {
3655 /* check item type */
3656 if (axl_item_get_type (item) == ITEM_NODE)
3657 count++;
3659 /* get the next */
3660 item = item->next;
3662 } /* end while */
3664 /* return the number of chils */
3665 return count;
3669 /**
3670 * @brief Allows to get childs nodes for the given xml node (\ref
3671 * axlNode).
3673 * This function creates a newly allocated list. In the case a
3674 * iterating over all childs for the provided node is its better to
3675 * use the following:
3676 * \code
3677 * axlNode * child;
3679 * // get the first child
3680 * child = axl_node_get_first_child (parent);
3682 * // iterate over all nodes
3683 * while (child != NULL) {
3685 * // do something with the child
3686 * do_some_work (child);
3688 * // update the reference to the next child
3689 * child = axl_node_get_next (child);
3691 * \endcode
3693 * @param node The node where the childs will be returned.
3695 * @return An \ref axlList containing \ref axlNode items or NULL if it
3696 * fails. The list returned MUST be deallocated.
3698 axlList * axl_node_get_childs (axlNode * node)
3700 axlItem * child;
3701 axlList * result;
3703 axl_return_val_if_fail (node, NULL);
3705 /* create the result list without destroy function */
3706 result = axl_list_new (__axl_node_equal, NULL);
3708 /* get the first child */
3709 child = node->first;
3711 while (child != NULL) {
3712 /* check the node type */
3713 if (axl_item_get_type (child) == ITEM_NODE) {
3714 /* add the child to the list */
3715 axl_list_add (result, child->data);
3717 } /* end if */
3719 /* update the reference to the next child */
3720 child = child->next;
3721 } /* end while */
3723 /* return current childs */
3724 return result;
3727 bool __axl_node_are_equal_attr (axlPointer key,
3728 axlPointer value,
3729 axlPointer user_data,
3730 axlPointer user_data2)
3732 char * value2;
3733 bool * result = user_data2;
3735 /* get the attr value and compare it with data */
3736 value2 = axl_hash_get ((axlHash *) user_data, (char *) key);
3738 if (! axl_cmp ((char *) value, value2)) {
3739 /* flag that node attributes aren't equal */
3740 (* result) = false;
3742 /* stop foreach */
3743 return true;
3746 /* make the process to continue */
3747 return false;
3750 /**
3751 * @brief Allows to check if the provided references represents two
3752 * equivalent nodes.
3754 * The function will check node name, node content and node attributes
3755 * and its values.
3757 * @param node The node to check.
3758 * @param node2 The second node to check.
3760 * @return true if both nodes are equivalent or false if not.
3762 bool axl_node_are_equal (axlNode * node, axlNode * node2)
3764 bool result;
3766 axl_return_val_if_fail (node, false);
3767 axl_return_val_if_fail (node2, false);
3769 /* check document root name */
3770 if (! axl_cmp (axl_node_get_name (node), axl_node_get_name (node2))) {
3771 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node names aren't equal <%s> != <%s>",
3772 node->name, node2->name);
3773 return false;
3776 /* check empty ness configuration */
3777 if (axl_node_is_empty (node) != axl_node_is_empty (node2)) {
3778 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "emptyness configuration differs <%s> != <%s>",
3779 node->name, node2->name);
3780 return false;
3783 /* check childs configuration */
3784 if (axl_node_have_childs (node) != axl_node_have_childs (node2)) {
3785 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "childs configuration differs <%s> != <%s>",
3786 node->name, node2->name);
3787 return false;
3790 /* check childs number */
3791 if (axl_node_get_child_num (node) != axl_node_get_child_num (node2)) {
3792 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "child number differs <%s>(%d) != <%s>(%d)",
3793 node->name, axl_node_get_child_num (node), node2->name, axl_node_get_child_num (node2));
3794 return false;
3797 /* check attribute values */
3798 if ((node->attributes != NULL && node2->attributes != NULL)) {
3800 /* check the number of attributes that has the hash */
3801 if (node->attr_num != node2->attr_num) {
3802 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "both nodes have different number of attributes (%d != %d)",
3803 node->attr_num, node2->attr_num);
3804 return false;
3807 /* now both hashes */
3808 result = true;
3809 if (node->attr_num <= 10) {
3810 /* check both list are equal */
3811 result = __axl_node_attr_list_is_equal ((axlNodeAttr *) node->attributes, (axlNodeAttr *) node2->attributes);
3812 } else {
3813 /* check both hashes are equal */
3814 axl_hash_foreach2 ((axlHash *) node->attributes, __axl_node_are_equal_attr, (axlHash *) node2->attributes, &result);
3817 if (! result) {
3818 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node attributes differs <%s> != <%s>",
3819 node->name, node2->name);
3820 /* attribute missmatch */
3821 return false;
3823 } else {
3824 if (node->attributes == NULL && node2->attributes != NULL) {
3825 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node <%s> has no attributes but <%s> has",
3826 axl_node_get_name (node), axl_node_get_name (node2));
3827 return false;
3830 if (node2->attributes == NULL && node->attributes != NULL) {
3831 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node <%s> has no attributes but <%s> has",
3832 axl_node_get_name (node2), axl_node_get_name (node));
3833 return false;
3836 } /* end if */
3838 /* both nodes seems to be equal */
3839 return true;
3842 /**
3843 * @brief Allows to associate a PI element, including its content to
3844 * the provided node.
3846 * See the following function for more information: \ref
3847 * axl_doc_add_pi_target.
3849 * @param node The \ref axlNode where the PI element (\ref axlPI) will
3850 * be added.
3852 * @param target The PI target name to add.
3854 * @param content Optional PI content.
3856 void axl_node_add_pi_target (axlNode * node,
3857 char * target,
3858 char * content)
3860 axlPI * pi;
3862 /* perform some environmental checks */
3863 axl_return_if_fail (node);
3864 axl_return_if_fail (target);
3866 /* create the PI element */
3867 pi = axl_pi_create (target, content);
3869 /* set the new process instruction found */
3870 axl_item_set_child (node, ITEM_PI, pi);
3872 return;
3876 /**
3877 * @brief Allows to check if the provided Processing instruction
3878 * target is defined on the given xml node document (\ref axlNode).
3880 * Processing instruction are a way to configure the xml node document
3881 * with processing information to instruct the application level that
3882 * is going to consume the XML information.
3884 * @param node The \ref axlNode where the processing instruction will
3885 * be read.
3887 * @param pi_target The process instruction name.
3889 * @return true is the processing instruction is defined,
3890 * otherwise false is returned.
3892 bool axl_node_has_pi_target (axlNode * node,
3893 char * pi_target)
3895 axlPI * pi;
3896 axlItem * item;
3898 axl_return_val_if_fail (node, false);
3899 axl_return_val_if_fail (pi_target, false);
3901 /* assume the pi target doesn't exist if it is not
3902 * initialized */
3903 item = node->first;
3904 while (item != NULL) {
3906 /* check the type */
3907 if (axl_item_get_type (item) == ITEM_PI) {
3908 /* get a reference */
3909 pi = item->data;
3911 /* only check the first ocurrency */
3912 if (axl_cmp (axl_pi_get_name (pi), pi_target))
3913 return true;
3914 } /* end if */
3916 /* get the next item */
3917 item = item->next;
3919 } /* end while */
3921 return false;
3924 /**
3925 * @brief Allows to get current processing instruction content.
3927 * @param node The document where the processing instruction is placed.
3929 * @param pi_target The processing instruction target to get current
3930 * content.
3932 * @return An internal reference to the process instruction target
3933 * content. Value returned mustn't be deallocated
3935 char * axl_node_get_pi_target_content (axlNode * node,
3936 char * pi_target)
3938 axlPI * pi;
3939 axlItem * item;
3941 axl_return_val_if_fail (node, false);
3942 axl_return_val_if_fail (pi_target, false);
3944 /* assume the pi target doesn't exist if it is not
3945 * initialized */
3946 item = node->first;
3947 while (item != NULL) {
3949 /* check the type */
3950 if (axl_item_get_type (item) == ITEM_PI) {
3951 /* get a reference */
3952 pi = item->data;
3954 /* only check the first ocurrency */
3955 if (axl_cmp (axl_pi_get_name (pi), pi_target))
3956 return axl_pi_get_content (pi);
3957 } /* end if */
3959 /* get the next item */
3960 item = item->next;
3962 } /* end while */
3964 return NULL;
3967 /**
3968 * @brief Allows to transfer (move from) all childs (including
3969 * comments, content, PI, nodes, etc) from the old parent to the new
3970 * parent.
3972 * This function is particular useful while moving content from nodes.
3974 * @param old_parent The old parent node where all childs will be
3975 * removed and and placed in the new parent.
3977 * @param new_parent The parent node where the content will be
3978 * placed. If the parent node already have childs, the content will be
3979 * appended.
3981 void axl_node_transfer_childs (axlNode * old_parent,
3982 axlNode * new_parent)
3984 axlItem * item;
3985 axlItem * item_aux;
3987 /* get the first child for the old parent */
3988 item = old_parent->first;
3989 while (item != NULL) {
3991 /* get a reference to the next before adding */
3992 item_aux = item->next;
3994 /* set the item to parent for the new node */
3995 axl_item_set_child_ref (new_parent, item);
3999 /* get the next */
4000 item = item_aux;
4002 } /* end while */
4004 /* clear reference from previous parent */
4005 old_parent->first = NULL;
4006 old_parent->last = NULL;
4008 return;
4011 /**
4012 * @internal Implementation for the public API provided to dump node content.
4014 bool __axl_node_dump_common (axlNode * node, char ** content, int * size, bool pretty_print, int level, int tabular)
4016 int _size;
4017 int index;
4018 char * result;
4020 /* check refererences received */
4021 axl_return_val_if_fail (node, false);
4022 axl_return_val_if_fail (content, false);
4024 /* get dump size */
4025 _size = axl_node_get_flat_size (node, pretty_print, level, tabular);
4027 /* dump the content */
4028 result = axl_new (char, _size + 1);
4029 index = axl_node_dump_at (node, result, 0, pretty_print, level, tabular);
4031 /* check result */
4032 if (index != _size) {
4033 __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "failed to dump xml node, size dump operation mismatch: %d != %d",
4034 index, _size);
4035 /* free allocated result */
4036 axl_free (result);
4038 /* nullify content */
4039 if (size)
4040 *size = -1;
4041 *content = NULL;
4043 return false;
4044 } /* end if */
4046 /* fill the size */
4047 if (size)
4048 *size = _size;
4049 *content = result;
4051 /* return content */
4052 return true;
4055 /**
4056 * @brief Allows to dump the xml content taking as starting point the
4057 * xml node provided.
4059 * @param node The \ref axlNode to dump.
4061 * @param content The reference where the result will be returned.
4063 * @param size The reference where the document content size will be
4064 * returned.
4066 * @return The function returns \ref true if the dump operation was
4067 * performed. Otherwise \ref false is returned.
4069 bool axl_node_dump (axlNode * node,
4070 char ** content,
4071 int * size)
4073 /* use common implementation for all functions */
4074 return __axl_node_dump_common (node, content, size, false, 0, 0);
4077 /**
4078 * @brief Allows to perform a pretty print operation using as
4079 * reference (starting point) the node provided.
4081 * @param node The node to be used as reference for the dump operation.
4083 * @param content A reference to a user defined pointer where the
4084 * content will be placed. Not optional parameter.
4086 * @param size A reference to a user defined pointer where the content
4087 * size will be placed. Optional parameter.
4089 * @param tabular How many spaces to be placed at each level.
4091 * @return true if the dump operation was properly done, otherwise
4092 * false is returned.
4094 bool axl_node_dump_pretty (axlNode * node,
4095 char ** content,
4096 int * size,
4097 int tabular)
4099 /* use common implementation for all functions */
4100 return __axl_node_dump_common (node, content, size, true, 0, tabular);
4103 /**
4104 * @brief Allows to dump the xml document using as reference the node
4105 * provided, at the file path provided.
4107 * @param node The document node reference to use to build the
4108 * content.
4110 * @param file_path File path where place the result.
4112 * @return \ref true if the dump operation was done, otherwise \ref false is
4113 * returned.
4115 bool axl_node_dump_to_file (axlNode * node,
4116 char * file_path)
4118 char * content;
4119 int size;
4120 FILE * fd;
4121 int written;
4123 /* use common implementation for all functions */
4124 if (! __axl_node_dump_common (node, &content, &size, true, 0, 0))
4125 return false;
4127 /* open the file and check */
4128 #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
4129 if (fopen_s (&fd, file_path, "w") != 0) {
4130 #else
4131 if ((fd = fopen (file_path, "w")) == NULL) {
4132 #endif
4133 /* failed to open the file to dump the content */
4134 axl_free (content);
4136 return false;
4139 /* dump the content */
4140 written = fwrite (content, 1, size, fd);
4142 /* free the content */
4143 axl_free (content);
4145 /* close file */
4146 fclose (fd);
4148 /* return if we have failed to dump all the content to the
4149 * file or not. */
4150 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "returning that the dump was: %s (written:%d == size:%d)",
4151 (written == size) ? "OK" : "FAILED",
4152 written, size);
4154 return (written == size);
4158 /**
4159 * @brief Allows to pretty print dump the xml document using as
4160 * reference the node provided, at the file path provided.
4162 * @param node The document node reference to use to build the
4163 * content.
4165 * @param file_path File path where place the result.
4167 * @param tabular How many spaces to be placed at each level.
4169 * @return \ref true if the dump operation was done, otherwise \ref false is
4170 * returned.
4172 bool axl_node_dump_pretty_to_file (axlNode * node,
4173 char * file_path,
4174 int tabular)
4176 char * content;
4177 int size;
4178 FILE * fd;
4179 int written;
4181 /* use common implementation for all functions */
4182 if (! __axl_node_dump_common (node, &content, &size, true, 0, tabular))
4183 return false;
4185 /* open the file and check */
4186 #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
4187 if (fopen_s (&fd, file_path, "w") != 0) {
4188 #else
4189 if ((fd = fopen (file_path, "w")) == NULL) {
4190 #endif
4191 /* failed to open the file to dump the content */
4192 axl_free (content);
4194 return false;
4197 /* dump the content */
4198 written = fwrite (content, 1, size, fd);
4200 /* free the content */
4201 axl_free (content);
4203 /* close file */
4204 fclose (fd);
4206 /* return if we have failed to dump all the content to the
4207 * file or not. */
4208 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "returning that the dump was: %s (written:%d == size:%d)",
4209 (written == size) ? "OK" : "FAILED",
4210 written, size);
4212 return (written == size);
4215 /**
4216 * @brief Allows to get a list which contains \ref axlPI nodes,
4217 * representing all process instruction that the \ref axlNode (xml
4218 * document node) has.
4220 * While using PI, you can use the following functions to get PI
4221 * information:
4223 * - \ref axl_node_has_pi_target
4224 * - \ref axl_node_get_pi_target_content
4226 * However, this function will return first ocurrency for PI found
4227 * inside the xml document. If you don't use repeated PI elements, you
4228 * won't find problems, but, if you need to iterate ever all PI found
4229 * or you are using repeated PI, you can use this function as follows
4230 * to get current pi elements:
4232 * \code
4233 * void show_all_pi (axlNode * node)
4235 * int iterator;
4236 * axlPI * pi;
4237 * axlList * PIs;
4239 * // get all PI target that the node has
4240 * PIs = axl_node_get_pi_target_list (node);
4241 * iterator = 0;
4243 * while (iterator < axl_list_length (PIs)) {
4244 * // get next pi stored
4245 * pi = axl_list_get_nth (PIs, iterator);
4247 * // do some stuff
4248 * printf ("PI found target name=%s, content=%s\n",
4249 * axl_pi_get_name (pi),
4250 * axl_pi_get_content (pi));
4252 * // update the iterator
4253 * iterator++;
4256 * // once finished, free the list
4257 * axl_list_free (PIs);
4258 * return;
4260 * \endcode
4262 * @param node The xml node (\ref axlNode) where the process
4263 * instruction will be returned.
4265 * @return A reference to the list of processing instruction that the
4266 * xml node (\ref axlNode) has. The returned list, if defined, must be
4267 * deallocated.
4269 axlList * axl_node_get_pi_target_list (axlNode * node)
4271 axlList * result = NULL;
4272 axlItem * item;
4274 axl_return_val_if_fail (node, false);
4276 /* assume the pi target doesn't exist if it is not
4277 * initialized */
4278 item = node->first;
4279 while (item != NULL) {
4281 /* check the type */
4282 if (axl_item_get_type (item) == ITEM_PI) {
4283 /* create the result list */
4284 if (result == NULL)
4285 result = axl_list_new (axl_list_always_return_1, (axlDestroyFunc) axl_pi_free);
4287 /* add the list */
4288 axl_list_add (result, item->data);
4290 } /* end if */
4292 /* get the next item */
4293 item = item->next;
4295 } /* end while */
4297 return result;
4300 bool __axl_node_get_flat_size_attributes_foreach (axlPointer attr,
4301 axlPointer value,
4302 axlPointer user_data)
4304 int * length = user_data;
4306 /* " attribute='value' */
4307 (*length) += 4 + strlen ((char*) attr) + strlen ((char*) value);
4309 /* make the process to continue */
4310 return false;
4313 /**
4314 * @internal
4315 * @brief Returns the space required to write the attribute part.
4317 int __axl_node_get_flat_size_attributes (axlNode * node)
4320 int length = 0;
4321 axlNodeAttr * attr = NULL;
4323 /* if attribute list is not defined just return 0 */
4324 if (node->attributes == NULL)
4325 return 0;
4327 /* perform a foreach and accumulate */
4328 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "get flat size for node <%s>",
4329 axl_node_get_name (node));
4330 if (node->attr_num <= 10) {
4331 /* get the first reference */
4332 attr = (axlNodeAttr *) node->attributes;
4333 while (attr != NULL) {
4334 /* call to get length */
4335 __axl_node_get_flat_size_attributes_foreach (attr->attribute, attr->value, &length);
4337 /* get the next */
4338 attr = attr->next;
4341 } else {
4342 /* perform a foreach */
4343 axl_hash_foreach ((axlHash *) node->attributes, __axl_node_get_flat_size_attributes_foreach, &length);
4346 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "after foreach flat size for node <%s> is %d",
4347 axl_node_get_name (node), length);
4349 /* return the length */
4350 return length;
4353 /**
4354 * @internal
4356 * Returns which the size that the node and its childs will hold if
4357 * the are represented into a flat xml stream.
4359 * @param node The node that is requested its stream xml size.
4361 * @param pretty_print If pretty print is activated.
4363 * @param level Which is the relative level of the node respected to
4364 * the root node.
4366 * @return The stream size or -1 if fails.
4368 int axl_node_get_flat_size (axlNode * node, bool pretty_print, int level, int tabular)
4370 int result = 0;
4371 axlItem * item;
4372 axlNodeContent * content;
4373 bool is_empty;
4374 bool have_childs;
4376 axl_return_val_if_fail (node, -1);
4378 /* get values */
4379 is_empty = axl_node_is_empty (node);
4380 have_childs = axl_node_have_childs (node);
4382 if (have_childs || (!have_childs && !is_empty)) {
4383 /* the node is emtpy because it has no content but it has
4384 * childs:
4386 * "<" + strlen (node-name) + ">" + ... + "</" + strlen (node-name) + ">" */
4387 result = 5 + (2 * strlen (node->name)) + __axl_node_get_flat_size_attributes (node);
4389 /* check pretty_print */
4390 if (pretty_print) {
4391 /* two tabulations plus two carry return \r\n
4392 * on windows and \n on unix */
4393 if (have_childs)
4394 result += (level * tabular * 2) + 2;
4395 else
4396 result += (level * tabular) + 1;
4397 #ifdef __AXL_OS_WIN32__
4398 if (have_childs)
4399 result += 2;
4400 else
4401 result ++;
4402 #endif
4404 } else {
4405 if (is_empty) {
4406 /* "<" + strlen (node-name) + " />" */
4407 result = strlen (node->name) + 4 + __axl_node_get_flat_size_attributes (node);
4409 /* check pretty print */
4410 if (pretty_print) {
4411 /* one tabular plus one carry return
4412 * \r\n on windows and \n on unix */
4413 result += (level * tabular) + 1;
4414 #ifdef __AXL_OS_WIN32__
4415 result += 1;
4416 #endif
4419 /* return sum */
4420 return result;
4424 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node=<%s> count=%d", node->name, result);
4426 /* get first child */
4427 item = node->first;
4428 while (item != NULL) {
4429 /* according to the type, check a size */
4430 switch (axl_item_get_type (item)) {
4431 case ITEM_NODE:
4432 /* count how many bytes the node holds */
4433 result += axl_node_get_flat_size (item->data, pretty_print, level + 1, tabular);
4434 break;
4435 case ITEM_CONTENT:
4436 /* content */
4437 content = (axlNodeContent *) item->data;
4438 result += content->content_size;
4439 break;
4440 case ITEM_CDATA:
4441 /* content + '<![CDATA[' + ']]>' */
4442 content = (axlNodeContent *) item->data;
4443 result += content->content_size + 12;
4444 break;
4445 case ITEM_PI:
4446 /* get current size */
4447 result += axl_pi_get_size (item->data);
4448 break;
4449 case ITEM_COMMENT:
4450 /* content + '<!-- ' + ' -->' */
4451 content = (axlNodeContent *) item->data;
4452 result += content->content_size + 9;
4453 if (pretty_print) {
4454 /* tabular indent + \n */
4455 result += ((level + 1) * tabular) + 1;
4456 #ifdef __AXL_OS_WIN32__
4457 /* \r\n */
4458 result += 1;
4459 #endif
4462 break;
4463 case ITEM_REF:
4464 /* item ref + '&' + ';' */
4465 content = (axlNodeContent *) item->data;
4466 result += content->content_size + 2;
4467 break;
4468 case ITEM_FROM_FACTORY:
4469 case ITEM_CONTENT_FROM_FACTORY:
4470 /* never reached */
4471 break;
4473 /* get next item */
4474 item = item->next;
4476 } /* end while */
4478 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "child processing finished for: parent=<%s>, count=%d", node->name, result);
4480 /* return the result */
4481 return result;
4484 bool __axl_node_dump_attributes_at_foreach (axlPointer key,
4485 axlPointer value,
4486 axlPointer user_data,
4487 axlPointer user_data2)
4489 char * content = user_data;
4490 int * _desp = user_data2;
4491 bool terminator = false;
4492 int desp = (*_desp);
4493 int length;
4495 memcpy (content + desp, " ", 1);
4496 desp += 1;
4498 length = strlen ((char*) key);
4499 memcpy (content + desp, (char *) key, length);
4500 desp += length;
4502 /* check if the content contains a ' so, enclose the attribute
4503 * with " */
4504 if (strstr (value, "'") == NULL) {
4505 memcpy (content + desp, "='", 2);
4506 desp += 2;
4507 }else {
4508 terminator = true;
4509 memcpy (content + desp, "=\"", 2);
4510 desp += 2;
4513 length = strlen ((char*) value);
4514 memcpy (content + desp, (char*) value, length);
4515 desp += length;
4517 /* dump attribute termination */
4518 if (terminator) {
4519 memcpy (content + desp, "\"", 1);
4520 }else {
4521 memcpy (content + desp, "'", 1);
4523 desp += 1;
4525 /* update desp */
4526 (*_desp) = desp;
4528 /* make the process to continue */
4529 return false;
4532 void __axl_node_dump_at_the_end (axlNodeAttr * attr, char * content, int * desp)
4534 /* return if no attribute must be dumped */
4535 if (attr == NULL)
4536 return;
4538 /* call to dump next attributes first */
4539 __axl_node_dump_at_the_end (attr->next, content, desp);
4541 /* now dump our attribute */
4542 __axl_node_dump_attributes_at_foreach (attr->attribute, attr->value, content, desp);
4544 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping attribute: %s=%s", attr->attribute, attr->value);
4546 return;
4549 /**
4550 * @internal
4552 * Internal support function which dumps current attribute
4553 * configuration into the given memory using the provided desp.
4555 int axl_node_dump_attributes_at (axlNode * node, char * content, int desp)
4557 axlNodeAttr * attr = NULL;
4559 /* if attribute list is not defined just return 0 */
4560 if (node->attributes == NULL)
4561 return desp;
4563 /* according to the attribute num */
4564 if (node->attr_num <= 10) {
4565 /* get the first reference */
4566 attr = (axlNodeAttr *) node->attributes;
4567 __axl_node_dump_at_the_end (attr, content, &desp);
4569 } else {
4570 /* foreach attribute dump */
4571 axl_hash_foreach2 ((axlHash *) node->attributes, __axl_node_dump_attributes_at_foreach, content, &desp);
4574 /* return the length */
4575 return desp;
4578 /**
4579 * @internal Writes the indentation according to the tabular size and
4580 * the indent level.
4582 * @param content The reference to the content where the dump
4583 * operation will be performed.
4585 * @param tabular The tabular size to be applied for each level.
4587 * @param level The indent level to be applied.
4589 * @return The number of bytes written.
4591 int __axl_node_dump_at_write_indent (char * content, int tabular, int level)
4593 int iterator = 0;
4595 while (iterator < (tabular * level)) {
4596 /* write tabular info */
4597 memcpy (content + iterator, " ", 1);
4599 /* update iterator */
4600 iterator++;
4601 } /* end while */
4603 return iterator;
4606 /* dump content */
4607 int __axl_node_dump_items (axlItem * item, char * content, int level, bool pretty_print, int desp, int tabular)
4610 axlNodeContent * nodeContent;
4611 char * string_aux;
4613 /* get first child */
4614 while (item != NULL) {
4615 /* according to the type, check a size */
4616 switch (axl_item_get_type (item)) {
4617 case ITEM_NODE:
4618 /* write axl node content */
4619 desp = axl_node_dump_at (item->data, content, desp, pretty_print, level + 1, tabular);
4620 break;
4621 case ITEM_CONTENT:
4622 /* write content information */
4623 nodeContent = (axlNodeContent *)item->data;
4624 memcpy (content + desp, nodeContent->content, nodeContent->content_size);
4625 desp += nodeContent->content_size;
4626 break;
4627 case ITEM_CDATA:
4628 /* write content information */
4629 nodeContent = (axlNodeContent *)item->data;
4631 /* write cdata content */
4632 memcpy (content + desp, "<![CDATA[", 9);
4633 desp += 9;
4635 /* write content */
4636 memcpy (content + desp, nodeContent->content, nodeContent->content_size);
4637 desp += nodeContent->content_size;
4639 /* write cdata end */
4640 memcpy (content + desp, "]]>", 3);
4641 desp += 3;
4642 break;
4643 case ITEM_PI:
4644 /* write pi start */
4645 memcpy (content + desp, "<?", 2);
4646 desp += 2;
4648 /* write pi name */
4649 string_aux = axl_pi_get_name (item->data);
4650 memcpy (content + desp, string_aux, strlen (string_aux));
4651 desp += strlen (string_aux);
4653 /* write pi start */
4654 memcpy (content + desp, " ", 1);
4655 desp += 1;
4657 /* write pi content */
4658 string_aux = axl_pi_get_content (item->data);
4659 memcpy (content + desp, string_aux, strlen (string_aux));
4660 desp += strlen (string_aux);
4662 /* write pi start */
4663 memcpy (content + desp, "?>", 2);
4664 desp += 2;
4665 break;
4666 case ITEM_COMMENT:
4668 /* check for pretty print to write indent */
4669 if (pretty_print) {
4670 desp += __axl_node_dump_at_write_indent (content + desp, tabular, level + 1);
4673 /* content + '<!-- ' + ' -->' */
4674 memcpy (content + desp, "<!-- ", 5);
4675 desp += 5;
4677 /* get a reference to the content */
4678 nodeContent = (axlNodeContent *)item->data;
4680 /* write content */
4681 memcpy (content + desp, nodeContent->content, nodeContent->content_size);
4682 desp += nodeContent->content_size;
4684 memcpy (content + desp, " -->", 4);
4685 desp += 4;
4687 if (pretty_print) {
4688 #ifdef __AXL_OS_WIN32__
4689 memcpy (content + desp, "\r\n", 2);
4690 desp += 2;
4691 #else
4692 memcpy (content + desp, "\n", 1);
4693 desp += 1;
4694 #endif
4697 break;
4698 case ITEM_REF:
4699 /* content + '&' + ';' */
4700 memcpy (content + desp, "&", 1);
4701 desp += 1;
4703 /* get a reference to the content */
4704 nodeContent = (axlNodeContent *)item->data;
4706 /* write content */
4707 memcpy (content + desp, nodeContent->content, nodeContent->content_size);
4708 desp += nodeContent->content_size;
4710 memcpy (content + desp, ";", 1);
4711 desp += 1;
4712 break;
4713 case ITEM_FROM_FACTORY:
4714 case ITEM_CONTENT_FROM_FACTORY:
4715 /* never reached */
4716 break;
4719 /* get next item */
4720 item = item->next;
4722 } /* end while */
4724 /* return desp calculated */
4725 return desp;
4727 } /* end __axl_node_dump_items */
4729 /**
4730 * @internal
4732 * Writes the node information represented by the node provided at the
4733 * given position into the buffer provided.
4735 * @param node The node to dump and its childs.
4737 * @param content The memory buffer where the content will be dumped.
4739 * @param desp A memory desp where to dump the node content inside the
4740 * memory provided.
4742 * @return The new desp value to be used on the next dump.
4744 int axl_node_dump_at (axlNode * node,
4745 char * content,
4746 int desp,
4747 bool pretty_print,
4748 int level,
4749 int tabular)
4751 axlItem * item;
4753 axl_return_val_if_fail (node, -1);
4755 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping node=<%s> at %d",
4756 axl_node_get_name (node), desp);
4758 /* check for pretty print and tabular */
4759 if (pretty_print) {
4760 desp += __axl_node_dump_at_write_indent (content + desp, tabular, level);
4761 } /* end if */
4763 /* check if the node is empty */
4764 if (axl_node_is_empty (node)) {
4765 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node <%s> is empty",
4766 axl_node_get_name (node));
4768 if (! axl_node_have_childs (node)) {
4769 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping an empty node without childs=<%s>",
4770 axl_node_get_name (node));
4772 /* "<" + strlen (node-name) + " />" */
4773 memcpy (content + desp, "<", 1);
4774 desp += 1;
4776 memcpy (content + desp, node->name, strlen (node->name));
4777 desp += strlen (node->name);
4779 /* dump attribute values */
4780 desp = axl_node_dump_attributes_at (node, content, desp);
4782 memcpy (content + desp, " />", 3);
4783 desp += 3;
4785 /* write traling node information */
4786 if (pretty_print) {
4787 #ifdef __AXL_OS_WIN32__
4788 memcpy (content + desp, "\r\n", 2);
4789 desp += 2;
4790 #else
4791 memcpy (content + desp, "\n", 1);
4792 desp += 1;
4793 #endif
4796 return desp;
4800 /* the node is empty because it doesn't have content but it
4801 * has childs
4802 * "<" + strlen (node-name) + ">" + strlen (node-content) +
4803 * "</" + strlen (node-name) + ">" */
4804 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting content for: <%s>", axl_node_get_name (node));
4806 /* dump node start tag */
4807 memcpy (content + desp, "<", 1);
4808 desp += 1;
4810 memcpy (content + desp, node->name, strlen (node->name));
4811 desp += strlen (node->name);
4813 /* dump attribute values */
4814 desp = axl_node_dump_attributes_at (node, content, desp);
4816 memcpy (content + desp, ">", 1);
4817 desp += 1;
4819 /* if the node have childs */
4820 if (axl_node_have_childs (node)) {
4822 /* write traling node information */
4823 if (pretty_print) {
4824 #ifdef __AXL_OS_WIN32__
4825 memcpy (content + desp, "\r\n", 2);
4826 desp += 2;
4827 #else
4828 memcpy (content + desp, "\n", 1);
4829 desp += 1;
4830 #endif
4831 } /* end if */
4833 /* dump content */
4834 item = node->first;
4835 desp = __axl_node_dump_items (item, content, level, pretty_print, desp, tabular);
4837 /* check for pretty print and tabular */
4838 if (pretty_print) {
4839 desp += __axl_node_dump_at_write_indent (content + desp, tabular, level);
4840 } /* end if */
4842 }else {
4843 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node is not empty and have no childs");
4845 /* dump content */
4846 item = node->first;
4847 desp = __axl_node_dump_items (item, content, level, pretty_print, desp, tabular);
4848 } /* end if */
4850 /* dump close tag */
4851 memcpy (content + desp, "</", 2);
4852 desp += 2;
4854 memcpy (content + desp, node->name, strlen (node->name));
4855 desp += strlen (node->name);
4857 memcpy (content + desp, ">", 1);
4858 desp += 1;
4860 /* write traling node information */
4861 if (pretty_print) {
4862 #ifdef __AXL_OS_WIN32__
4863 memcpy (content + desp, "\r\n", 2);
4864 desp += 2;
4865 #else
4866 memcpy (content + desp, "\n", 1);
4867 desp += 1;
4868 #endif
4871 /* return the result */
4872 return desp;
4875 /**
4876 * @brief Allows to check if the provided string have escape sequences
4877 * that must be defined by using the entity reference rather the value
4878 * itself.
4880 * This function is useful in the sense it allows to know if a
4881 * particular content will contain elements not allowed by the XML 1.0
4882 * definition to be placed directly (like &, <, ;, ' and ").
4886 * @param content The content to check.
4888 * @param content_size The size of the content to be checked. If -1 is
4889 * provided, the function will calculate the content length.
4891 * @param added_size An integer reference where the additional size
4892 * variable will be added. This additional size will be the space
4893 * required to replace non-valid characters with entity
4894 * references. This parameter is optional, so passing a NULL value is
4895 * allowed.
4897 * @return true if the string contains non valid sequences that
4898 * must be escaped using entity references.
4900 bool axl_node_has_invalid_chars (const char * content,
4901 int content_size,
4902 int * added_size)
4904 int iterator = 0;
4905 bool result = false;
4906 axl_return_val_if_fail (content, false);
4908 /* reset additional size value */
4909 if (added_size != NULL)
4910 *added_size = 0;
4912 /* calculate the content size */
4913 if (content_size == -1)
4914 content_size = strlen (content);
4916 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking valid sequence: content size=%d", content_size);
4918 /* iterate over all content defined */
4919 while (iterator < content_size) {
4920 /* check for &apos; */
4921 if (content [iterator] == '\'') {
4922 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='\\'");
4923 result = true;
4924 if (added_size != NULL)
4925 (*added_size) += 5;
4928 /* check for &quot; */
4929 if (content [iterator] == '"') {
4930 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='\"'");
4931 result = true;
4932 if (added_size != NULL)
4933 (*added_size) += 5;
4936 /* check for &amp; */
4937 if (content [iterator] == '&') {
4938 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='&'");
4939 result = true;
4940 if (added_size != NULL)
4941 (*added_size) += 4;
4944 /* check for &gt; */
4945 if (content [iterator] == '>') {
4946 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='>'");
4947 result = true;
4948 if (added_size != NULL)
4949 (*added_size) += 3;
4952 /* check for &lt; */
4953 if (content [iterator] == '<') {
4954 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='<'");
4955 result = true;
4956 if (added_size != NULL)
4957 (*added_size) += 3;
4960 /* update the iterator */
4961 iterator++;
4964 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "valid sequence checking result=%d: content size=%d, additional size=%d resul=%s",
4965 result, content_size, (added_size != NULL) ? *added_size : 0, result ? "HAS INVALID SEQUENCES" : "HAS NO INVALID SEQUENCES");
4967 /* return results */
4968 return result;
4971 /**
4972 * @brief Allows to perform a copy for the content provided, doing an
4973 * xml character escaping for non allowed values (&, <, >, ' and ").
4975 * This function must be used with \ref axl_node_has_invalid_chars to
4976 * check if the content has escapable chars an to get the additional
4977 * content that must be allocated by this function.
4979 * Here is an example:
4980 * \code
4981 * char * content = "Some content with invalid chars & < >";
4982 * int additional_size;
4983 * char * new_content
4985 * if (axl_node_has_invalid_chars (content, strlen (content), &additional_size)) {
4986 * // found that the string has invalid chars, escape them
4987 * new_content = axl_node_content_copy_and_escape (content, strlen (content), additional_size);
4988 * }
4990 * \endcode
4992 * @param content The content to be escaped. If this parameter is
4993 * null, the function returns NULL.
4995 * @param content_size The content size for the first parameter.
4997 * @param additional_size The additional size calculated from \ref axl_node_has_invalid_chars.
4999 * @return A newly allocated string with all characters escaped. Use
5000 * \ref axl_free to dealloc the result.
5002 char * axl_node_content_copy_and_escape (const char * content,
5003 int content_size,
5004 int additional_size)
5006 axl_return_val_if_fail (content, NULL);
5008 /* call to the internal implementation */
5009 return __axl_node_content_copy_and_escape (content, content_size, additional_size);
5012 void __axl_node_free_internal (axlNode * node, bool also_childs)
5014 axlItem * item;
5015 axlItem * itemAux;
5017 axl_return_if_fail (node);
5019 /* free current node */
5020 if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
5021 axl_free (node->name);
5023 /* release memory hold by attributes */
5024 if (node->attributes != NULL) {
5025 if (node->attr_num <= 10)
5026 __axl_node_free_attr_list ((axlNodeAttr *) node->attributes);
5027 else
5028 axl_hash_free ((axlHash *) node->attributes);
5031 /* release memory hold by childs */
5032 if (node->first != NULL && also_childs) {
5033 /* get the first item */
5034 item = node->first;
5036 /* foreach item stored */
5037 while (item != NULL) {
5039 /* get the next item */
5040 itemAux = item->next;
5042 /* free the item */
5043 axl_item_free (item, true);
5045 /* update reference */
5046 item = itemAux;
5048 } /* end while */
5050 } /* end if */
5052 /* free the item itself */
5053 if (node->holder != NULL) {
5054 if ((node->holder->type & ITEM_FROM_FACTORY) == 0) {
5055 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG,
5056 "item holder found to be not from a factory, dealloc reference=0x%x, node=0x%x, type=%d",
5057 node->holder, node, node->holder->type);
5058 axl_free (node->holder);
5059 node->holder = NULL;
5063 /* do not free the node itself */
5064 return;
5067 /**
5068 * @brief Destroy the given node provided by the reference.
5070 * The function will check for nodes that are null references.
5072 * @param node The node to destroy.
5074 void axl_node_free (axlNode * node)
5076 axlHash * hash;
5077 axl_return_if_fail (node);
5079 /* get a reference to the hash */
5080 hash = node->annotate_data;
5082 /* free internal content */
5083 __axl_node_free_internal (node, true);
5085 /* free attributes */
5086 if (! (node->conf & NODE_FROM_FACTORY))
5087 axl_free (node);
5089 /* annotate data deallocation must be done here because it is
5090 * used by the application user and the library to store
5091 * reference that could be pointing to internal structures
5092 * deallocated by the __axl_node_free_internal */
5093 axl_hash_free (hash);
5095 /* the node to release */
5096 return;
5099 /**
5100 * @brief Allows to remove the provided node without removing childs
5101 * inside it.
5103 * @param node The node to deallocate.
5105 * @param also_childs Signal the function to dealloc childs or not.
5107 void axl_node_free_full (axlNode * node, bool also_childs)
5109 axlHash * hash;
5110 axl_return_if_fail (node);
5112 /* get a reference to the hash */
5113 hash = node->annotate_data;
5115 /* free node */
5116 __axl_node_free_internal (node, false);
5118 /* free the node itself */
5119 if (!(node->conf & NODE_FROM_FACTORY))
5120 axl_free (node);
5122 /* annotate data deallocation must be done here because it is
5123 * used by the application user and the library to store
5124 * reference that could be pointing to internal structures
5125 * deallocated by the __axl_node_free_internal */
5126 axl_hash_free (hash);
5128 return;
5132 * @}
5136 * \defgroup axl_node_attribute_cursor Axl Node Attribute iteration: An interface provided to iterate attribute nodes without knowing them.
5139 /**
5140 * \addtogroup axl_node_attribute_cursor
5141 * @{
5145 /**
5146 * @brief Allows to get a cursor to iterate attributes found in the
5147 * provided node in a linear and efficient way.
5149 * The \ref axlAttrCursor could be used to iterate attributes
5150 * inside a particular node in an efficient way because it stores
5151 * current state (position), hiding all module details, providing
5152 * access to attributes without knowing them. Then using the following
5153 * functions you can modify the state (current position to get):
5155 * - \ref axl_node_attr_cursor_first
5156 * - \ref axl_node_attr_cursor_next
5158 * Finally, the following functions are provided to get the the key
5159 * and the value data associated to the current selected attribute,
5160 * pointed by the current status of the cursor:
5162 * - \ref axl_node_attr_cursor_get_key (returns the key of the current attribute selected)
5163 * - \ref axl_node_attr_cursor_get_value (returns the value of the current attribute selected)
5165 * Here is an example:
5166 * \code
5167 * axlPointer key;
5168 * axlPointer value;
5169 * axlAttrCursor * cursor;
5171 * // create the cursor
5172 * cursor = axl_node_attr_cursor_new (node);
5174 * // while there are more elements
5175 * while (axl_node_attr_cursor_has_item (cursor)) {
5177 * // get the value and key
5178 * key = axl_node_attr_cursor_get_key (cursor);
5179 * value = axl_node_attr_cursor_get_value (cursor);
5181 * // get the next
5182 * axl_node_attr_cursor_next (cursor);
5184 * }
5186 * // free the cursor
5187 * axl_node_attr_cursor_free (cursor);
5188 * \endcode
5190 * Once created the \ref axlAttrCursor you must release it and
5191 * create a new one if you modify your \ref axlNode attribute configuration
5192 * adding more items.
5194 * @param node The node that is requested to create the \ref
5195 * axlAttrCursor reference to iterate all attributes inside.
5197 * @return A newly created \ref axlAttrCursor used to iterate
5198 * attributes inside the node provided. Once finished you must call to
5199 * \ref axl_node_attr_cursor_free.
5201 axlAttrCursor * axl_node_attr_cursor_new (axlNode * node)
5203 axlAttrCursor * cursor;
5205 axl_return_val_if_fail (node, NULL);
5207 /* create and configure basics */
5208 cursor = axl_new (axlAttrCursor, 1);
5209 cursor->node = node;
5210 cursor->count = node->attr_num;
5212 /* according to the number of attributes configure the hash or
5213 * the linked attribte list */
5214 if (cursor->count <= 10) {
5215 /* just point to the first attribute (managed as AxlNodeAttr) */
5216 cursor->data = node->attributes;
5217 } else {
5218 /* create an axl hash cursor */
5219 cursor->data = axl_hash_cursor_new ((axlHash *) node->attributes);
5220 } /* end if */
5222 /* return created cursor */
5223 return cursor;
5226 /**
5227 * @brief Allows to configure the provided cursor to point to the
5228 * first attribute found inside the node.
5230 * @param cursor The cursor that is going to be configured.
5232 void axl_node_attr_cursor_first (axlAttrCursor * cursor)
5234 axl_return_if_fail (cursor);
5236 /* check attribute configuration */
5237 if (cursor->count != cursor->node->attr_num) {
5238 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5239 return;
5240 } /* end if */
5242 if (cursor->count <= 10) {
5243 /* just point to the first attribute (managed as AxlAttribute) */
5244 cursor->data = cursor->node->attributes;
5245 } else {
5246 /* make hash cursor to point to the first */
5247 axl_hash_cursor_first (cursor->data);
5248 } /* end if */
5250 return;
5253 /**
5254 * @brief Configures the provided attribute cursor to point to the
5255 * next attribute.
5257 * @param cursor The attribute cursor to be configured.
5259 void axl_node_attr_cursor_next (axlAttrCursor * cursor)
5261 axl_return_if_fail (cursor);
5263 /* check attribute configuration */
5264 if (cursor->count != cursor->node->attr_num) {
5265 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5266 return;
5267 } /* end if */
5269 if (cursor->count <= 10) {
5270 /* check null values */
5271 if (cursor->data == NULL)
5272 return;
5274 /* just point to the first attribute (managed as AxlAttribute) */
5275 cursor->data = ((axlNodeAttr *) cursor->data)->next;
5277 return;
5278 } /* end if */
5280 /* make hash cursor to point to the first */
5281 axl_hash_cursor_next (cursor->data);
5284 return;
5287 /**
5288 * @brief Allows to check if the is a next attribute, following
5289 * current attribute selected.
5291 * @param cursor The cursor to be configured.
5293 * @return \ref true if it has next element, otherwise \ref false.
5295 bool axl_node_attr_cursor_has_next (axlAttrCursor * cursor)
5297 axl_return_val_if_fail (cursor, false);
5299 if (cursor->count != cursor->node->attr_num) {
5300 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5301 return false;
5302 } /* end if */
5304 if (cursor->count <= 10) {
5305 /* just point to the first attribute (managed as AxlAttribute) */
5306 return (((axlNodeAttr *) cursor->data)->next) != NULL;
5307 } /* end if */
5309 /* make hash cursor to point to the first */
5310 return axl_hash_cursor_has_next (cursor->data);
5313 /**
5314 * @brief Allows to check if the current position selected has an
5315 * attribute reference.
5317 * @param cursor The cursor that is being queried.
5319 * @return \ref true if it has item element, otherwise \ref false.
5321 bool axl_node_attr_cursor_has_item (axlAttrCursor * cursor)
5323 axl_return_val_if_fail (cursor, false);
5325 /* check attribute configuration */
5326 if (cursor->count != cursor->node->attr_num) {
5327 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5328 return false;
5329 } /* end if */
5331 if (cursor->count <= 10) {
5332 /* just point to the first attribute (managed as AxlAttribute) */
5333 return cursor->data != NULL;
5334 } /* end if */
5336 /* make hash cursor to point to the first */
5337 return axl_hash_cursor_has_item (cursor->data);
5340 /**
5341 * @brief Allows to get the attribute key associated to the attribute
5342 * selected by the cursor.
5344 * @param cursor The cursor that is being queried.
5346 * @return A reference to the attribute key or NULL if it fails.
5348 const char * axl_node_attr_cursor_get_key (axlAttrCursor * cursor)
5350 axl_return_val_if_fail (cursor, NULL);
5352 /* check attribute configuration */
5353 if (cursor->count != cursor->node->attr_num) {
5354 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5355 return NULL;
5356 } /* end if */
5358 if (cursor->count <= 10) {
5359 /* just point to the first attribute (managed as AxlAttribute) */
5360 return ((axlNodeAttr *) cursor->data)->attribute;
5361 } /* end if */
5363 /* make hash cursor to point to the first */
5364 return axl_hash_cursor_get_key (cursor->data);
5367 /**
5368 * @brief Allows to get the attribute value associated to the
5369 * attribute selected by the cursor.
5371 * @param cursor The cursor that is being queried.
5373 * @return A reference to the attribute value or NULL if it fails.
5375 const char * axl_node_attr_cursor_get_value (axlAttrCursor * cursor)
5377 axl_return_val_if_fail (cursor, NULL);
5379 /* check attribute configuration */
5380 if (cursor->count != cursor->node->attr_num) {
5381 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5382 return NULL;
5383 } /* end if */
5385 if (cursor->count <= 10) {
5386 /* just point to the first attribute (managed as AxlAttribute) */
5387 return ((axlNodeAttr *) cursor->data)->value;
5388 } /* end if */
5390 /* make hash cursor to point to the first */
5391 return axl_hash_cursor_get_value (cursor->data);
5394 /**
5395 * @brief Allows to release \ref axlAttrCursor.
5397 * @param cursor The cursor to release.
5399 void axl_node_attr_cursor_free (axlAttrCursor * cursor)
5401 axl_return_if_fail (cursor);
5403 /* free hash cursor */
5404 if (cursor->count > 10)
5405 axl_hash_cursor_free (cursor->data);
5407 /* free the cursor */
5408 axl_free (cursor);
5410 return;
5414 /**
5415 * @internal Function that helps axl_node_attr_foreach to iterate all
5416 * attributes.
5418 bool __axl_node_attr_foreach_aux (axlPointer key, axlPointer data, axlPointer user_data, axlPointer user_data2, axlPointer user_data3)
5420 return ((axlNodeAttrForeachFunc) user_data) (key, data, user_data2, user_data3);
5423 /**
5424 * @brief Allows to provide a function which is called foreach
5425 * attribute installed on the provided node.
5427 * This function will allow you to operate on every attribute
5428 * installed, doing an foreach operation. This is an alternative API
5429 * to the \ref axlAttrCursor, which could be used to save allocations.
5431 * @param node The node for which the provided function will be called
5432 * for each attribute found.
5434 * @param func The foreach function to be called.
5436 * @param data User defined data to be passed to the foreach function.
5438 * @param data2 Second user defined data to be passed to the foreach
5439 * function.
5441 void axl_node_attr_foreach (axlNode * node,
5442 axlNodeAttrForeachFunc func,
5443 axlPointer data,
5444 axlPointer data2)
5446 axlNodeAttr * attr;
5447 axl_return_if_fail (node);
5448 axl_return_if_fail (func);
5450 /* if no attributes no foreach operation */
5451 if (node->attributes == NULL)
5452 return;
5454 /* store the attribute using the general case */
5455 if (node->attr_num < 11) {
5456 /* handled as a simple list */
5457 attr = (axlNodeAttr *) node->attributes;
5458 while (attr != NULL) {
5459 /* call to notify each attribute */
5460 if (func (attr->attribute, attr->value, data, data2))
5461 return;
5463 /* get the next */
5464 attr = attr->next;
5465 } /* end while */
5466 } else {
5467 /* handled as a hash */
5468 axl_hash_foreach3 ((axlHash *) node->attributes, __axl_node_attr_foreach_aux, func, data, data2);
5469 } /* end if */
5471 return;
5475 * @}
5479 * \defgroup axl_item_module Axl Item: A basic item abstraction that represents a child node that could be another node, content, xml comment, etc.
5482 /**
5483 * \addtogroup axl_item_module
5484 * @{
5487 /**
5488 * @brief Allows to create an \ref axlItem, with the provided type and
5489 * holding the provided data.
5491 * The function won't configure the parent node holding the
5492 * item. There is an alternative API that allows to create an \ref
5493 * axlItem without performing a copy: \ref axl_item_new_ref.
5495 * @param type The type that will represent the \ref axlItem created.
5496 * @param data Data associated to the axlItem. In the case the \ref
5497 * axlItem being created will represent content (\ref ITEM_CONTENT),
5498 * an entity ref (\ref ITEM_REF), a comment (\ref ITEM_COMMENT) or
5499 * cdata (\ref ITEM_CDATA), the function will create a local copy. In
5500 * the case of a \ref ITEM_NODE, the function will copy the entire
5501 * node, and all its childs.
5503 * @return A newly allocated \ref axlItem with no parent and holding
5504 * the data provided.
5506 axlItem * axl_item_new (AxlItemType type,
5507 axlPointer data)
5509 axlItem * item = NULL;
5510 axlNode * node;
5511 axlNodeContent * content;
5513 /* allocate an item type */
5514 item = axl_new (axlItem, 1);
5515 item->type = type;
5517 switch (axl_item_get_type (item)) {
5518 case ITEM_NODE:
5519 /* item the node */
5520 node = axl_node_copy (item->data, true, true);
5521 node->holder = item;
5522 item->data = node;
5523 break;
5524 case ITEM_CONTENT:
5525 case ITEM_CDATA:
5526 case ITEM_COMMENT:
5527 /* item content */
5528 content = axl_new (axlNodeContent, 1);
5529 content->content = axl_strdup ((const char *) data);
5530 content->content_size = strlen ((const char *) data);
5532 /* item content */
5533 item->data = content;
5534 break;
5535 case ITEM_PI:
5536 /* item pi */
5537 item->data = axl_pi_copy (data);
5538 break;
5539 case ITEM_REF:
5540 /* not implemented yet */
5541 break;
5542 case ITEM_FROM_FACTORY:
5543 case ITEM_CONTENT_FROM_FACTORY:
5544 /* never reached */
5545 break;
5546 } /* end switch */
5548 /* return item created */
5549 return item;
5552 /**
5553 * @brief Allows to create an \ref axlItem, with the provided type and
5554 * holding the provided data.
5556 * The function won't configure the parent node holding the item.
5558 * @param type The type that will represent the \ref axlItem created.
5559 * @param data Data associated to the axlItem. This function won't
5560 * perform any copy for the data received. The user calling to this
5561 * API will ensure that the data is only owned by the \ref axlItem
5562 * created.
5564 * @return A newly allocated \ref axlItem with no parent and holding
5565 * the data provided.
5567 axlItem * axl_item_new_ref (AxlItemType type,
5568 axlPointer data)
5570 axlItem * item = NULL;
5571 axlNode * node;
5572 axlNodeContent * content;
5574 /* allocate an item type */
5575 item = axl_new (axlItem, 1);
5576 item->type = type;
5578 switch (axl_item_get_type (item)) {
5579 case ITEM_NODE:
5580 /* item the node */
5581 node = data;
5582 node->holder = item;
5583 item->data = node;
5584 break;
5585 case ITEM_CONTENT:
5586 case ITEM_CDATA:
5587 case ITEM_COMMENT:
5588 /* item content */
5589 content = axl_new (axlNodeContent, 1);
5590 content->content = data;
5591 content->content_size = strlen ((const char *) data);
5593 /* item content */
5594 item->data = content;
5595 break;
5596 case ITEM_PI:
5597 /* item pi */
5598 item->data = data;
5599 break;
5600 case ITEM_REF:
5601 /* not implemented yet */
5602 break;
5603 case ITEM_FROM_FACTORY:
5604 case ITEM_CONTENT_FROM_FACTORY:
5605 /* never reached */
5606 break;
5607 } /* end switch */
5609 /* return item created */
5610 return item;
5614 /**
5615 * @brief Allows to get the reference to the document that is holding
5616 * the provided item without taking into consideration the item type.
5618 * @param item The item that is required to return its document.
5620 * @return A reference to the \ref axlDoc that is holding the item.
5622 axlDoc * axl_item_get_doc (axlItem * item)
5624 axl_return_val_if_fail (item, NULL);
5626 /* return the document reference */
5627 return item->doc;
5630 /**
5631 * @internal Internal function that allows to configure the document
5632 * that is holding the item provided.
5634 * @param item The axlItem to be configured.
5635 * @param doc The axlDoc reference to configure.
5637 void axl_item_set_doc (axlItem * item, axlDoc * doc)
5639 axl_return_if_fail (item);
5641 /* configure document */
5642 item->doc = doc;
5644 return;
5647 /**
5648 * @brief Allows to get the parent that is containing the \ref axlItem
5649 * provider. The parent of a \ref axlItem is always a node.
5651 * @param item The \ref axlItem reference that is required to return
5652 * its parent.
5654 * @return A reference to the \ref axlNode.
5656 axlNode * axl_item_get_parent (axlItem * item)
5658 /* return that we don't have parent */
5659 if (item == NULL)
5660 return NULL;
5662 /* return the parent */
5663 return item->parent;
5666 /**
5667 * @brief Allows to get the following element that is next to the item
5668 * reference provided (\ref axlItem), at the same level.
5670 * @param item The item that is required to return its next reference.
5672 * @return A reference to the next element or NULL if no it fails or
5673 * no element is found next to the element provided.
5675 axlItem * axl_item_get_next (axlItem * item)
5677 axl_return_val_if_fail (item, NULL);
5679 /* return the next element */
5680 return item->next;
5683 /**
5684 * @brief Returns the following \ref axlItem to the \ref axlNode
5685 * reference, in the same level.
5687 * @param node The node that is required to return the following item
5688 * to it.
5690 * @return An reference to the following or NULL.
5692 axlItem * axl_item_node_next (axlNode * node)
5694 axl_return_val_if_fail (node, NULL);
5696 if (node->holder != NULL) {
5697 /* return the next */
5698 return node->holder->next;
5701 /* no holder, no next */
5702 return NULL;
5706 /**
5707 * @brief Allows to get the following element that is previous to the item
5708 * reference provided (\ref axlItem), at the same level.
5710 * @param item The item that is required to return its previous reference.
5712 * @return A reference to the previous element or NULL if no it fails or
5713 * no element is found previous to the element provided.
5715 axlItem * axl_item_get_previous (axlItem * item)
5717 axl_return_val_if_fail (item, NULL);
5719 /* return the previous element */
5720 return item->previous;
5723 /**
5724 * @brief Returns the previous \ref axlItem to the \ref axlNode
5725 * reference, in the same level.
5727 * @param node The node that is required to return the previous item
5728 * to it.
5730 * @return An reference to the previous or NULL.
5732 axlItem * axl_item_node_previous (axlNode * node)
5734 axl_return_val_if_fail (node, NULL);
5736 if (node->holder != NULL) {
5737 /* return the previousx */
5738 return node->holder->previous;
5741 /* no holder, no previous */
5742 return NULL;
5745 /**
5746 * @brief Allows to get the \ref axlItem reference that is holding the
5747 * node provided.
5749 * @param node The node that is required to return its holding item.
5751 * @return The item reference or NULL if it fails or it isn't set.
5753 axlItem * axl_item_node_holder (axlNode * node)
5755 axl_return_val_if_fail (node, NULL);
5757 /* return the holder */
5758 return node->holder;
5761 /**
5762 * @brief Allows to get the very first child item stored on the
5763 * provided \ref axlNode.
5765 * This function is similar to \ref axl_node_get_first_child, but
5766 * returning the first \ref axlItem no matter its type.
5768 * This function is mainly used inside the MIXED API where nodes are
5769 * expected to enclose content mixed with another xml nodes. See \ref
5770 * axl_node_get_first_child for more details.
5772 * @param node The \ref axlNode reference that is required to return
5773 * is first child reference (\ref axlItem).
5775 * @return The \ref axlItem reference or NULL if the axlNode is empty
5776 * (\ref axl_node_is_empty) and have no childs (\ref
5777 * axl_node_have_childs). The function also returns NULL if it fails
5778 * (when it receives a NULL reference).
5780 axlItem * axl_item_get_first_child (axlNode * node)
5782 /* check reference received */
5783 axl_return_val_if_fail (node, NULL);
5785 /* return the first item reference */
5786 return node->first;
5789 /**
5790 * @brief Allows to get the very last child item stored on the
5791 * provided \ref axlNode.
5793 * This function is similar to \ref axl_node_get_last_child, but
5794 * returning the last \ref axlItem no matter its type.
5796 * This function is mainly used inside the MIXED API where nodes are
5797 * expected to enclose content mixed with another xml nodes. See \ref
5798 * axl_node_get_last_child for more details.
5800 * @param node The \ref axlNode reference that is required to return
5801 * is last child reference (\ref axlItem).
5803 * @return The \ref axlItem reference or NULL if the axlNode is empty
5804 * (\ref axl_node_is_empty) and have no childs (\ref
5805 * axl_node_have_childs). The function also returns NULL if it fails
5806 * (when it receives a NULL reference).
5808 axlItem * axl_item_get_last_child (axlNode * node)
5810 /* check reference received */
5811 axl_return_val_if_fail (node, NULL);
5813 /* return the last item reference */
5814 return node->last;
5817 /**
5818 * @brief Allows to get the item type that represents the reference
5819 * received (\ref axlItem).
5821 * Every \ref axlItem represents a particular content that could be
5822 * found inside an xml document parsed by the library (\ref
5823 * axlDoc). This function allows to return the type associated to the
5824 * element encapsulated by the \ref axlItem. See \ref AxlItemType for
5825 * more details.
5827 * @param item The reference that is required to return its type.
5829 * @return The type that is inside the reference or -1 if it fails.
5831 AxlItemType axl_item_get_type (axlItem * item)
5833 /* return stored type */
5834 return item->type & (~ (ITEM_FROM_FACTORY | ITEM_CONTENT_FROM_FACTORY));
5837 /**
5838 * @brief Returns the item data that is stored inside the \ref axlItem
5839 * received.
5841 * According to the type that is representing the \ref axlItem
5842 * received, it will return a particular type. Check \ref AxlItemType
5843 * for more information.
5845 * @param item The item that is required to return the data
5846 * encapsulated on it.
5848 * @return A pointer to the data stored, or NULL if it fails. The
5849 * pointer returned, in the case it is defined, mustn't be
5850 * released. It is a internal reference to the content.
5852 axlPointer axl_item_get_data (axlItem * item)
5854 axl_return_val_if_fail (item, NULL);
5856 /* return stored type */
5857 return item->data;
5860 /**
5861 * @brief Convenience API that allows to get the content stored (and
5862 * its size) from the received \ref axlItem, supposing it is storing
5863 * an \ref ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref ITEM_REF.
5865 * @param item The \ref axlItem that is supposed to store an item with type: \ref ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref ITEM_REF.
5867 * @param size Optional variable reference. If defined, if returns the
5868 * content size.
5870 * @return An internal reference to the content stored and optionally
5871 * the content size notified on the variable received. In the case the
5872 * function receives an incompatible \ref axlItem (which is not \ref
5873 * ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref ITEM_REF),
5874 * the function will return NULL, and the optional variable will be
5875 * filled with -1.
5877 char * axl_item_get_content (axlItem * item,
5878 int * size)
5880 axlNodeContent * content;
5882 /* check content received */
5883 if (size != NULL)
5884 *size = -1;
5886 /* check if the item reference is NULL */
5887 axl_return_val_if_fail (item,
5888 NULL);
5889 axl_return_val_if_fail (axl_item_get_type (item) != ITEM_NODE && axl_item_get_type (item) != ITEM_PI,
5890 NULL);
5892 /* get the content */
5893 content = item->data;
5895 /* fill the size */
5896 if (size != NULL)
5897 *size = content->content_size;
5899 /* return a pointer to the content */
5900 return content->content;
5903 /* prepare the item to be added to the xml document */
5904 axlItem * __axl_item_common_configure (axlNode * parent, AxlItemType type, axlPointer data)
5906 axlNode * node = NULL;
5907 axlItem * item = NULL;
5909 /* return if the parent is defined */
5910 axl_return_val_if_fail (parent, NULL);
5912 /* check if the node received already have a pointer to a
5913 * holder created */
5914 if (type & ITEM_NODE) {
5915 /* get a reference to the node */
5916 node = (axlNode *) data;
5918 /* get a reference to the holder */
5919 item = node->holder;
5921 /* check if the current item was allocated from a
5922 * factory to ensure we don't loose that
5923 * information */
5924 if ((item != NULL) && (item->type & ITEM_FROM_FACTORY))
5925 type = type | ITEM_FROM_FACTORY;
5928 /* create an item to hold the child, configuring the node, the
5929 * parent and the document */
5930 if (item == NULL) {
5931 if ((parent->holder != NULL) && (parent->holder->doc != NULL)) {
5932 item = axl_item_factory_get (axl_doc_get_item_factory (parent->holder->doc));
5933 type = type | ITEM_FROM_FACTORY;
5934 } else
5935 item = axl_new (axlItem, 1);
5937 item->type = type;
5938 item->data = data;
5939 item->doc = (parent->holder != NULL) ? parent->holder->doc : NULL;
5941 if (item->type & ITEM_NODE) {
5942 /* now configure the item that will hold the new child */
5943 node->holder = item;
5944 } /* end if */
5946 /* return item created */
5947 return item;
5950 /**
5951 * @internal Function that helps adding a new item to the provided
5952 * parent node.
5954 * The new item will be added as flaged by the type provided. The
5955 * function isn't exposed to the public API because there are better
5956 * alternatives to add items to a \ref axlNode. Don't use this API
5957 * directly.
5959 * @param parent The axl node that will receive the new content.
5961 * @param type The type to configure to the new item.
5963 * @param data The data associated to the data being stored.
5965 * NOTE: the function doesn't check data received as it is supposed to
5966 * receive calls from the library.
5968 void axl_item_set_child (axlNode * parent, AxlItemType type, axlPointer data)
5970 axlItem * item;
5972 /* prepare the item to be added to the xml document */
5973 item = __axl_item_common_configure (parent, type, data);
5975 /* call to set child with a created item */
5976 axl_item_set_child_ref (parent, item);
5978 return;
5981 /**
5982 * @brief Allows to configure xml content just after the item used as
5983 * reference.
5985 * @param item The item used as reference to place the content after it.
5987 * @param type AxlItemType to configure the content to be placed.
5989 * @param data Pointer that is
5991 void axl_item_set_after (axlItem * item,
5992 AxlItemType type,
5993 axlPointer data)
5995 axlItem * new_item = NULL;
5997 /* prepare the item to be added to the xml document */
5998 new_item = __axl_item_common_configure (item->parent, type, data);
6000 /* configure the parent node */
6001 new_item->parent = item->parent;
6003 /* configure new item references */
6004 new_item->previous = item;
6005 new_item->next = item->next;
6007 /* configure item references */
6008 if (item->next != NULL)
6009 item->next->previous = new_item;
6010 else
6011 item->parent->last = new_item;
6012 item->next = new_item;
6014 return;
6017 /* call to set child with a created item */
6018 void axl_item_set_child_ref (axlNode * parent, axlItem * item)
6020 axl_return_if_fail (parent);
6021 axl_return_if_fail (item);
6023 /* configure the parent node */
6024 item->parent = parent;
6026 /* get the current last child */
6027 if (parent->first == NULL) {
6028 /* init first and last reference to the only one
6029 * child */
6030 parent->first = item;
6031 parent->last = item;
6032 }else {
6033 /* configure the next item to the current last
6034 * child */
6035 parent->last->next = item;
6037 /* update the last child reference */
6038 item->previous = parent->last;
6039 item->next = NULL;
6040 parent->last = item;
6043 return;
6046 /**
6047 * @brief Copies the reference provided creating a newly allocated
6048 * copy, including he content inside.
6050 * @param item The item to copy.
6052 * @param set_parent Optionally, allows to provide the parent to be
6053 * configured to the item created. This is really required while
6054 * copying items that contains nodes.
6056 * @return A newly allocated \ref axlItem reference, containing the
6057 * same data (a deep copy) and optionally configured with the provided
6058 * parent.
6060 axlItem * axl_item_copy (axlItem * item, axlNode * set_parent)
6062 axlItem * copy;
6063 axlNode * node;
6064 axlNodeContent * content;
6066 /* check values received */
6067 axl_return_val_if_fail (item, NULL);
6069 /* allocate an copy type */
6070 copy = axl_new (axlItem, 1);
6071 copy->type = axl_item_get_type (item);
6072 copy->parent = set_parent;
6074 switch (axl_item_get_type (item)) {
6075 case ITEM_NODE:
6076 /* copy the node */
6077 node = axl_node_copy (item->data, true, true);
6078 node->holder = copy;
6079 copy->data = node;
6080 break;
6081 case ITEM_CONTENT:
6082 case ITEM_CDATA:
6083 case ITEM_COMMENT:
6084 /* copy content */
6085 content = axl_new (axlNodeContent, 1);
6086 content->content = axl_strdup (((axlNodeContent * ) item->data)->content);
6087 content->content_size = ((axlNodeContent * ) item->data)->content_size;
6089 /* copy content */
6090 copy->data = content;
6091 break;
6092 case ITEM_PI:
6093 /* copy pi */
6094 copy->data = axl_pi_copy (item->data);
6095 break;
6096 case ITEM_REF:
6097 /* not implemented yet */
6098 break;
6099 case ITEM_FROM_FACTORY:
6100 case ITEM_CONTENT_FROM_FACTORY:
6101 /* never reached */
6102 break;
6103 } /* end switch */
6105 /* return copy created */
6106 return copy;
6109 /**
6110 * @brief Allows to remove the \ref axlItem instance from the document
6111 * that is currently linked, optionally deallocating the memory used
6112 * by the structure.
6114 * @param item The item to remove from its container (without taking
6115 * into consideration the item type).
6117 * @param dealloc Deallocs the memory used by the \ref axlItem
6118 * reference.
6120 void axl_item_remove (axlItem * item,
6121 bool dealloc)
6124 /* free the item */
6125 axl_return_if_fail (item);
6127 /* realloc references */
6128 if (item->previous != NULL)
6129 item->previous->next = item->next;
6131 if (item->next != NULL)
6132 item->next->previous = item->previous;
6134 /* realloc parent references in the case of a node */
6135 if (axl_item_get_type (item) == ITEM_NODE) {
6136 if (item->previous == NULL)
6137 item->parent->first = item->next;
6139 if (item->next == NULL)
6140 item->parent->last = item->previous;
6141 } /* end if */
6143 /* free the item */
6144 item->next = NULL;
6145 item->previous = NULL;
6147 if (dealloc) {
6148 axl_item_free (item, true);
6149 } /* end if */
6151 return;
6153 } /* end axl_item_remove */
6155 /**
6156 * @brief Allows to replace the content held by the \ref axlItem
6157 * reference with a new \ref axlItem, updating all references, and
6158 * optionally, deallocating the memory used by the previous node.
6160 * @param item The item to be replaced.
6162 * @param new_item The new item to be placed where the previous one is
6163 * located.
6165 * @param dealloc Signal to function to dealloc the memory hold the
6166 * the item replaced.
6168 void axl_item_replace (axlItem * item,
6169 axlItem * new_item,
6170 bool dealloc)
6172 /* free the item */
6173 axl_return_if_fail (item);
6174 axl_return_if_fail (new_item);
6176 /* realloc references */
6177 if (item->previous != NULL) {
6178 item->previous->next = new_item;
6179 new_item->previous = item->previous;
6182 if (item->next != NULL) {
6183 item->next->previous = new_item;
6184 new_item->next = item->next;
6187 /* realloc parent references in the case of a node */
6188 if (axl_item_get_type (item) == ITEM_NODE) {
6189 if (item->previous == NULL)
6190 item->parent->first = new_item;
6192 if (item->next == NULL)
6193 item->parent->last = new_item;
6194 } /* end if */
6196 /* free the item */
6197 item->next = NULL;
6198 item->previous = NULL;
6200 /* configure values */
6201 new_item->parent = item->parent;
6202 new_item->doc = item->doc;
6204 if (dealloc) {
6205 axl_item_free (item, true);
6207 } /* end if */
6209 return;
6211 } /* end axl_item_replace */
6213 /**
6214 * @brief Allows to transfer all childs contained inside the provided
6215 * \ref axlNode (old_parent) placed after the provided axlItem
6216 * (item_ref) on the same level.
6218 * This function allows to manipulate a xml document loaded inside
6219 * memory, by transfering all childs (including xml nodes, xml
6220 * comments, content, process instructions and entity references) from
6221 * the selected parent (the old parent) provided by the
6222 * <i>old_parent</i> attribute, to be placed at the same level, where
6223 * the <i>item_ref</i> is situated following it.
6226 * @param old_parent Previous parent, where the childs to be
6227 * transfered will be found.
6229 * @param item_ref The \ref axlItem that will act as a reference
6230 * placing all childs following the item.
6232 void axl_item_transfer_childs_after (axlNode * old_parent,
6233 axlItem * item_ref)
6235 axlItem * item;
6236 axlItem * item_aux;
6238 /* get the first child for the old parent */
6239 item = old_parent->first;
6241 /* check if the parent node contains childs to be
6242 * transferred. If no child is found, just return */
6243 if (item == NULL)
6244 return;
6246 /* remember previous next */
6247 item_aux = item_ref->next;
6249 /* make the first child to follow the item ref */
6250 item_ref->next = item;
6251 item->previous = item_ref;
6253 /* set the next at the end of all items transferred, and the
6254 * new parent node */
6255 while (item != NULL) {
6256 /* configure the new parent */
6257 item->parent = item_ref->parent;
6259 /* check the item to be the last */
6260 if (item->next == NULL) {
6261 /* the last item was found, configure it */
6262 item->next = item_aux;
6264 /* configure it to point to the last item
6265 * transferred */
6266 if (item_aux != NULL)
6267 item_aux->previous = item;
6269 /* break the loop! */
6270 break;
6271 } /* end if */
6273 /* get the next */
6274 item = item->next;
6276 } /* end while */
6278 /* check that the item selected to be reference isn't the last
6279 * child inside new parent node. If it is, update the new
6280 * last */
6281 if (item_aux == NULL) {
6282 /* because item is pointing to the last item in the
6283 * level, use it as the new last */
6284 item->parent->last = item;
6285 } /* end if */
6287 /* clear reference from previous parent */
6288 old_parent->first = NULL;
6289 old_parent->last = NULL;
6291 return;
6294 /**
6295 * @brief Allows to check if both items are equal, considering the
6296 * item type and the content associated to the item type.
6299 * @param item The first item to check. @param item2 The second item
6300 * to check with the first item. @param trimmed This paramenter
6301 * allows to configure how equal checking is performed for content
6302 * element (\ref ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT and
6303 * \ref ITEM_REF).
6305 * @return \ref true if the both items represents the same
6306 * information, otherwise \ref false is returned. If the function
6307 * receives a null value it will return false.
6309 bool axl_item_are_equal (axlItem * item,
6310 axlItem * item2,
6311 bool trimmed)
6313 axlNodeContent * content;
6314 axlNodeContent * content2;
6316 /* trim content */
6317 char * trim;
6318 char * trim2;
6319 bool result;
6321 axl_return_val_if_fail (item, false);
6322 axl_return_val_if_fail (item2, false);
6324 /* basic type check */
6325 if (axl_item_get_type (item) != axl_item_get_type (item2))
6326 return false;
6328 /* according the type */
6329 switch (axl_item_get_type (item)) {
6330 case ITEM_NODE:
6331 /* check that both nodes are equal */
6332 return axl_node_are_equal (item->data, item2->data);
6333 case ITEM_CONTENT:
6334 case ITEM_CDATA:
6335 case ITEM_COMMENT:
6336 case ITEM_REF:
6337 /* get the contenet */
6338 content = item->data;
6339 content2 = item2->data;
6341 if (! trimmed) {
6342 /* check first content length */
6343 if (content->content_size != content2->content_size)
6344 return false;
6346 /* now check content value */
6347 return axl_cmp (content->content, content2->content);
6348 }else {
6349 /* duplicate the content */
6350 trim = axl_strdup (content->content);
6351 trim2 = axl_strdup (content2->content);
6353 /* trim content */
6354 axl_stream_trim (trim);
6355 axl_stream_trim (trim2);
6357 /* do the comparision */
6358 result = axl_cmp (trim, trim2);
6360 /* free data */
6361 axl_free (trim);
6362 axl_free (trim2);
6364 return result;
6367 case ITEM_PI:
6368 /* pi case */
6369 return axl_pi_are_equal (item->data, item2->data);
6370 default:
6371 /* no case identified, not equal */
6372 break;
6373 } /* end switch */
6375 return false;
6378 /**
6379 * @brief Allows to release the memory hold the item reference
6380 * provided, and the value stored inside it.
6382 * @param item The item to dealloc.
6384 * @param dealloc true to also dealloc the value inside.
6386 void axl_item_free (axlItem * item,
6387 bool dealloc)
6389 axl_return_if_fail (item);
6392 /* according the type */
6393 switch (axl_item_get_type (item)) {
6394 case ITEM_NODE:
6395 /* free the node */
6396 axl_node_free (item->data);
6397 break;
6398 case ITEM_CONTENT:
6399 case ITEM_CDATA:
6400 case ITEM_COMMENT:
6401 case ITEM_REF:
6402 /* all of them, managed equally */
6404 /* check and free content */
6405 if ((item->type & ITEM_CONTENT_FROM_FACTORY) == 0) {
6406 axl_free (((axlNodeContent *)item->data)->content);
6408 /* free node */
6409 axl_free ((axlNodeContent *)item->data);
6412 if ((item->type & ITEM_FROM_FACTORY) == 0)
6413 axl_free (item);
6414 break;
6415 case ITEM_PI:
6416 /* an process instruction */
6417 axl_pi_free (item->data);
6419 /* free the item */
6420 if ((item->type & ITEM_FROM_FACTORY) == 0)
6421 axl_free (item);
6422 break;
6423 case ITEM_FROM_FACTORY:
6424 case ITEM_CONTENT_FROM_FACTORY:
6425 /* never reached */
6426 break;
6428 } /* end switch */
6431 return;
6434 axlFactory * axl_item_factory_create ()
6436 return axl_factory_create (sizeof (axlItem));
6439 axlItem * axl_item_factory_get (axlFactory * factory)
6441 return axl_factory_get (factory);
6444 axlFactory * axl_node_factory_create ()
6446 return axl_factory_create (sizeof (axlNode));
6449 axlNode * axl_node_factory_get (axlFactory * factory)
6451 /* get a node */
6452 axlNode * node = axl_factory_get (factory);
6454 /* configure it */
6455 node->conf = NODE_FROM_FACTORY;
6457 return node;
6460 axlFactory * axl_item_content_factory_create ()
6462 /* create a factory for axlNodeContent elements */
6463 return axl_factory_create (sizeof (axlNodeContent));
6466 axlFactory * axl_item_attr_factory_create ()
6468 /* create a factory for axlNodeAttr elements */
6469 return axl_factory_create (sizeof (axlNodeAttr));
6472 /* @} */