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
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
27 * For commercial support on build XML enabled solutions contact us:
30 * Advanced Software Production Line, S.L.
31 * C/ Dr. Michavila NÂș 14
32 * Coslada 28820 Madrid
36 * info@aspl.es - http://fact.aspl.es
40 #define LOG_DOMAIN "axl-node"
43 * \defgroup axl_node_module Axl Node: Xml node interface functions to use and manipulate xml nodes inside documents.
47 * \addtogroup axl_node_module
51 struct _axlAttrCursor
{
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
{
67 * @brief Pointer which holds current content inside the xml
74 * @brief Current content size stored on the given axlNode.
81 * @internal Type representation to hold node attributes while they
84 typedef struct _axlNodeAttr axlNodeAttr
;
88 * @internal Node attribute name.
93 * @internal Node attribute value.
98 * @internal Flags the attribute pair to be considered from a
104 * @internal Next attribute.
110 * @internal Function that allows to copy all attributes found on the
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 */
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 */
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
)
149 /* if the list isn't defined, return NULL */
154 while (attr
!= NULL
) {
155 /* get the next attribute */
158 /* free attribute description */
159 if (! attr
->from_factory
) {
160 axl_free (attr
->attribute
);
161 axl_free (attr
->value
);
170 /* return result created */
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
181 * @param attr2 The second attribute pointing to the rest of the
184 * @return \ref true if both lists are equal, otherwise \ref false is
187 bool __axl_node_attr_list_is_equal (axlNodeAttr
* attr
, axlNodeAttr
* attr2
)
189 axlNodeAttr
* attrAux
;
192 /* for each attribute found in the attribute list, check it on
194 while (attr
!= NULL
) {
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 */
209 attrAux
= attrAux
->next
;
213 /* check if the attribute was found */
222 /* all attributes was found, including its values, so, the
229 * @internal Signal axl library that the node was allocated by
230 * a factory not by the system alloc.
232 NODE_FROM_FACTORY
= 1,
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
245 * Node name that is the value found at the very begining of
246 * the node definition <name.../>
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.
261 * @brief The attributes this node has.
263 axlPointer
* attributes
;
266 * @internal A reference to the frist child.
271 * @internal A reference to the last child.
276 * @internal A hash used to store arbitrary data associated to
279 axlHash
* annotate_data
;
282 * @internal Internal reference to the holder axlItem
283 * containing the axl node reference.
288 * @internal Value that contains flags for configuration.
295 * @internal A reference to the type that is being hold by the
296 * encapsulation reference.
301 * @internal The reference to the pointer that is actually
308 * A pointer to the parent node.
315 * A pointer to the brother node, the node that is found on
321 * @internal Stores a reference to the previous node inside
329 * Internal reference to the whole xml document where the node
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
)
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
,
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 ' */
367 if (content
[iterator2
] == '\'') {
368 memcpy (result
+ iterator
, "'", 6);
374 /* check for " */
375 if (content
[iterator2
] == '"') {
376 memcpy (result
+ iterator
, """, 6);
382 /* check for & */
383 if (content
[iterator2
] == '&') {
384 memcpy (result
+ iterator
, "&", 5);
391 if (content
[iterator2
] == '>') {
392 memcpy (result
+ iterator
, ">", 4);
399 if (content
[iterator2
] == '<') {
400 memcpy (result
+ iterator
, "<", 4);
406 /* copy value received because it is not an escape
408 memcpy (result
+ iterator
, content
+ iterator2
, 1);
410 /* update the iterator */
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
,
437 axl_return_val_if_fail (content
, false);
439 /* iterate over all content defined */
440 while (iterator
< (*content_size
)) {
442 /* check for ' */
443 if (axl_stream_cmp (content
+ iterator
, "'", 6)) {
444 content
[iterator2
] = '\'';
451 /* check for " */
452 if (axl_stream_cmp (content
+ iterator
, """, 6)) {
453 content
[iterator2
] = '"';
460 /* check for & */
461 if (axl_stream_cmp (content
+ iterator
, "&", 5)) {
462 content
[iterator2
] = '&';
470 if (axl_stream_cmp (content
+ iterator
, ">", 4)) {
471 content
[iterator2
] = '>';
479 if (axl_stream_cmp (content
+ iterator
, "<", 4)) {
480 content
[iterator2
] = '<';
487 /* copy move the content */
488 if (iterator2
!= iterator
)
489 content
[iterator2
] = content
[iterator
];
491 /* update the iterator */
496 /* return results, setting the new content size */
497 *content_size
= iterator2
;
498 content
[iterator2
] = 0;
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
)
523 node
= axl_new (axlNode
, 1);
524 node
->name
= axl_strdup (name
);
530 * @brief This function allows to create a xml node from the provided
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:
539 * axlError * error = NULL;
540 * axlNode * node = NULL;
543 * root = axl_node_parse_strings (error,
545 * " <widget class=\"GtkLabel\" id=\"label4\">",
546 * " <property name=\"visible\">True</property>",
547 * " <property name=\"label\" translatable=\"yes\"><b>1. Seleccione el sistema:</b></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>",
563 * " <property name=\"padding\">0</property>",
564 * " <property name=\"expand\">False</property>",
565 * " <property name=\"fill\">False</property>",
569 * if (root == NULL) {
570 * printf ("Error: unable to parse content, error: %s\n", axl_error_get (error));
571 * axl_error_free (error);
575 * // once finished, free the node
576 * axl_node_free (root);
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
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
588 axlNode
* axl_node_parse_strings (axlError
** error
, ...)
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
) {
605 stream
= axl_stream_concat (stream
, string
);
606 if (stream_aux
!= NULL
) {
607 axl_free (stream_aux
);
612 /* close the stdargs */
615 /* check that we have received, at least, an string
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
);
630 /* free the 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 */
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:
654 * axlNode * node = axl_node_parse (NULL, "<content attr='value' attr2='value'>This is content</content>");
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
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
672 axlNode
* axl_node_parse (axlError
** error
, const char * content
, ...)
679 /* open the stdargs */
680 va_start (args
, content
);
682 /* create the content */
683 _content
= axl_strdup_printfv (content
, args
);
685 /* close the stdargs */
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
);
693 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "failed to parse document:\n %s", _content
);
701 /* free the 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 */
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
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:
736 * // propery node creation
737 * axlNode * node = axl_node_create ("test");
739 * // NOT PROPER node creation
740 * axlNode * node = axl_node_create_ref ("test");
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
)
755 node
= axl_new (axlNode
, 1);
758 /* return a reference to a new axlNode */
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
);
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 */
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
)
825 /* update configuration */
826 node
->conf
|= NODE_NAME_FROM_FACTORY
;
831 axlPointer
__axl_node_copy_key (axlPointer key
, axlDestroyFunc key_destroy
,
832 axlPointer data
, axlDestroyFunc data_destroy
)
835 return axl_strdup (key
);
838 axlPointer
__axl_node_copy_value (axlPointer key
, axlDestroyFunc key_destroy
,
839 axlPointer data
, axlDestroyFunc data_destroy
)
842 return axl_strdup (data
);
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
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
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
,
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)",
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
889 result
->attributes
= (axlPointer
) axl_hash_copy ((axlHash
*) node
->attributes
,
890 /* key copy function */
892 /* value copy function */
893 __axl_node_copy_value
);
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 */
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",
912 axl_item_get_type (copy
));
914 /* set the content */
915 axl_item_set_child_ref (result
, copy
);
917 /* get the next element */
924 /* return the node created */
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
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
);
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
)
965 axl_return_if_fail (node
);
966 axl_return_if_fail (doc
);
968 /* get the item reference */
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
;
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
);
983 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "setting doc to the item node");
985 /* call to set item at the document */
995 * Support function to install attribute information provided into the
996 * \ref axlNode provided.
998 void __axl_node_set_attribute (axlFactory
* factory
,
1007 /* init attribute list */
1008 /* do not init attribute list twice */
1009 if (node
->attributes
== NULL
) {
1010 /* configure default axl attribute list */
1013 /* create the node */
1015 attr
= axl_factory_get (factory
);
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
;
1028 /* store the attribute using the general case */
1029 if (node
->attr_num
< 10) {
1031 /* create the node */
1033 attr
= axl_factory_get (factory
);
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 */
1065 if (! attr
->from_factory
)
1068 /* get the next item to store */
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
);
1081 /* update attribute count */
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:
1095 * <complex attr1='value'>
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
1109 * @param node The \ref axlNode where the attribute will be installed
1111 * @param attribute The attribute name to configure. This value can't
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
,
1121 int additional_size
= 0;
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
,
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
,
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);
1165 * @brief Allows to install a new attribute pair, based on the
1166 * attribute name and the attribute value, without allocating memory
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
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);
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
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
,
1210 /* insert the attribute */
1211 __axl_node_set_attribute (factory
, node
, attribute
, value
, true);
1217 * @brief Allows to check if a particular attribute is installed on
1220 * @param node The node where the attribute will be checked to be
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
)
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
)
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
))
1247 /* get the next attribute */
1251 /* attribute not found */
1255 /* hashed configuration */
1256 return axl_hash_exists ((axlHash
*) node
->attributes
, (axlPointer
) attribute
);
1260 * @brief Allows to remove the attribute provided, from the node
1263 * @param node The node that will be updated by removing the attribute
1266 * @param attribute The attribute to locate and remove.
1268 void axl_node_remove_attribute (axlNode
* node
,
1269 const char * attribute
)
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
)
1281 if (node
->attr_num
<= 10) {
1282 /* linked configuration */
1283 attr
= (axlNodeAttr
*) node
->attributes
;
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
;
1292 previous
->next
= attr
->next
;
1294 /* do not decrease attribute number
1295 * since it is used to know the kind
1298 /* now dealloc the attribute */
1299 if (! attr
->from_factory
) {
1300 axl_free (attr
->attribute
);
1301 axl_free (attr
->value
);
1308 /* get the next attribute */
1313 /* attribute not found */
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
1328 * @brief Allows to get the number of attributes installed on the
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
)
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
) {
1350 /* get the next attribute */
1354 /* attribute not found */
1358 /* hashed configuration */
1359 return axl_hash_items ((axlHash
*) node
->attributes
);
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
);
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
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
1396 const char * axl_node_get_attribute_value (axlNode
* node
, const char * attribute
)
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
)
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
))
1416 /* get the next attribute */
1420 /* attribute not found */
1424 /* return value stored for the provided key */
1425 return axl_hash_get ((axlHash
*) node
->attributes
, (axlPointer
) attribute
);
1429 * @brief Gets an allocated copy for the value associated to the given
1432 * See \ref axl_node_get_attribute_value for more information. This
1433 * function works the same way but returning an already allocated
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
);
1453 return axl_strdup (_value
);
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>&</b>, <b><</b>, etc, this
1467 * function will translate them into the corresponding values.
1469 * @param node The \ref axlNode instance where the attribute content
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
)
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
);
1492 size
= strlen (_value
);
1493 return __axl_node_content_translate_defaults (_value
, &size
);
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
1512 const char * axl_node_get_attribute_value_trimmed (axlNode
* node
,
1513 const char * attribute
)
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
);
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
1545 bool axl_node_has_attribute_value (axlNode
* node
,
1546 const char * attribute
,
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
);
1562 * \defgroup axl_node_annotate Axl Node Annotate: An interface that allows associate arbitrary data to a particular node, indexed as a hash.
1566 * \addtogroup axl_node_annotate
1571 * @internal function which checks and initializes the hash used for
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
);
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
1609 * @param data The data to be stored associated to the key provided.
1611 void axl_node_annotate_data (axlNode
* node
,
1615 axl_return_if_fail (node
);
1617 /* check and init node annotation */
1618 __init_node_annotation (node
);
1621 axl_hash_insert (node
->annotate_data
, (axlPointer
) key
, data
);
1623 /* nothing more to do */
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
1641 * @param key_destroy The destroy function to be called to deallocate
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
,
1651 axlDestroyFunc key_destroy
,
1653 axlDestroyFunc data_destroy
)
1655 axl_return_if_fail (node
);
1657 /* check and init node annotation */
1658 __init_node_annotation (node
);
1661 axl_hash_insert_full (node
->annotate_data
, (axlPointer
) key
, key_destroy
, data
, data_destroy
);
1663 /* nothing more to do */
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
,
1686 bool lookup_in_parent
)
1688 axlPointer result
= NULL
;
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 */
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 */
1720 /* get the next parent */
1721 parent
= axl_item_get_parent (parent
->holder
);
1725 /* no node was found */
1730 * @internal definition to clasify node annotation.
1734 * @internal definition to clasify int elements.
1738 * @internal definition to clasify string elements.
1740 ANNOTATE_STRING
= 1,
1742 * @internal definition to clasify int elements.
1747 typedef struct _AnnotateNodeData
{
1749 * @internal type annotated.
1754 * @internal Value annotated: int, string or double.
1758 char * string_value
;
1759 double double_value
;
1763 void __axl_annotate_data_free (AnnotateNodeData
* data
)
1768 /* free the string */
1769 if (data
->type
== ANNOTATE_STRING
)
1770 axl_free (data
->value
.string_value
);
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
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
,
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
);
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
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
,
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
);
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
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
,
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
);
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
,
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. */
1998 if (data
->type
!= ANNOTATE_INT
) {
2000 __axl_log (LOG_DOMAIN
, AXL_LEVEL_CRITICAL
, "accesing to a annotation data that isn't flaged as integer");
2004 /* return the integer value inside */
2005 return data
->value
.int_value
;
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
,
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. */
2046 if (data
->type
!= ANNOTATE_STRING
) {
2048 __axl_log (LOG_DOMAIN
, AXL_LEVEL_CRITICAL
, "accesing to a annotation data that isn't flaged as string");
2052 /* return the string value inside */
2053 return data
->value
.string_value
;
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
,
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. */
2094 if (data
->type
!= ANNOTATE_DOUBLE
) {
2096 __axl_log (LOG_DOMAIN
, AXL_LEVEL_CRITICAL
, "accesing to a annotation data that isn't flaged as double");
2100 /* return the double value inside */
2101 return data
->value
.double_value
;
2109 * \addtogroup axl_node_module
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:
2124 * // clear all content inside
2125 * axl_node_set_is_empty (node, true);
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
)
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 */
2149 /* get the first child and eliminate all content */
2150 child
= node
->first
;
2151 while (child
!= NULL
) {
2153 /* count each item found */
2156 /* get a reference to the 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 */
2174 /* update to the next */
2179 /* now check if items removed are equal to items counted */
2180 if (removed
== count
) {
2181 /* then clear node references */
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>.
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:
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
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
2219 const char * axl_node_get_name (axlNode
* node
)
2221 axl_return_val_if_fail (node
, NULL
);
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
2234 * @param node The xml node that is requested to return its parent
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",
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
;
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
)
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)");
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,
2303 while (item
!= NULL
) {
2305 /* get the item found */
2306 if (axl_item_get_type (item
) == ITEM_NODE
)
2314 /* or null if no reference is defined */
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
,
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
))
2344 /* update to the next */
2345 next
= axl_node_get_next (next
);
2348 /* no node was found */
2353 * @brief Allows to get the previous reference from the reference node
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
)
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 */
2385 /* or null if no reference is defined */
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
,
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
))
2416 /* update to the next */
2417 previous
= axl_node_get_previous (previous
);
2420 /* no node was found */
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
2453 * If you want to get a reference to the <b>child</b> node you can do
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.
2466 * However, in the case the previous content mix node with content as
2471 * Some content previous to the first child.
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 <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
)
2493 axl_return_val_if_fail (node
, NULL
);
2495 /* get first item child and lookup for the first child that is
2498 while (item
!= NULL
) {
2499 /* check the item type */
2500 if (axl_item_get_type (item
) == ITEM_NODE
)
2507 /* return NULL: no child axlNode was found */
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
)
2525 axl_return_val_if_fail (node
, NULL
);
2527 /* get first item child and lookup for the first child that is
2530 while (item
!= NULL
) {
2531 /* check the item type */
2532 if (axl_item_get_type (item
) == ITEM_NODE
)
2536 item
= item
->previous
;
2539 /* return NULL: no child axlNode was found */
2544 * @brief Allows to get current emptyness configuration for the given
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:
2553 * Xml content, data node content
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 <data> node with
2563 * childs that have content, but the parent node, <data> do not
2564 * have content, therefore is empty.
2568 * <row>Some data</row>
2569 * <row>More content</row>
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
2580 bool axl_node_is_empty (axlNode
* node
)
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 */
2599 /* go to the next */
2600 child
= child
->next
;
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
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 * "&" or """ 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
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
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
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
;
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
;
2684 /* get the next item */
2685 child
= child
->next
;
2689 /* set content size to zero */
2690 if (content_size
!= NULL
)
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:
2702 * Content inside the xml node.
2706 * Because the function will perform a local copy for the provided
2707 * data, it will also check for especial entities to be placed
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.
2716 * <tr><td><b>Character</b></td><td>Entity name</td></tr>
2717 * <tr><td>'</td><td>&apos;</td></tr>
2718 * <tr><td><</td><td>&lt;</td></tr>
2719 * <tr><td>></td><td>&gt;</td></tr>
2720 * <tr><td>&</td><td>&amp;</td></tr>
2721 * <tr><td>"</td><td>&quot;</td></tr>
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
2741 void axl_node_set_content (axlNode
* node
,
2742 const char * content
,
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
)) {
2762 itemContent
->content
= __axl_node_content_copy_and_escape (content
,
2765 /* set node content size */
2766 itemContent
->content_size
= content_size
+ additional_size
;
2768 /* set current content */
2769 itemContent
->content_size
= content_size
;
2770 itemContent
->content
= axl_new (char, content_size
+ 1);
2773 memcpy (itemContent
->content
, content
, itemContent
->content_size
);
2776 /* add it to the current node */
2777 axl_item_set_child (node
, ITEM_CONTENT
, itemContent
);
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
,
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
);
2811 itemContent
= axl_new (axlNodeContent
, 1);
2813 /* configure content size */
2814 itemContent
->content_size
= content_size
;
2816 /* set current content */
2817 itemContent
->content
= content
;
2822 axl_item_set_child (node
, ITEM_CDATA
| ITEM_CONTENT_FROM_FACTORY
, itemContent
);
2825 axl_item_set_child (node
, ITEM_CONTENT
| ITEM_CONTENT_FROM_FACTORY
, itemContent
);
2830 /* store as cdata */
2831 axl_item_set_child (node
, ITEM_CDATA
, itemContent
);
2833 /* store as parsed xml content */
2834 axl_item_set_child (node
, ITEM_CONTENT
, itemContent
);
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
);
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
2865 * @param content_size The content size.
2867 void axl_node_set_content_ref (axlNode
* node
,
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);
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
2885 void axl_node_set_content_from_factory (axlFactory
* factory
,
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);
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
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
,
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);
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
2947 void axl_node_set_cdata_content_from_factory (axlFactory
* factory
,
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);
2961 * @brief Allows to configure a new comment (<!-- 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
2973 * @param comment_size The comment size or -1 to make the function to
2976 void axl_node_set_comment (axlNode
* node
,
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
);
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
3019 * @return A newly allocated string representing the node content.
3021 char * axl_node_get_content_copy (axlNode
* node
, int * content_size
)
3025 const char * content
;
3027 /* get the content and check if it is defined */
3029 content
= axl_node_get_content (node
, content_size
);
3031 content
= axl_node_get_content (node
, &_content_size
);
3034 if (content
== NULL
|| strlen (content
) == 0) {
3035 return axl_strdup ("");
3038 /* allocate enough memory for the result */
3040 result
= axl_new (char, (*content_size
) + 1);
3041 memcpy (result
, content
, *content_size
);
3043 result
= axl_new (char, _content_size
+ 1);
3044 memcpy (result
, content
, _content_size
);
3047 /* return a newly allocated reference to the content */
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
3060 * @param node The node where the content will be trimmed and
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
3071 char * axl_node_get_content_trim (axlNode
* node
,
3076 axlNodeContent
* content
;
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
;
3106 /* get the next item */
3107 child
= child
->next
;
3111 /* set content size to zero */
3112 if (content_size
!= NULL
)
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
3132 char * axl_node_get_content_trans (axlNode
* node
, int * content_size
)
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
3141 result
= axl_node_get_content_copy (node
, content_size
);
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 */
3152 /* translate all references that performs the entities to the
3153 * replacement text. */
3155 return __axl_node_content_translate_defaults (result
, content_size
);
3156 return __axl_node_content_translate_defaults (result
, &_content_size
);
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
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
3178 * So, to build the following structure:
3186 * You must perform the following operations:
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);
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
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
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
);
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
,
3245 /* call to the item implementation */
3246 axl_item_set_after (reference
->holder
, ITEM_NODE
, child
);
3253 * @brief Allows to replace a selected node, with the new reference
3254 * inside its context (updating all references: next, previous and
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
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
,
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
);
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
;
3312 /* dealloc node if configured so */
3315 axl_node_free (node
);
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
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
3338 void axl_node_remove (axlNode
* node
,
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
);
3355 if (axl_item_get_parent (item
) != NULL
) {
3357 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "doing reference relocation (remove operation) for=<%s>",
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
;
3384 /* disconnect the item */
3385 item
->previous
= NULL
;
3391 /* dealloc node if configured so */
3394 axl_node_free (node
);
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,
3410 * If the node isn't attached to any document, the function does
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);
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
)
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
3453 * @param node The \ref axlNode reference.
3455 * @return An \ref true if the \ref axlNode have childs or \ref
3458 bool axl_node_have_childs (axlNode
* node
)
3462 axl_return_val_if_fail (node
, false);
3465 while (item
!= NULL
) {
3466 /* check item type */
3467 if (axl_item_get_type (item
) == ITEM_NODE
)
3470 /* go to the next */
3475 /* return false because no item was found with ITEM_NODE
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
)
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
)
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 */
3513 /* compare for find the child */
3514 if (NODE_CMP_NAME (node
, name
))
3520 item
= axl_item_get_next (item
);
3523 /* no child was found */
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
)
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
))
3565 node
= axl_node_get_next (node
);
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 */
3579 node
= axl_node_get_next (node
);
3582 /* child note found */
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
)
3602 /* perform some environment checks */
3603 axl_return_val_if_fail (parent
, NULL
);
3605 /* check for first reference */
3606 if (parent
->first
== NULL
) {
3610 /* get the first item */
3611 item
= parent
->first
;
3613 /* get the first node found */
3615 while (item
!= NULL
) {
3616 /* check the item type */
3617 if (axl_item_get_type (item
) == ITEM_NODE
) {
3618 if (iterator
== position
) {
3629 /* no first child found */
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
)
3645 /* perform some environment checks */
3646 axl_return_val_if_fail (parent
, -1);
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
)
3664 /* return the number of chils */
3670 * @brief Allows to get childs nodes for the given xml node (\ref
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:
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);
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
)
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
);
3719 /* update the reference to the next child */
3720 child
= child
->next
;
3723 /* return current childs */
3727 bool __axl_node_are_equal_attr (axlPointer key
,
3729 axlPointer user_data
,
3730 axlPointer user_data2
)
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 */
3746 /* make the process to continue */
3751 * @brief Allows to check if the provided references represents two
3754 * The function will check node name, node content and node attributes
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
)
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
);
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
);
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
);
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
));
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
);
3807 /* now both hashes */
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
);
3813 /* check both hashes are equal */
3814 axl_hash_foreach2 ((axlHash
*) node
->attributes
, __axl_node_are_equal_attr
, (axlHash
*) node2
->attributes
, &result
);
3818 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "node attributes differs <%s> != <%s>",
3819 node
->name
, node2
->name
);
3820 /* attribute missmatch */
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
));
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
));
3838 /* both nodes seems to be equal */
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
3852 * @param target The PI target name to add.
3854 * @param content Optional PI content.
3856 void axl_node_add_pi_target (axlNode
* node
,
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
);
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
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
,
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
3904 while (item
!= NULL
) {
3906 /* check the type */
3907 if (axl_item_get_type (item
) == ITEM_PI
) {
3908 /* get a reference */
3911 /* only check the first ocurrency */
3912 if (axl_cmp (axl_pi_get_name (pi
), pi_target
))
3916 /* get the next item */
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
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
,
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
3947 while (item
!= NULL
) {
3949 /* check the type */
3950 if (axl_item_get_type (item
) == ITEM_PI
) {
3951 /* get a reference */
3954 /* only check the first ocurrency */
3955 if (axl_cmp (axl_pi_get_name (pi
), pi_target
))
3956 return axl_pi_get_content (pi
);
3959 /* get the next item */
3968 * @brief Allows to transfer (move from) all childs (including
3969 * comments, content, PI, nodes, etc) from the old parent to the new
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
3981 void axl_node_transfer_childs (axlNode
* old_parent
,
3982 axlNode
* new_parent
)
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
);
4004 /* clear reference from previous parent */
4005 old_parent
->first
= NULL
;
4006 old_parent
->last
= NULL
;
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
)
4020 /* check refererences received */
4021 axl_return_val_if_fail (node
, false);
4022 axl_return_val_if_fail (content
, false);
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
);
4032 if (index
!= _size
) {
4033 __axl_log (LOG_DOMAIN
, AXL_LEVEL_CRITICAL
, "failed to dump xml node, size dump operation mismatch: %d != %d",
4035 /* free allocated result */
4038 /* nullify content */
4051 /* return content */
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
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
,
4073 /* use common implementation for all functions */
4074 return __axl_node_dump_common (node
, content
, size
, false, 0, 0);
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
,
4099 /* use common implementation for all functions */
4100 return __axl_node_dump_common (node
, content
, size
, true, 0, tabular
);
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
4110 * @param file_path File path where place the result.
4112 * @return \ref true if the dump operation was done, otherwise \ref false is
4115 bool axl_node_dump_to_file (axlNode
* node
,
4123 /* use common implementation for all functions */
4124 if (! __axl_node_dump_common (node
, &content
, &size
, true, 0, 0))
4127 /* open the file and check */
4128 #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
4129 if (fopen_s (&fd
, file_path
, "w") != 0) {
4131 if ((fd
= fopen (file_path
, "w")) == NULL
) {
4133 /* failed to open the file to dump the content */
4139 /* dump the content */
4140 written
= fwrite (content
, 1, size
, fd
);
4142 /* free the content */
4148 /* return if we have failed to dump all the content to the
4150 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "returning that the dump was: %s (written:%d == size:%d)",
4151 (written
== size
) ? "OK" : "FAILED",
4154 return (written
== size
);
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
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
4172 bool axl_node_dump_pretty_to_file (axlNode
* node
,
4181 /* use common implementation for all functions */
4182 if (! __axl_node_dump_common (node
, &content
, &size
, true, 0, tabular
))
4185 /* open the file and check */
4186 #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
4187 if (fopen_s (&fd
, file_path
, "w") != 0) {
4189 if ((fd
= fopen (file_path
, "w")) == NULL
) {
4191 /* failed to open the file to dump the content */
4197 /* dump the content */
4198 written
= fwrite (content
, 1, size
, fd
);
4200 /* free the content */
4206 /* return if we have failed to dump all the content to the
4208 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "returning that the dump was: %s (written:%d == size:%d)",
4209 (written
== size
) ? "OK" : "FAILED",
4212 return (written
== size
);
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
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:
4233 * void show_all_pi (axlNode * node)
4239 * // get all PI target that the node has
4240 * PIs = axl_node_get_pi_target_list (node);
4243 * while (iterator < axl_list_length (PIs)) {
4244 * // get next pi stored
4245 * pi = axl_list_get_nth (PIs, iterator);
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
4256 * // once finished, free the list
4257 * axl_list_free (PIs);
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
4269 axlList
* axl_node_get_pi_target_list (axlNode
* node
)
4271 axlList
* result
= NULL
;
4274 axl_return_val_if_fail (node
, false);
4276 /* assume the pi target doesn't exist if it is not
4279 while (item
!= NULL
) {
4281 /* check the type */
4282 if (axl_item_get_type (item
) == ITEM_PI
) {
4283 /* create the result list */
4285 result
= axl_list_new (axl_list_always_return_1
, (axlDestroyFunc
) axl_pi_free
);
4288 axl_list_add (result
, item
->data
);
4292 /* get the next item */
4300 bool __axl_node_get_flat_size_attributes_foreach (axlPointer attr
,
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 */
4315 * @brief Returns the space required to write the attribute part.
4317 int __axl_node_get_flat_size_attributes (axlNode
* node
)
4321 axlNodeAttr
* attr
= NULL
;
4323 /* if attribute list is not defined just return 0 */
4324 if (node
->attributes
== NULL
)
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
);
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 */
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
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
)
4372 axlNodeContent
* content
;
4376 axl_return_val_if_fail (node
, -1);
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
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 */
4391 /* two tabulations plus two carry return \r\n
4392 * on windows and \n on unix */
4394 result
+= (level
* tabular
* 2) + 2;
4396 result
+= (level
* tabular
) + 1;
4397 #ifdef __AXL_OS_WIN32__
4406 /* "<" + strlen (node-name) + " />" */
4407 result
= strlen (node
->name
) + 4 + __axl_node_get_flat_size_attributes (node
);
4409 /* check 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__
4424 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "node=<%s> count=%d", node
->name
, result
);
4426 /* get first child */
4428 while (item
!= NULL
) {
4429 /* according to the type, check a size */
4430 switch (axl_item_get_type (item
)) {
4432 /* count how many bytes the node holds */
4433 result
+= axl_node_get_flat_size (item
->data
, pretty_print
, level
+ 1, tabular
);
4437 content
= (axlNodeContent
*) item
->data
;
4438 result
+= content
->content_size
;
4441 /* content + '<![CDATA[' + ']]>' */
4442 content
= (axlNodeContent
*) item
->data
;
4443 result
+= content
->content_size
+ 12;
4446 /* get current size */
4447 result
+= axl_pi_get_size (item
->data
);
4450 /* content + '<!-- ' + ' -->' */
4451 content
= (axlNodeContent
*) item
->data
;
4452 result
+= content
->content_size
+ 9;
4454 /* tabular indent + \n */
4455 result
+= ((level
+ 1) * tabular
) + 1;
4456 #ifdef __AXL_OS_WIN32__
4464 /* item ref + '&' + ';' */
4465 content
= (axlNodeContent
*) item
->data
;
4466 result
+= content
->content_size
+ 2;
4468 case ITEM_FROM_FACTORY
:
4469 case ITEM_CONTENT_FROM_FACTORY
:
4478 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "child processing finished for: parent=<%s>, count=%d", node
->name
, result
);
4480 /* return the result */
4484 bool __axl_node_dump_attributes_at_foreach (axlPointer key
,
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
);
4495 memcpy (content
+ desp
, " ", 1);
4498 length
= strlen ((char*) key
);
4499 memcpy (content
+ desp
, (char *) key
, length
);
4502 /* check if the content contains a ' so, enclose the attribute
4504 if (strstr (value
, "'") == NULL
) {
4505 memcpy (content
+ desp
, "='", 2);
4509 memcpy (content
+ desp
, "=\"", 2);
4513 length
= strlen ((char*) value
);
4514 memcpy (content
+ desp
, (char*) value
, length
);
4517 /* dump attribute termination */
4519 memcpy (content
+ desp
, "\"", 1);
4521 memcpy (content
+ desp
, "'", 1);
4528 /* make the process to continue */
4532 void __axl_node_dump_at_the_end (axlNodeAttr
* attr
, char * content
, int * desp
)
4534 /* return if no attribute must be dumped */
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
);
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
)
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
);
4570 /* foreach attribute dump */
4571 axl_hash_foreach2 ((axlHash
*) node
->attributes
, __axl_node_dump_attributes_at_foreach
, content
, &desp
);
4574 /* return the length */
4579 * @internal Writes the indentation according to the tabular size and
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
)
4595 while (iterator
< (tabular
* level
)) {
4596 /* write tabular info */
4597 memcpy (content
+ iterator
, " ", 1);
4599 /* update iterator */
4607 int __axl_node_dump_items (axlItem
* item
, char * content
, int level
, bool pretty_print
, int desp
, int tabular
)
4610 axlNodeContent
* nodeContent
;
4613 /* get first child */
4614 while (item
!= NULL
) {
4615 /* according to the type, check a size */
4616 switch (axl_item_get_type (item
)) {
4618 /* write axl node content */
4619 desp
= axl_node_dump_at (item
->data
, content
, desp
, pretty_print
, level
+ 1, tabular
);
4622 /* write content information */
4623 nodeContent
= (axlNodeContent
*)item
->data
;
4624 memcpy (content
+ desp
, nodeContent
->content
, nodeContent
->content_size
);
4625 desp
+= nodeContent
->content_size
;
4628 /* write content information */
4629 nodeContent
= (axlNodeContent
*)item
->data
;
4631 /* write cdata content */
4632 memcpy (content
+ desp
, "<![CDATA[", 9);
4636 memcpy (content
+ desp
, nodeContent
->content
, nodeContent
->content_size
);
4637 desp
+= nodeContent
->content_size
;
4639 /* write cdata end */
4640 memcpy (content
+ desp
, "]]>", 3);
4644 /* write pi start */
4645 memcpy (content
+ desp
, "<?", 2);
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);
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);
4668 /* check for pretty print to write indent */
4670 desp
+= __axl_node_dump_at_write_indent (content
+ desp
, tabular
, level
+ 1);
4673 /* content + '<!-- ' + ' -->' */
4674 memcpy (content
+ desp
, "<!-- ", 5);
4677 /* get a reference to the content */
4678 nodeContent
= (axlNodeContent
*)item
->data
;
4681 memcpy (content
+ desp
, nodeContent
->content
, nodeContent
->content_size
);
4682 desp
+= nodeContent
->content_size
;
4684 memcpy (content
+ desp
, " -->", 4);
4688 #ifdef __AXL_OS_WIN32__
4689 memcpy (content
+ desp
, "\r\n", 2);
4692 memcpy (content
+ desp
, "\n", 1);
4699 /* content + '&' + ';' */
4700 memcpy (content
+ desp
, "&", 1);
4703 /* get a reference to the content */
4704 nodeContent
= (axlNodeContent
*)item
->data
;
4707 memcpy (content
+ desp
, nodeContent
->content
, nodeContent
->content_size
);
4708 desp
+= nodeContent
->content_size
;
4710 memcpy (content
+ desp
, ";", 1);
4713 case ITEM_FROM_FACTORY
:
4714 case ITEM_CONTENT_FROM_FACTORY
:
4724 /* return desp calculated */
4727 } /* end __axl_node_dump_items */
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
4742 * @return The new desp value to be used on the next dump.
4744 int axl_node_dump_at (axlNode
* node
,
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 */
4760 desp
+= __axl_node_dump_at_write_indent (content
+ desp
, tabular
, level
);
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);
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);
4785 /* write traling node information */
4787 #ifdef __AXL_OS_WIN32__
4788 memcpy (content
+ desp
, "\r\n", 2);
4791 memcpy (content
+ desp
, "\n", 1);
4800 /* the node is empty because it doesn't have content but it
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);
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);
4819 /* if the node have childs */
4820 if (axl_node_have_childs (node
)) {
4822 /* write traling node information */
4824 #ifdef __AXL_OS_WIN32__
4825 memcpy (content
+ desp
, "\r\n", 2);
4828 memcpy (content
+ desp
, "\n", 1);
4835 desp
= __axl_node_dump_items (item
, content
, level
, pretty_print
, desp
, tabular
);
4837 /* check for pretty print and tabular */
4839 desp
+= __axl_node_dump_at_write_indent (content
+ desp
, tabular
, level
);
4843 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "the node is not empty and have no childs");
4847 desp
= __axl_node_dump_items (item
, content
, level
, pretty_print
, desp
, tabular
);
4850 /* dump close tag */
4851 memcpy (content
+ desp
, "</", 2);
4854 memcpy (content
+ desp
, node
->name
, strlen (node
->name
));
4855 desp
+= strlen (node
->name
);
4857 memcpy (content
+ desp
, ">", 1);
4860 /* write traling node information */
4862 #ifdef __AXL_OS_WIN32__
4863 memcpy (content
+ desp
, "\r\n", 2);
4866 memcpy (content
+ desp
, "\n", 1);
4871 /* return the result */
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
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
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
,
4905 bool result
= false;
4906 axl_return_val_if_fail (content
, false);
4908 /* reset additional size value */
4909 if (added_size
!= NULL
)
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 ' */
4921 if (content
[iterator
] == '\'') {
4922 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "found invalid sequence='\\'");
4924 if (added_size
!= NULL
)
4928 /* check for " */
4929 if (content
[iterator
] == '"') {
4930 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "found invalid sequence='\"'");
4932 if (added_size
!= NULL
)
4936 /* check for & */
4937 if (content
[iterator
] == '&') {
4938 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "found invalid sequence='&'");
4940 if (added_size
!= NULL
)
4944 /* check for > */
4945 if (content
[iterator
] == '>') {
4946 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "found invalid sequence='>'");
4948 if (added_size
!= NULL
)
4952 /* check for < */
4953 if (content
[iterator
] == '<') {
4954 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "found invalid sequence='<'");
4956 if (added_size
!= NULL
)
4960 /* update the 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 */
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:
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);
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
,
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
)
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
);
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 */
5036 /* foreach item stored */
5037 while (item
!= NULL
) {
5039 /* get the next item */
5040 itemAux
= item
->next
;
5043 axl_item_free (item
, true);
5045 /* update reference */
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 */
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
)
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
))
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 */
5100 * @brief Allows to remove the provided node without removing childs
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
)
5110 axl_return_if_fail (node
);
5112 /* get a reference to the hash */
5113 hash
= node
->annotate_data
;
5116 __axl_node_free_internal (node
, false);
5118 /* free the node itself */
5119 if (!(node
->conf
& NODE_FROM_FACTORY
))
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
);
5136 * \defgroup axl_node_attribute_cursor Axl Node Attribute iteration: An interface provided to iterate attribute nodes without knowing them.
5140 * \addtogroup axl_node_attribute_cursor
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:
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);
5182 * axl_node_attr_cursor_next (cursor);
5186 * // free the cursor
5187 * axl_node_attr_cursor_free (cursor);
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
;
5218 /* create an axl hash cursor */
5219 cursor
->data
= axl_hash_cursor_new ((axlHash
*) node
->attributes
);
5222 /* return created cursor */
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.");
5242 if (cursor
->count
<= 10) {
5243 /* just point to the first attribute (managed as AxlAttribute) */
5244 cursor
->data
= cursor
->node
->attributes
;
5246 /* make hash cursor to point to the first */
5247 axl_hash_cursor_first (cursor
->data
);
5254 * @brief Configures the provided attribute cursor to point to the
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.");
5269 if (cursor
->count
<= 10) {
5270 /* check null values */
5271 if (cursor
->data
== NULL
)
5274 /* just point to the first attribute (managed as AxlAttribute) */
5275 cursor
->data
= ((axlNodeAttr
*) cursor
->data
)->next
;
5280 /* make hash cursor to point to the first */
5281 axl_hash_cursor_next (cursor
->data
);
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.");
5304 if (cursor
->count
<= 10) {
5305 /* just point to the first attribute (managed as AxlAttribute) */
5306 return (((axlNodeAttr
*) cursor
->data
)->next
) != NULL
;
5309 /* make hash cursor to point to the first */
5310 return axl_hash_cursor_has_next (cursor
->data
);
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.");
5331 if (cursor
->count
<= 10) {
5332 /* just point to the first attribute (managed as AxlAttribute) */
5333 return cursor
->data
!= NULL
;
5336 /* make hash cursor to point to the first */
5337 return axl_hash_cursor_has_item (cursor
->data
);
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.");
5358 if (cursor
->count
<= 10) {
5359 /* just point to the first attribute (managed as AxlAttribute) */
5360 return ((axlNodeAttr
*) cursor
->data
)->attribute
;
5363 /* make hash cursor to point to the first */
5364 return axl_hash_cursor_get_key (cursor
->data
);
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.");
5385 if (cursor
->count
<= 10) {
5386 /* just point to the first attribute (managed as AxlAttribute) */
5387 return ((axlNodeAttr
*) cursor
->data
)->value
;
5390 /* make hash cursor to point to the first */
5391 return axl_hash_cursor_get_value (cursor
->data
);
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 */
5415 * @internal Function that helps axl_node_attr_foreach to iterate all
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
);
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
5441 void axl_node_attr_foreach (axlNode
* node
,
5442 axlNodeAttrForeachFunc func
,
5447 axl_return_if_fail (node
);
5448 axl_return_if_fail (func
);
5450 /* if no attributes no foreach operation */
5451 if (node
->attributes
== NULL
)
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
))
5467 /* handled as a hash */
5468 axl_hash_foreach3 ((axlHash
*) node
->attributes
, __axl_node_attr_foreach_aux
, func
, data
, data2
);
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.
5483 * \addtogroup axl_item_module
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
,
5509 axlItem
* item
= NULL
;
5511 axlNodeContent
* content
;
5513 /* allocate an item type */
5514 item
= axl_new (axlItem
, 1);
5517 switch (axl_item_get_type (item
)) {
5520 node
= axl_node_copy (item
->data
, true, true);
5521 node
->holder
= item
;
5528 content
= axl_new (axlNodeContent
, 1);
5529 content
->content
= axl_strdup ((const char *) data
);
5530 content
->content_size
= strlen ((const char *) data
);
5533 item
->data
= content
;
5537 item
->data
= axl_pi_copy (data
);
5540 /* not implemented yet */
5542 case ITEM_FROM_FACTORY
:
5543 case ITEM_CONTENT_FROM_FACTORY
:
5548 /* return item created */
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
5564 * @return A newly allocated \ref axlItem with no parent and holding
5565 * the data provided.
5567 axlItem
* axl_item_new_ref (AxlItemType type
,
5570 axlItem
* item
= NULL
;
5572 axlNodeContent
* content
;
5574 /* allocate an item type */
5575 item
= axl_new (axlItem
, 1);
5578 switch (axl_item_get_type (item
)) {
5582 node
->holder
= item
;
5589 content
= axl_new (axlNodeContent
, 1);
5590 content
->content
= data
;
5591 content
->content_size
= strlen ((const char *) data
);
5594 item
->data
= content
;
5601 /* not implemented yet */
5603 case ITEM_FROM_FACTORY
:
5604 case ITEM_CONTENT_FROM_FACTORY
:
5609 /* return item created */
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 */
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 */
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
5654 * @return A reference to the \ref axlNode.
5656 axlNode
* axl_item_get_parent (axlItem
* item
)
5658 /* return that we don't have parent */
5662 /* return the parent */
5663 return item
->parent
;
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 */
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
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 */
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
;
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
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 */
5746 * @brief Allows to get the \ref axlItem reference that is holding the
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
;
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 */
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 */
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
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
));
5838 * @brief Returns the item data that is stored inside the \ref axlItem
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 */
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
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
5877 char * axl_item_get_content (axlItem
* item
,
5880 axlNodeContent
* content
;
5882 /* check content received */
5886 /* check if the item reference is NULL */
5887 axl_return_val_if_fail (item
,
5889 axl_return_val_if_fail (axl_item_get_type (item
) != ITEM_NODE
&& axl_item_get_type (item
) != ITEM_PI
,
5892 /* get the content */
5893 content
= item
->data
;
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
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
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 */
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
;
5935 item
= axl_new (axlItem
, 1);
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
;
5946 /* return item created */
5951 * @internal Function that helps adding a new item to the provided
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
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
)
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
);
5982 * @brief Allows to configure xml content just after the item used as
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
,
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
;
6011 item
->parent
->last
= new_item
;
6012 item
->next
= new_item
;
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
6030 parent
->first
= item
;
6031 parent
->last
= item
;
6033 /* configure the next item to the current last
6035 parent
->last
->next
= item
;
6037 /* update the last child reference */
6038 item
->previous
= parent
->last
;
6040 parent
->last
= item
;
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
6060 axlItem
* axl_item_copy (axlItem
* item
, axlNode
* set_parent
)
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
)) {
6077 node
= axl_node_copy (item
->data
, true, true);
6078 node
->holder
= copy
;
6085 content
= axl_new (axlNodeContent
, 1);
6086 content
->content
= axl_strdup (((axlNodeContent
* ) item
->data
)->content
);
6087 content
->content_size
= ((axlNodeContent
* ) item
->data
)->content_size
;
6090 copy
->data
= content
;
6094 copy
->data
= axl_pi_copy (item
->data
);
6097 /* not implemented yet */
6099 case ITEM_FROM_FACTORY
:
6100 case ITEM_CONTENT_FROM_FACTORY
:
6105 /* return copy created */
6110 * @brief Allows to remove the \ref axlItem instance from the document
6111 * that is currently linked, optionally deallocating the memory used
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
6120 void axl_item_remove (axlItem
* 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
;
6145 item
->previous
= NULL
;
6148 axl_item_free (item
, true);
6153 } /* end axl_item_remove */
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
6165 * @param dealloc Signal to function to dealloc the memory hold the
6166 * the item replaced.
6168 void axl_item_replace (axlItem
* 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
;
6198 item
->previous
= NULL
;
6200 /* configure values */
6201 new_item
->parent
= item
->parent
;
6202 new_item
->doc
= item
->doc
;
6205 axl_item_free (item
, true);
6211 } /* end axl_item_replace */
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
,
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 */
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
6266 if (item_aux
!= NULL
)
6267 item_aux
->previous
= item
;
6269 /* break the loop! */
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
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
;
6287 /* clear reference from previous parent */
6288 old_parent
->first
= NULL
;
6289 old_parent
->last
= NULL
;
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
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
,
6313 axlNodeContent
* content
;
6314 axlNodeContent
* content2
;
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
))
6328 /* according the type */
6329 switch (axl_item_get_type (item
)) {
6331 /* check that both nodes are equal */
6332 return axl_node_are_equal (item
->data
, item2
->data
);
6337 /* get the contenet */
6338 content
= item
->data
;
6339 content2
= item2
->data
;
6342 /* check first content length */
6343 if (content
->content_size
!= content2
->content_size
)
6346 /* now check content value */
6347 return axl_cmp (content
->content
, content2
->content
);
6349 /* duplicate the content */
6350 trim
= axl_strdup (content
->content
);
6351 trim2
= axl_strdup (content2
->content
);
6354 axl_stream_trim (trim
);
6355 axl_stream_trim (trim2
);
6357 /* do the comparision */
6358 result
= axl_cmp (trim
, trim2
);
6369 return axl_pi_are_equal (item
->data
, item2
->data
);
6371 /* no case identified, not equal */
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
,
6389 axl_return_if_fail (item
);
6392 /* according the type */
6393 switch (axl_item_get_type (item
)) {
6396 axl_node_free (item
->data
);
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
);
6409 axl_free ((axlNodeContent
*)item
->data
);
6412 if ((item
->type
& ITEM_FROM_FACTORY
) == 0)
6416 /* an process instruction */
6417 axl_pi_free (item
->data
);
6420 if ((item
->type
& ITEM_FROM_FACTORY
) == 0)
6423 case ITEM_FROM_FACTORY
:
6424 case ITEM_CONTENT_FROM_FACTORY
:
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
)
6452 axlNode
* node
= axl_factory_get (factory
);
6455 node
->conf
= NODE_FROM_FACTORY
;
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
));