Annotation of gpl/axl/src/axl_node.c, revision 1.1.1.2
1.1 misho 1: /*
2: * LibAxl: Another XML library
3: * Copyright (C) 2006 Advanced Software Production Line, S.L.
4: *
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.
9: *
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.
14: *
15: * You should have received a copy of the GNU Lesser General Public
16: * License along with this program; if not, write to the Free
17: * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18: * 02111-1307 USA
19: *
20: * You may find a copy of the license under this software is released
21: * at COPYING file. This is LGPL software: you are welcome to
22: * develop proprietary applications using this library without any
23: * royalty or fee but returning back any change, improvement or
24: * addition in the form of source code, project image, documentation
25: * patches, etc.
26: *
27: * For commercial support on build XML enabled solutions contact us:
28: *
29: * Postal address:
30: * Advanced Software Production Line, S.L.
31: * Edificio Alius A, Oficina 102,
32: * C/ Antonio Suarez Nº 10,
33: * Alcalá de Henares 28802 Madrid
34: * Spain
35: *
36: * Email address:
37: * info@aspl.es - http://www.aspl.es/xml
38: */
39:
40: #include <axl.h>
41: #define LOG_DOMAIN "axl-node"
42:
43: /**
44: * \defgroup axl_node_module Axl Node: Xml node interface functions to use and manipulate xml nodes inside documents.
45: */
46:
47: /**
48: * \addtogroup axl_node_module
49: * @{
50: */
51:
52: struct _axlAttrCursor {
53: axlPointer data;
54: int count;
55: axlNode * node;
56: };
57:
58: /**
59: * @internal Axl content representation used to store comments, xml
60: * content, CDATA content and entity references.
61: */
62: typedef struct _axlNodeContent axlNodeContent;
63:
64: struct _axlNodeContent {
65: /**
66: * @internal
67: *
68: * @brief Pointer which holds current content inside the xml
69: * node.
70: */
71: char * content;
72: /**
73: * @internal
74: *
75: * @brief Current content size stored on the given axlNode.
76: */
77: int content_size;
78:
79: };
80:
81: /**
82: * @internal Type representation to hold node attributes while they
83: * are fewer.
84: */
85: typedef struct _axlNodeAttr axlNodeAttr;
86:
87: struct _axlNodeAttr {
88: /**
89: * @internal Node attribute name.
90: */
91: char * attribute;
92:
93: /**
94: * @internal Node attribute value.
95: */
96: char * value;
97:
98: /**
99: * @internal Flags the attribute pair to be considered from a
100: * factory.
101: */
102: axl_bool from_factory;
103:
104: /**
105: * @internal Next attribute.
106: */
107: axlNodeAttr * next;
108: };
109:
110: /**
111: * @internal Function that allows to copy all attributes found on the
112: * list received.
113: *
114: * @param list The attribute list to copy.
115: *
116: * @return A newly allocated attribute list.
117: */
118: axlNodeAttr * __axl_node_copy_attr_list (axlNodeAttr * list)
119: {
120: axlNodeAttr * result = NULL;
121:
122: /* if the list isn't defined, return NULL */
123: if (list == NULL)
124: return NULL;
125:
126: /* alloc memory to hold attribute name and value, and
127: * copy it from the list */
128: result = axl_new (axlNodeAttr, 1);
1.1.1.2 ! misho 129: /* check allocated result */
! 130: if (result == NULL)
! 131: return NULL;
1.1 misho 132: result->attribute = axl_strdup (list->attribute);
133: result->value = axl_strdup (list->value);
134:
135: /* call to copy the rest of the list */
136: result->next = __axl_node_copy_attr_list (list->next);
137:
138: /* return result created */
139: return result;
140: }
141:
142: /**
143: * @internal Deallocs the attribute list received.
144: *
145: * @param list The attribute list to copy.
146: *
147: * @return A newly allocated attribute list.
148: */
149: void __axl_node_free_attr_list (axlNodeAttr * attr)
150: {
151: axlNodeAttr * next;
152:
153: /* if the list isn't defined, return NULL */
154: if (attr == NULL)
155: return;
156:
157: /* copy all nodes */
158: while (attr != NULL) {
159: /* get the next attribute */
160: next = attr->next;
161:
162: /* free attribute description */
163: if (! attr->from_factory) {
164: axl_free (attr->attribute);
165: axl_free (attr->value);
166: axl_free (attr);
167: } /* end if */
168:
169: /* get the next */
170: attr = next;
171:
172: } /* end while */
173:
174: /* return result created */
175: return;
176: }
177:
178: /**
179: * @internal Function that allows to now if both lists represents the
180: * same set of attributes, even if they aren't ordered using the same.
181: *
182: * @param attr The first attribute pointing to the rest of the
183: * attribute list.
184: *
185: * @param attr2 The second attribute pointing to the rest of the
186: * attribute list.
187: *
188: * @return \ref axl_true if both lists are equal, otherwise \ref axl_false is
189: * returned.
190: */
191: axl_bool __axl_node_attr_list_is_equal (axlNodeAttr * attr, axlNodeAttr * attr2)
192: {
193: axlNodeAttr * attrAux;
194: axl_bool found;
195:
196: /* for each attribute found in the attribute list, check it on
197: * the second list */
198: while (attr != NULL) {
199:
200: attrAux = attr2;
201: found = axl_false;
202: while (attrAux != NULL) {
203:
204: /* check attribute */
205: if (axl_cmp (attrAux->attribute, attr->attribute) &&
206: axl_cmp (attrAux->value, attr->value)) {
207: /* attribute found, break the loop */
208: found = axl_true;
209: break;
210: }
211:
212: /* next attribute */
213: attrAux = attrAux->next;
214:
215: } /* end while */
216:
217: /* check if the attribute was found */
218: if (! found )
219: return axl_false;
220:
221: /* get the next */
222: attr = attr->next;
223:
224: } /* end while */
225:
226: /* all attributes was found, including its values, so, the
227: * list is equal */
228: return axl_true;
229: }
230:
231: typedef enum {
232: /**
233: * @internal Signal axl library that the node was allocated by
234: * a factory not by the system alloc.
235: */
236: NODE_FROM_FACTORY = 1,
237:
238: /**
239: * @internal Signal axl library that the node node was
240: * allocated by a factory not by the system alloc.
241: */
242: NODE_NAME_FROM_FACTORY = 1 << 2
243: } axlNodeConf;
244:
245: struct _axlNode {
246: /**
247: * @internal
248: *
249: * Node name that is the value found at the very begining of
250: * the node definition <name.../>
251: */
252: char * name;
253:
254: /**
255: * @internal Number of attributes stored. This value is used
256: * to now if the attributes are stored using a hash or a
257: * linked list. In the case it is equal or greater than 11, a
258: * hash is used to store attribute. Otherwise, a linked list
259: * (using axlAttrNode) is used.
260: */
261: int attr_num;
262:
263: /**
264: * @internal
265: * @brief The attributes this node has.
266: */
267: axlPointer * attributes;
268:
269: /**
270: * @internal A reference to the first child.
271: */
272: axlItem * first;
273:
274: /**
275: * @internal A reference to the last child.
276: */
277: axlItem * last;
278:
279: /**
280: * @internal A hash used to store arbitrary data associated to
281: * the node.
282: */
283: axlHash * annotate_data;
284:
285: /**
286: * @internal Internal reference to the holder axlItem
287: * containing the axl node reference.
288: */
289: axlItem * holder;
290:
291: /**
292: * @internal Value that contains flags for configuration.
293: */
294: int conf;
295: };
296:
297: struct _axlItem {
298: /**
299: * @internal A reference to the type that is being hold by the
300: * encapsulation reference.
301: */
302: AxlItemType type;
303:
304: /**
305: * @internal The reference to the pointer that is actually
306: * stored.
307: */
308: axlPointer data;
309:
310: /**
311: * @internal
312: * A pointer to the parent node.
313: */
314: axlNode * parent;
315:
316: /**
317: * @internal
318: *
319: * A pointer to the brother node, the node that is found on
320: * the next position.
321: */
322: axlItem * next;
323:
324: /**
325: * @internal Stores a reference to the previous node inside
326: * the same level.
327: */
328: axlItem * previous;
329:
330: /**
331: * @internal
332: *
333: * Internal reference to the whole xml document where the node
334: * is contained.
335: */
336: axlDoc * doc;
337: };
338:
339: /**
340: * @internal
341: *
342: * @brief Internal position function which ensures that nodes added
343: * will be added at the end of the list.
344: */
345: int __axl_node_equal (axlPointer a, axlPointer b)
346: {
347: return 1;
348: }
349:
350: /**
351: * @internal
352: *
353: * Internal function which allocates the enough memory to copy
354: * received content changing all escape sequences.
355: */
356: char * __axl_node_content_copy_and_escape (const char * content,
357: int content_size,
358: int additional_size,
359: axl_bool cdata)
360: {
361: int iterator = 0;
362: int iterator2 = 0;
363: char * result;
364: axl_return_val_if_fail (content, NULL);
365:
366: /* allocate the memory to be returned */
367: result = axl_new (char, content_size + additional_size + 1);
368:
369: /* iterate over all content defined */
370: while (iterator2 < content_size) {
371: /* check for ' */
372: if (content [iterator2] == '\'') {
373: memcpy (result + iterator, "'", 6);
374: iterator += 6;
375: iterator2++;
376: continue;
377: }
378:
379: /* check for " */
380: if (content [iterator2] == '"') {
381: memcpy (result + iterator, """, 6);
382: iterator += 6;
383: iterator2++;
384: continue;
385: }
386:
387: /* check for & */
388: if (content [iterator2] == '&') {
389: memcpy (result + iterator, "&", 5);
390: iterator += 5;
391: iterator2++;
392: continue;
393: }
394:
395: /* check for > */
396: if (content [iterator2] == '>') {
397: memcpy (result + iterator, ">", 4);
398: iterator += 4;
399: iterator2++;
400: continue;
401: }
402:
403: /* check for < */
404: if (content [iterator2] == '<') {
405: memcpy (result + iterator, "<", 4);
406: iterator += 4;
407: iterator2++;
408: continue;
409: }
410:
411: /* check for ]]> declaration */
412: if (content [iterator2] == ']' && content [iterator2 + 1] == ']' && content [iterator2 + 2] == '>') {
413: if (cdata) {
414: memcpy (result + iterator, "]]>]]><![CDATA[", 18);
415: iterator += 18;
416: iterator2 +=3;
417: } else {
418: memcpy (result + iterator, "]]>", 6);
419: iterator += 6;
420: iterator2 += 3;
421: }
422: continue;
423: }
424:
425: /* copy value received because it is not an escape
426: * sequence */
427: memcpy (result + iterator, content + iterator2, 1);
428:
429: /* update the iterator */
430: iterator++;
431: iterator2++;
432: }
433:
434: /* return results */
435: return result;
436: }
437:
438: /**
439: * @brief Replaces all entity references to its corresponding
440: * values. This function only implements translation for default
441: * recognized entities (&, <, >, ' and ").
442: *
443: * @param content The string content having escaped XML declarations
444: * such \> or \< which should be
445: * translated into its corresponding utf-8 symbol (for example > and
446: * <).
447: *
448: * @param content_size A non-optional reference to an integer variable
449: * which will hold the new size of the string returned. You can pass a
450: * variable initialized to 0 or -1 to let the function to calculate
451: * the initial string length (by using strlen).
452: *
453: * Because the substitution pattern applied on this operation makes
454: * not necessary to allocate memory, the function return the same
455: * string received, but with all values replaced. If you want to avoid
456: * this behaviour, use \ref axl_strdup before calling to this
457: * function.
458: *
459: * @return Returns the string modified or NULL if it fails.
460: */
461: char * axl_node_content_translate_defaults (char * content,
462: int * content_size)
463: {
464: int iterator = 0;
465: int iterator2 = 0;
466:
467: axl_return_val_if_fail (content, NULL);
468: axl_return_val_if_fail (content_size, NULL);
469:
470: /* update string length if no data was provided */
471: if (*content_size == 0 || *content_size == -1)
472: *content_size = strlen (content);
473:
474: /* iterate over all content defined */
475: while (iterator < (*content_size)) {
476:
477: /* check for ' */
478: if (axl_stream_cmp (content + iterator, "'", 6)) {
479: content [iterator2] = '\'';
480: iterator2++;
481:
482: iterator += 6;
483: continue;
484: }
485:
486: /* check for " */
487: if (axl_stream_cmp (content + iterator, """, 6)) {
488: content [iterator2] = '"';
489: iterator2++;
490:
491: iterator += 6;
492: continue;
493: }
494:
495: /* check for & */
496: if (axl_stream_cmp (content + iterator, "&", 5)) {
497: content [iterator2] = '&';
498: iterator2++;
499:
500: iterator += 5;
501: continue;
502: }
503:
504: /* check for > */
505: if (axl_stream_cmp (content + iterator, ">", 4)) {
506: content [iterator2] = '>';
507: iterator2++;
508:
509: iterator += 4;
510: continue;
511: }
512:
513: /* check for < */
514: if (axl_stream_cmp (content + iterator, "<", 4)) {
515: content [iterator2] = '<';
516: iterator2++;
517:
518: iterator += 4;
519: continue;
520: }
521:
522: /* copy move the content */
523: if (iterator2 != iterator)
524: content [iterator2] = content [iterator];
525:
526: /* update the iterator */
527: iterator++;
528: iterator2++;
529: }
530:
531: /* return results, setting the new content size */
532: *content_size = iterator2;
533: content [iterator2] = 0;
534: return content;
535: }
536:
537:
538:
539: /**
540: * @brief Creates a new \ref axlNode with the provided name.
541: *
542: * The function will perform a new local copy from the name reference
543: * received. See also \ref axl_node_create_ref for an explanation
544: * about how to save memory.
545: *
546: * @param name The name to be used for the node be created. The
547: * function doesn't check if the paramater received is null.
548: *
549: * @return A newly allocated \ref axlNode reference, that must be
550: * deallocated by \ref axl_node_free.
551: */
552: axlNode * axl_node_create (const char * name)
553: {
554:
555: axlNode * node;
556:
557: /* init the node */
558: node = axl_new (axlNode, 1);
559: node->name = axl_strdup (name);
560:
561: return node;
562: }
563:
564: /**
565: * @brief This function allows to create a xml node from the provided
566: * xml content (bootstraping XML content).
567: *
568: * This function is useful if it is required to create a node with a
569: * particular complex content, without going into the detail of
570: * creating all childs, attributes and content.
571: *
572: * Here is an example:
573: * \code
574: * axlError * error = NULL;
575: * axlNode * node = NULL;
576: *
577: * // parse document
578: * root = axl_node_parse_strings (error,
579: * "<child>",
580: * " <widget class=\"GtkLabel\" id=\"label4\">",
581: * " <property name=\"visible\">True</property>",
582: * " <property name=\"label\" translatable=\"yes\"><b>1. Seleccione el sistema:</b></property>",
583: * " <property name=\"use_underline\">False</property>",
584: * " <property name=\"use_markup\">True</property>",
585: * " <property name=\"justify\">GTK_JUSTIFY_LEFT</property>",
586: * " <property name=\"wrap\">False</property>",
587: * " <property name=\"selectable\">False</property>",
588: * " <property name=\"xalign\">0</property>",
589: * " <property name=\"yalign\">0.5</property>",
590: * " <property name=\"xpad\">0</property>",
591: * " <property name=\"ypad\">0</property>",
592: * " <property name=\"ellipsize\">PANGO_ELLIPSIZE_NONE</property>",
593: * " <property name=\"width_chars\">-1</property>",
594: * " <property name=\"single_line_mode\">False</property>",
595: * " <property name=\"angle\">0</property>",
596: * " </widget>",
597: * " <packing>",
598: * " <property name=\"padding\">0</property>",
599: * " <property name=\"expand\">False</property>",
600: * " <property name=\"fill\">False</property>",
601: * " </packing>",
602: * "</child>",
603: * NULL);
604: * if (root == NULL) {
605: * printf ("Error: unable to parse content, error: %s\n", axl_error_get (error));
606: * axl_error_free (error);
607: * return;
608: * }
609: *
610: * // once finished, free the node
611: * axl_node_free (root);
612: * \endcode
613: *
614: * @param error Optional error reference to report parsing error
615: * problems that can be found.
616: *
617: * The function receives a set of strings, separate by comma, ended by
618: * NULL.
619: *
620: * @return A newly allocated reference to the \ref axlNode or NULL if
621: * it fails. In such case, the error variable is filled with the error
622: * found.
623: */
624: axlNode * axl_node_parse_strings (axlError ** error, ...)
625: {
626: axlDoc * doc;
627: axlNode * root;
628: va_list args;
629: char * string = NULL;
630: char * stream = NULL;
631: char * stream_aux = NULL;
632:
633: /* check incoming data */
634: axl_return_val_if_fail (error, NULL);
635:
636: /* open the stdargs */
637: va_start (args, error);
638:
639: while ((string = va_arg (args, char *)) != NULL) {
640: stream_aux = stream;
641: stream = axl_stream_concat (stream, string);
642: if (stream_aux != NULL) {
643: axl_free (stream_aux);
644: stream_aux = NULL;
645: }
646: }
647:
648: /* close the stdargs */
649: va_end (args);
650:
651: /* check that we have received, at least, an string
652: * parseable */
653: if (stream == NULL)
654: return NULL;
655:
656: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "string to parse: %s", stream);
657:
658: /* parse the string */
659: doc = axl_doc_parse (stream, -1, error);
660: if (doc == NULL) {
661: /* free document */
662: axl_free (stream);
663: return NULL;
664: }
665:
666: /* free the stream */
667: axl_free (stream);
668:
669: /* deattach the root node */
670: root = axl_doc_get_root (doc);
671: axl_node_deattach (root);
672:
673: /* do not free the document, rather, store it to be
674: * deallocated by the node just after it is deallocated. */
675: axl_node_annotate_data_full (root, "__root_document", NULL, doc, (axlDestroyFunc) axl_doc_free);
676:
677: /* return the node created */
678: return root;
679: }
680:
681: /**
682: * @brief Allows to create a complete node configuring not only the
683: * node but its content, using a printf-like format.
684: *
685: * This handy function, like \ref axl_node_parse_strings, allows to
686: * create complex xml structures providing inline content.
687: *
688: * Here is an example:
689: * \code
690: * axlNode * node = axl_node_parse (NULL, "<content attr='value' attr2='value'>This is content</content>");
691: * \endcode
692: *
693: * The previous call will create a node called <b>content</b> with the
694: * provided attributes and content, in one step.
695: *
696: * The node returned can be integrated into a xml document using usual
697: * API, for example: \ref axl_node_set_child or \ref axl_doc_set_root.
698: *
699: * @param error The optional error reference holding the returned
700: * result.
701: *
702: * @param content The content to be used to create the node.
703: *
704: * @return A reference to a newly allocated \ref axlNode or NULL if it
705: * fails. The \ref axlError is filled with the error found if provided
706: * by the caller.
707: */
708: axlNode * axl_node_parse (axlError ** error, const char * content, ...)
709: {
710: char * _content;
711: va_list args;
712: axlDoc * doc;
713: axlNode * root;
714:
715: /* open the stdargs */
716: va_start (args, content);
717:
718: /* create the content */
719: _content = axl_strdup_printfv (content, args);
720:
721: /* close the stdargs */
722: va_end (args);
723:
724: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "parsing document:\n %s", _content);
725:
726: /* parse the string */
727: doc = axl_doc_parse (_content, -1, error);
728: if (doc == NULL) {
729: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "failed to parse document:\n %s", _content);
730:
731: /* free document */
732: axl_free (_content);
733:
734: return NULL;
735: }
736:
737: /* free the content */
738: axl_free (_content);
739:
740: /* deattach the root node */
741: root = axl_doc_get_root (doc);
742: axl_node_deattach (root);
743:
744: /* do not free the document, rather, store it to be
745: * deallocated by the node just after it is deallocated. */
746: axl_node_annotate_data_full (root, "__root_document", NULL, doc, (axlDestroyFunc) axl_doc_free);
747:
748: /* return the node created */
749: return root;
750: }
751:
752:
753: /**
754: * @brief Creates a new \ref axlNode but reusing the memory passed in
755: * by the name reference.
756: *
757: * This function works the same way like \ref axl_node_create, but
758: * previous one makes a local copy from the name provided. This means
759: * that, if you have allocated the reference being passed, the
760: * previous function will allocate again memory for the name
761: * reference.
762: *
763: * Obviously, for a few xml nodes this have none or little effect but,
764: * if your xml document have 100.000 nodes you save 100.000 extra
765: * memory allocations and deallocations. This may improve your
766: * application performace because memory
767: * fragmentation/allocations/deallocations are reduced.
768: *
769: * Keep in mind that this function should not be used with static strings. Example:
770: * \code
771: * // propery node creation
772: * axlNode * node = axl_node_create ("test");
773: *
774: * // NOT PROPER node creation
775: * axlNode * node = axl_node_create_ref ("test");
776: * \endcode
777: *
778: * @param name A user-space allocated memory representing the node
779: * name. The function doesn't check if the parameter received is null.
780: *
781: * @return A newly created \ref axlNode reference that must be
782: * deallocated by \ref axl_node_free.
783: */
784: axlNode * axl_node_create_ref (char * name)
785: {
786: axlNode * node;
787:
788: /* init the node */
789: node = axl_new (axlNode, 1);
790: node->name = name;
791:
792: /* return a reference to a new axlNode */
793: return node;
794: }
795:
796: /**
797: * @brief Allows to configure the node name, using the value provided.
798: *
799: * The function will dealloc the previous name stored, if found.
800: *
801: * @param node The node to be configured with a new name.
802: *
803: * @param name The new name to configure on the node. Function will
804: * create a local copy from the new name provided. The function won't
805: * check the name parameter received to be a non-null pointer.
806: */
807: void axl_node_set_name (axlNode * node, const char * name)
808: {
809: /* check the name to be already configured and dealloc it */
810: if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
811: axl_free (node->name);
812:
813: /* alloc the new name */
814: node->name = axl_strdup (name);
815: node->conf &= ~NODE_NAME_FROM_FACTORY;
816:
817: return;
818: }
819:
820: /**
821: * @brief Allows to configure the node name, using the value provided
822: * as a reference allocated and to be owned by the node.
823: *
824: * The function will dealloc the previous name stored, if found.
825: *
826: * @param node The node to be configured with a new name.
827: *
828: * @param name The new name to configure on the node. The value
829: * provided will be owned by the node. The function won't check the
830: * name parameter received to be a non-null pointer.
831: */
832: void axl_node_set_name_ref (axlNode * node, char * name)
833: {
834: /* check the name to be already configured and dealloc it */
835: if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
836: axl_free (node->name);
837:
838: /* alloc the new name */
839: node->name = name;
840:
841: return;
842: }
843:
844: /**
845: * @internal Allows to configure the xml node, flaging the string
846: * received to be owned by a factory. Do not use this API from your
847: * application. This is only useful for Axl Library internals.
848: *
849: * @param node The xml node that is going to be configured.
850: *
851: * @param name The xml node name to be configured. Previous
852: * configuration won't be deallocated as it is supposed that this
853: * function is only used from inside axl library.
854: */
855: void axl_node_set_name_from_factory (axlNode * node, char * name)
856: {
857: /* set node name */
858: node->name = name;
859:
860: /* update configuration */
861: node->conf |= NODE_NAME_FROM_FACTORY;
862:
863: return;
864: }
865:
866: axlPointer __axl_node_copy_key (axlPointer key, axlDestroyFunc key_destroy,
867: axlPointer data, axlDestroyFunc data_destroy)
868: {
869: /* copy the key */
870: return axl_strdup (key);
871: }
872:
873: axlPointer __axl_node_copy_value (axlPointer key, axlDestroyFunc key_destroy,
874: axlPointer data, axlDestroyFunc data_destroy)
875: {
876: /* copy data */
877: return axl_strdup (data);
878: }
879:
880: /**
881: * @brief Allows to perform a copy operation for the provided node.
882: *
883: * @param node The source node to copy.
884: *
885: * @param copy_attributes Signals the function to also copy node
886: * attributes into the newly created node.
887: *
888: * @param copy_childs Signals the function to also copy childs for the
889: * source node.
890: *
891: * @return A newly created node copy or null if it fails. The function
892: * will fail if the node reference provided is null.
893: */
894: axlNode * axl_node_copy (axlNode * node,
895: axl_bool copy_attributes,
896: axl_bool copy_childs)
897: {
898: axlNode * result;
899: axlItem * child;
900: axlItem * copy;
901:
902:
903: axl_return_val_if_fail (node, NULL);
904:
905: /* create the copy */
906: result = axl_node_create (axl_node_get_name (node));
907:
908: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node=<%s> (copy operation)",
909: result->name);
910:
911: /* check for attributes */
912: if (node->attributes != NULL && copy_attributes) {
913:
914: /* copy attribute configuration and attributes */
915: result->attr_num = node->attr_num;
916: if (node->attr_num >= 11) {
917: /* copy attribute list supposing it is a
918: * hash */
919: result->attributes = (axlPointer) axl_hash_copy ((axlHash *) node->attributes,
920: /* key copy function */
921: __axl_node_copy_key,
922: /* value copy function */
923: __axl_node_copy_value);
924: } else {
925: /* copy attribute list */
926: result->attributes = (axlPointer) __axl_node_copy_attr_list ((axlNodeAttr *) node->attributes);
927: }
928: }
929:
930: /* check if child nodes must be also copied */
931: if (copy_childs && (node->first != NULL)) {
932:
933: /* copy all content inside */
934: child = node->first;
935: while (child != NULL) {
936:
937: /* copy the child found */
938: copy = axl_item_copy (child, result);
939:
940: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, " new item created (copy operation) with parent=<%s> and type=%d",
941: copy->parent->name,
942: axl_item_get_type (copy));
943:
944: /* set the content */
945: axl_item_set_child_ref (result, copy);
946:
947: /* get the next element */
948: child = child->next;
949:
950: } /* end while */
951: } /* end if */
952:
953:
954: /* return the node created */
955: return result;
956: }
957:
958: /**
959: * @brief Allows to get the xml document (\ref axlDoc) where the
960: * provided xml node is stored.
961: *
962: * @param node The node that is being requested to return is xml
963: * document reference.
964: *
965: * @return The xml document reference or NULL if it is not already
966: * set.
967: */
968: axlDoc * axl_node_get_doc (axlNode * node)
969: {
970: axl_return_val_if_fail (node, NULL);
971:
972: /* return the internal reference */
973: return axl_item_get_doc (node->holder);
974: }
975:
976: /**
977: * @internal
978: *
979: * This function is not provided to the public API because it is used
980: * by the Axl internals to set the root node for a provided xml node,
981: * that is usually the root document xml node.
982: *
983: * @param node The node that is being configured to have, or being contained in, the provided xml document.
984: *
985: * @param doc The xml document that holds the node.
986: */
987: void axl_node_set_doc (axlNode * node, axlDoc * doc)
988: {
989: axlItem * item;
990:
991: axl_return_if_fail (node);
992: axl_return_if_fail (doc);
993:
994: /* get the item reference */
995: item = node->holder;
996:
997: if (item == NULL) {
998:
999: /* create an empty reference */
1000: item = axl_item_factory_get (axl_doc_get_item_factory (doc));
1001: item->type = ITEM_NODE | ITEM_FROM_FACTORY;
1002: item->data = node;
1003: node->holder = item;
1004:
1005: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node received doesn't have a holder reference, creating ref=0x%x, node=0x%x, type=%d",
1006: item, node, item->type);
1007: } /* end if */
1008:
1009: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting doc to the item node");
1010:
1011: /* call to set item at the document */
1012: item->doc = doc;
1013:
1014: return;
1015: }
1016:
1017:
1018: /**
1019: * @internal
1020: *
1021: * Support function to install attribute information provided into the
1022: * \ref axlNode provided.
1023: *
1024: * @return axl_true if the attribute was added, otherwise axl_false is
1025: * returned.
1026: */
1027: axl_bool __axl_node_set_attribute (axlFactory * factory,
1028: axlNode * node,
1029: char * attribute,
1030: char * value,
1031: axl_bool from_factory)
1032: {
1033: axlNodeAttr * attr;
1034: axlNodeAttr * next;
1035:
1036: /* init attribute list */
1037: /* do not init attribute list twice */
1038: if (node->attributes == NULL) {
1039: /* configure default axl attribute list */
1040: node->attr_num = 1;
1041:
1042: /* create the node */
1043: if (from_factory)
1044: attr = axl_factory_get (factory);
1045: else
1046: attr = axl_new (axlNodeAttr, 1);
1047: attr->from_factory = from_factory;
1048: attr->attribute = attribute;
1049: attr->value = value;
1050:
1051: /* store the node */
1052: node->attributes = (axlPointer) attr;
1053:
1054: return axl_true;
1055: }
1056:
1057: /* store the attribute using the general case */
1058: if (node->attr_num < 10) {
1059:
1060: /* check if the attribute exists */
1061: if (axl_node_has_attribute (node, attribute))
1062: return axl_false;
1063:
1064: /* create the node */
1065: if (from_factory)
1066: attr = axl_factory_get (factory);
1067: else
1068: attr = axl_new (axlNodeAttr, 1);
1069: attr->from_factory = from_factory;
1070: attr->attribute = attribute;
1071: attr->value = value;
1072:
1073: /* set the next to the new item to be the current first */
1074: attr->next = (axlNodeAttr *) node->attributes;
1075:
1076: /* set the new first */
1077: node->attributes = (axlPointer) attr;
1078:
1079: } else if (node->attr_num >= 10) {
1080:
1081: /* check if the attribute exists */
1082: if (axl_node_has_attribute (node, attribute))
1083: return axl_false;
1084:
1085: /* check if we have to translate current attributes */
1086: if (node->attr_num == 10) {
1087: /* get a reference to current attribute list */
1088: attr = (axlNodeAttr *) node->attributes;
1089:
1090: /* create the hash */
1091: node->attributes = (axlPointer) axl_hash_new_full (axl_hash_string, axl_hash_equal_string, 1);
1092:
1093: while (attr != NULL) {
1094: /* add the attribute */
1095: axl_hash_insert_full ((axlHash *) node->attributes,
1096: /* attribute name */
1097: attr->attribute, attr->from_factory ? NULL : axl_free,
1098: /* attribute value */
1099: attr->value, attr->from_factory ? NULL : axl_free);
1100: /* free current node */
1101: next = attr->next;
1102: if (! attr->from_factory)
1103: axl_free (attr);
1104:
1105: /* get the next item to store */
1106: attr = next;
1107: } /* end while */
1108:
1109: } /* end if */
1110:
1111: /* add the attribute */
1112: axl_hash_insert_full ((axlHash *) node->attributes,
1113: attribute, from_factory ? NULL : axl_free,
1114: value, from_factory ? NULL : axl_free);
1115:
1116: } /* end if */
1117:
1118: /* update attribute count */
1119: node->attr_num++;
1120:
1121: return axl_true;
1122: }
1123:
1124: /**
1125: * @brief Allows to configure an xml attribute on the given node.
1126: *
1127: * \code
1128: * <complex attr1='value'>
1129: * ..
1130: * </complex>
1131: * \endcode
1132: *
1133: * It is not allowed to store the same attribute twice inside the same
1134: * node. If the function detects that a node is being set to have the
1135: * same attribute name several times, the attribute will be silently
1136: * not added.
1137: *
1138: * Values for the attribute name (<b>attribute</b>) and its associated
1139: * value can be deallocated once the function finish. This function
1140: * will perform a local copy.
1141: *
1142: * @param node The \ref axlNode where the attribute will be installed.
1143: *
1144: * @param attribute The attribute name to configure. This value can't
1145: * be NULL.
1146: *
1147: * @param value The value associated to the attribute to be
1148: * configured. This value can't be NULL.
1149: */
1150: void axl_node_set_attribute (axlNode * node,
1151: const char * attribute,
1152: const char * value)
1153: {
1154: int additional_size = 0;
1155: char * _attr;
1156: char * _value;
1157:
1158: axl_return_if_fail (node);
1159: axl_return_if_fail (attribute);
1160: axl_return_if_fail (value);
1161:
1162: /* check for empty attribute names */
1163: if (attribute[0] == 0) {
1164: __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "skipping setting attribute with no name!");
1165: return;
1166: }
1167:
1168: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting attribute: %s='%s'", attribute, value);
1169:
1170: /* check attribute name */
1171: if (axl_node_has_invalid_chars (attribute, strlen (attribute),
1172: &additional_size)) {
1173:
1174: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found attribute content with escapable, non-valid content");
1175: _attr = __axl_node_content_copy_and_escape (attribute,
1176: strlen (attribute),
1177: additional_size,
1178: axl_false);
1179: }else {
1180:
1181: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "'%s' is a valid string..", attribute);
1182: _attr = axl_strdup (attribute);
1183: }
1184:
1185: /* check attribute value */
1186: additional_size = 0;
1187: if (axl_node_has_invalid_chars (value, strlen (value),
1188: &additional_size)) {
1189:
1190: _value = __axl_node_content_copy_and_escape (value,
1191: strlen (value),
1192: additional_size,
1193: axl_false);
1194: }else {
1195:
1196: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "'%s' is a valid string..", value);
1197: _value = axl_strdup (value);
1198: }
1199:
1200: /* insert the attribute */
1201: if (! __axl_node_set_attribute (NULL, node, _attr, _value, axl_false)) {
1202: axl_free (_attr);
1203: axl_free (_value);
1204: } /* end if */
1205:
1206: return;
1207: }
1208:
1209: /**
1210: * @brief Allows to install a new attribute pair, based on the
1211: * attribute name and the attribute value, without allocating memory
1212: * for them.
1213: *
1214: * This function works the same way like \ref axl_node_set_attribute
1215: * but reusing memory allocated by the user space.
1216: *
1217: * @param node The \ref axlNode where the attributes will be
1218: * installed.
1219: *
1220: * @param attribute The attribute name to be installed.
1221: *
1222: * @param value The attribute value to be installed.
1223: */
1224: void axl_node_set_attribute_ref (axlNode * node, char * attribute, char * value)
1225: {
1226:
1227: axl_return_if_fail (node);
1228: axl_return_if_fail (attribute);
1229: axl_return_if_fail (value);
1230:
1231: /* insert the attribute */
1232: if (! __axl_node_set_attribute (NULL, node, attribute, value, axl_false)) {
1233: axl_free (attribute);
1234: axl_free (value);
1235: return;
1236: } /* end if */
1237:
1238: return;
1239: }
1240:
1241: /**
1242: * @internal Function that allows configuring attributes to the
1243: * selected node, notifying that they come from a factory and
1244: * shouldn't be deallocated in the usual way. This function shouldn't
1245: * be used by API consumers. This is only useful for Axl Library
1246: * internals.
1247: *
1248: * @param node The node to be configured with the attribute values.
1249: *
1250: * @param attribute The attribute to configure.
1251: * @param value The attribute value to configure.
1252: */
1253: void axl_node_set_attribute_from_factory (axlFactory * factory,
1254: axlNode * node,
1255: char * attribute,
1256: char * value)
1257: {
1258: /* insert the attribute */
1259: __axl_node_set_attribute (factory, node, attribute, value, axl_true);
1260:
1261: return;
1262: }
1263:
1264: /**
1265: * @brief Allows to check if a particular attribute is installed on
1266: * the given node.
1267: *
1268: * @param node The node where the attribute will be checked to be
1269: * configured.
1270: *
1271: * @param attribute The attribute to check.
1272: *
1273: * @return A \ref axl_true if the attribute value is set, otherwise
1274: * \ref axl_false is returned.
1275: *
1276: * See also \ref HAS_ATTR.
1277: */
1278: axl_bool axl_node_has_attribute (axlNode * node, const char * attribute)
1279: {
1280: axlNodeAttr * attr;
1281:
1282: axl_return_val_if_fail (node, axl_false);
1283: axl_return_val_if_fail (attribute, axl_false);
1284:
1285: /* check for empty hash */
1286: if (node->attributes == NULL)
1287: return axl_false;
1288:
1289: if (node->attr_num <= 10) {
1290: /* linked configuration */
1291: attr = (axlNodeAttr *) node->attributes;
1292: while (attr != NULL) {
1293: /* check that the attribute is equal */
1294: if (axl_cmp (attr->attribute, attribute))
1295: return axl_true;
1296:
1297: /* get the next attribute */
1298: attr = attr->next;
1299: } /* end while */
1300:
1301: /* attribute not found */
1302: return axl_false;
1303: } /* end if */
1304:
1305: /* hashed configuration */
1306: return axl_hash_exists ((axlHash *) node->attributes, (axlPointer) attribute);
1307: }
1308:
1.1.1.2 ! misho 1309: axl_bool __axl_node_remove_attribute_reinsert (axlPointer key, axlPointer data, axlPointer user_data)
! 1310: {
! 1311:
! 1312: /* re-add attributes into the node */
! 1313: axl_node_set_attribute (user_data, key, data);
! 1314:
! 1315: return axl_false; /* do not stop until process all nodes */
! 1316: }
! 1317:
1.1 misho 1318: /**
1319: * @brief Allows to remove the provided attribute, from the node
1320: * provided.
1321: *
1322: * @param node The node to be updated by removing the attribute
1323: * provided.
1324: *
1325: * @param attribute The attribute to locate and remove.
1326: */
1327: void axl_node_remove_attribute (axlNode * node,
1328: const char * attribute)
1329: {
1330: axlNodeAttr * attr;
1331: axlNodeAttr * previous;
1.1.1.2 ! misho 1332: axlHash * temp;
1.1 misho 1333:
1334: axl_return_if_fail (node);
1335: axl_return_if_fail (attribute);
1336:
1337: /* check for empty hash */
1338: if (node->attributes == NULL)
1339: return;
1340:
1341: if (node->attr_num <= 10) {
1342: /* linked configuration */
1343: attr = (axlNodeAttr *) node->attributes;
1344: previous = NULL;
1345: while (attr != NULL) {
1346: /* check that the attribute is equal */
1347: if (axl_cmp (attr->attribute, attribute)) {
1348: /* attribute found */
1349: if (previous == NULL)
1350: node->attributes = (axlPointer) attr->next;
1351: else
1352: previous->next = attr->next;
1353:
1354: /* do not decrease attribute number
1355: * since it is used to know the kind
1356: * of store used. */
1357:
1358: /* now dealloc the attribute */
1359: if (! attr->from_factory) {
1360: axl_free (attr->attribute);
1361: axl_free (attr->value);
1362: axl_free (attr);
1363: } /* end if */
1.1.1.2 ! misho 1364:
! 1365: /* update attribute count */
! 1366: node->attr_num--;
1.1 misho 1367:
1368: return;
1369: }
1370:
1371: /* get the next attribute */
1372: previous = attr;
1373: attr = attr->next;
1374: } /* end while */
1375:
1376: /* attribute not found */
1377: return;
1378: } /* end if */
1379:
1380: /* hashed configuration */
1381: axl_hash_remove ((axlHash *) node->attributes, (axlPointer) attribute);
1382:
1.1.1.2 ! misho 1383: /* update attributes stored */
! 1384:
! 1385: node->attr_num = axl_hash_items ((axlHash *) node->attributes);
! 1386:
! 1387: /* if we have fewer than the provided number, rebuild structure */
! 1388: if (node->attr_num == 10) {
! 1389: /* reconvert attribute format */
! 1390: temp = (axlHash *) node->attributes;
! 1391: node->attributes = NULL;
! 1392: node->attr_num = 0;
! 1393:
! 1394: /* reinsert nodes */
! 1395: axl_hash_foreach (temp, __axl_node_remove_attribute_reinsert, node);
! 1396:
! 1397: /* release hash */
! 1398: axl_hash_free (temp);
! 1399:
! 1400: printf ("Number of items after reinserting..%d\n", node->attr_num);
! 1401: } /* end if */
1.1 misho 1402:
1403: return;
1404: }
1405:
1406: /**
1407: * @brief Allows to get the number of attributes installed on the
1408: * provided node.
1409: *
1410: * @param node The node that is requested to return the number of
1411: * attributes installed.
1412: *
1413: * @return Number of attributes installed, or -1 if it fails.
1414: */
1415: int axl_node_num_attributes (axlNode * node)
1416: {
1417: axl_return_val_if_fail (node, -1);
1418:
1419: if (node->attr_num <= 10) {
1.1.1.2 ! misho 1420: return node->attr_num;
1.1 misho 1421: } /* end if */
1422:
1423: /* hashed configuration */
1424: return axl_hash_items ((axlHash *) node->attributes);
1425: }
1426:
1427: /**
1428: * @brief Allows to check if the provided node has attributes
1429: * installed.
1430: *
1431: * @param node The node to be checked for attributes.
1432: *
1433: * @return \ref axl_true if the node has attributes, otherwise \ref axl_false
1434: * is returned. The function also returns \ref axl_false if a null
1435: * reference for the node is provided.
1436: */
1437: axl_bool axl_node_has_attributes (axlNode * node)
1438: {
1439: axl_return_val_if_fail (node, axl_false);
1440:
1441: /* return if the attributes reference is configured */
1442: return (node->attributes != NULL);
1443: }
1444:
1445: /**
1446: * @brief Allows to get current content of the provided attribute
1447: * inside the given node.
1448: *
1449: * It is recomended to call first to \ref axl_node_has_attribute to
1450: * ensure that the attribute to be reported its value already
1451: * exists. See also \ref ATTR_VALUE.
1452: *
1453: * @param node The \ref axlNode where the attribute value associated
1454: * will be returned.
1455: *
1456: * @param attribute The attribute that is being required for its
1457: * value.
1458: *
1459: * @return A string containing the attribute value or NULL if
1460: * fails. Returned value must not be deallocated, it is a reference to
1461: * a local copy. Use \ref axl_strdup function to get a persistent
1462: * copy.
1463: */
1464: const char * axl_node_get_attribute_value (axlNode * node, const char * attribute)
1465: {
1466: axlNodeAttr * attr;
1467:
1468: /* check values received */
1469: axl_return_val_if_fail (node, NULL);
1470: axl_return_val_if_fail (attribute, NULL);
1471:
1472: /* check for empty hash */
1473: if (node->attributes == NULL)
1474: return NULL;
1475:
1476: if (node->attr_num <= 10) {
1477: /* linked configuration */
1478: attr = (axlNodeAttr *) node->attributes;
1479: while (attr != NULL) {
1480: /* check that the attribute is equal */
1481: if (axl_cmp (attr->attribute, attribute))
1482: return attr->value;
1483:
1484: /* get the next attribute */
1485: attr = attr->next;
1486: } /* end while */
1487:
1488: /* attribute not found */
1489: return NULL;
1490: } /* end if */
1491:
1492: /* return value stored for the provided key */
1493: return axl_hash_get ((axlHash *) node->attributes, (axlPointer) attribute);
1494: }
1495:
1496: /**
1497: * @brief Gets an allocated copy for the value associated to the given
1498: * attribute.
1499: *
1500: * See \ref axl_node_get_attribute_value for more information. This
1501: * function works the same way but returning an already allocated
1502: * attribute value.
1503: *
1504: * @param node The node where the attribute value is requested.
1505: *
1506: * @param attribute The attribute that is being requested.
1507: *
1508: * @return A newly allocated reference that must be deallocated when
1509: * no longer needed calling to \ref axl_free.
1510: */
1511: char * axl_node_get_attribute_value_copy (axlNode * node,
1512: const char * attribute)
1513: {
1514: const char * _value;
1515:
1516: /* get the attribute */
1517: _value = axl_node_get_attribute_value (node, attribute);
1518: axl_return_val_if_fail (_value, NULL);
1519:
1520: /* return a copy */
1521: return axl_strdup (_value);
1522: }
1523:
1524: /**
1525: * @brief Gets the attribute content for the provided attribute name,
1526: * at the provided node, but translating entity references found.
1527: *
1528: * This function works the same way like \ref
1529: * axl_node_get_attribute_value_copy, in the sense it returns a
1530: * dinamically allocated copy for the attribute value requested but,
1531: * at the same time, it returns the content with all entity references
1532: * already translated.
1533: *
1534: * @param node The \ref axlNode instance where the attribute content
1535: * will be returned.
1536: *
1537: * @param attribute The attribute name that is being requested.
1538: *
1539: * @return The attribute content, already translated, for those
1540: * entities found. The function returns a dinamilly allocated string
1541: * so \ref axl_free must be used.
1542: */
1543: char * axl_node_get_attribute_value_trans (axlNode * node,
1544: const char * attribute)
1545: {
1546: char * _value;
1547: int size;
1548:
1549: /* get the attribute */
1550: _value = (char *) axl_node_get_attribute_value (node, attribute);
1551: axl_return_val_if_fail (_value, NULL);
1552:
1553: /* perform a local copy */
1554: _value = axl_strdup (_value);
1555:
1556: /* return a copy */
1557: size = strlen (_value);
1558: return axl_node_content_translate_defaults (_value, &size);
1559: }
1560:
1561: /**
1562: * @brief Allows to get the value associated to the attribute
1563: * provided, inside the node selected, removing trailing and ending
1564: * white spaces (in the W3C sence: \\n, \\t, \\r, ' ').
1565: *
1566: * See \ref ATTR_VALUE_TRIMMED for a convenience macro.
1567: *
1568: * @param node The node that is requested to return the associated
1569: * value to the attribute.
1570: *
1571: * @param attribute The attribute that is being requested.
1572: *
1573: * @return A reference to the attribute value or NULL if it fails. The
1574: * function doesn't return a copy, it returns a reference to the
1575: * internal value.
1576: */
1577: const char * axl_node_get_attribute_value_trimmed (axlNode * node,
1578: const char * attribute)
1579: {
1580: char * _value;
1581:
1582: /* get the attribute */
1583: _value = (char *) axl_node_get_attribute_value (node, attribute);
1584: axl_return_val_if_fail (_value, NULL);
1585:
1586: /* trim the value */
1587: axl_stream_trim (_value);
1588:
1589: /* return value */
1590: return _value;
1591: }
1592:
1593: /**
1594: * @brief Convenience function that allows to check if a particular
1595: * attribute with a particular value is found at the provided node.
1596: *
1597: * This function will check if the attribute provided in the node is
1598: * found and in such case, if the value that is contained inside the
1599: * node is actually the same as the one provide to this function.
1600: *
1601: * You can also use hits macro associated: \ref HAS_ATTR_VALUE.
1602: *
1603: * @param node The node that will be checked.
1604: * @param attribute The attribute to be checked.
1605: * @param value The value to checked if the attribute is found.
1606: *
1607: * @return \ref axl_true if the node has the attribute with the
1608: * provided value.
1609: */
1610: axl_bool axl_node_has_attribute_value (axlNode * node,
1611: const char * attribute,
1612: const char * value)
1613: {
1614: axl_return_val_if_fail (node, axl_false);
1615: axl_return_val_if_fail (attribute, axl_false);
1616: axl_return_val_if_fail (value, axl_false);
1617:
1618: /* return if the attribute value found is the same */
1619: return axl_cmp (axl_node_get_attribute_value (node, attribute), value);
1620: }
1621:
1622: /**
1623: * @}
1624: */
1625:
1626: /**
1627: * \defgroup axl_node_annotate Axl Node Annotate: An interface that allows associate arbitrary data to a particular node, indexed as a hash.
1628: */
1629:
1630: /**
1631: * \addtogroup axl_node_annotate
1632: * @{
1633: */
1634:
1635: /**
1636: * @internal function which checks and initializes the hash used for
1637: * annotated data.
1638: */
1639: void __init_node_annotation (axlNode * node)
1640: {
1641: if (node->annotate_data == NULL)
1642: node->annotate_data = axl_hash_new (axl_hash_string, axl_hash_equal_string);
1643: return;
1644: }
1645:
1646: /**
1647: * @brief Allows to store user defined data associated to the node
1648: * that is not visible from an XML perspective.
1649: *
1650: * This function allows to store data associated to the node and to
1651: * retrieve it later in an inherited fashion. This allows to store
1652: * semantic/metadata information while parsing xml documents.
1653: *
1654: * This function stores the given key using a hash,
1655: * associating the data provided on the given node. You can also check
1656: * the \ref axl_node_annotate_data_full which performs the same task
1657: * but allowing to provide key and data destroy functions.
1658: *
1659: * Once data is stored, it could be inherited by child nodes because
1660: * the access to it is done using \ref axl_node_annotate_get which can
1661: * configure the data lookup to into the particular node or its
1662: * parents.
1663: *
1664: * Additionally, you can also perform annotation using native types:
1665: * int, string and double. Check the following functions to do so.
1666: *
1667: * - \ref axl_node_annotate_int
1668: * - \ref axl_node_annotate_double
1669: * - \ref axl_node_annotate_string
1670: *
1671: * @param node The node where the annotated data will be stored.
1672: *
1673: * @param key The key under which the annotated data will be stored
1674: * (and indexed).
1675: *
1676: * @param data The data to be stored associated to the key provided.
1677: */
1678: void axl_node_annotate_data (axlNode * node,
1679: const char * key,
1680: axlPointer data)
1681: {
1682: axl_return_if_fail (node);
1683:
1684: /* check and init node annotation */
1685: __init_node_annotation (node);
1686:
1687: /* insert data */
1688: axl_hash_insert (node->annotate_data, (axlPointer) key, data);
1689:
1690: /* nothing more to do */
1691: return;
1692: }
1693:
1694: /**
1695: * @brief Allows to store user defined data associated to the node
1696: * that is not visible from an XML perspective.
1697: *
1698: * See \ref axl_node_annotate_data for a long explanation. This
1699: * function performs the same task as \ref axl_node_annotate_data but
1700: * allowing to set a key destroy and data destroy functions. They are
1701: * later used to deallocate key and data references.
1702: *
1703: * @param node The node where the annotated data will be stored.
1704: *
1705: * @param key The key under which the annotated data will be stored.
1706: *
1707: * @param key_destroy The destroy function to be called to deallocate
1708: * the key stored.
1709: *
1710: * @param data The data to be stored associated to the key provided.
1711: *
1712: * @param data_destroy The destroy function to be called to deallocate
1713: * the data provided.
1714: */
1715: void axl_node_annotate_data_full (axlNode * node,
1716: const char * key,
1717: axlDestroyFunc key_destroy,
1718: axlPointer data,
1719: axlDestroyFunc data_destroy)
1720: {
1721: axl_return_if_fail (node);
1722:
1723: /* check and init node annotation */
1724: __init_node_annotation (node);
1725:
1726: /* insert data */
1727: axl_hash_insert_full (node->annotate_data, (axlPointer) key, key_destroy, data, data_destroy);
1728:
1729: /* nothing more to do */
1730: return;
1731: }
1732:
1733: /**
1734: * @brief Allows to perform a lookup for annotated data stored on the
1735: * provided node.
1736: *
1737: * @param node The node where the lookup will be performed.
1738: *
1739: * @param key The key to lookup in the \ref axlNode reference.
1740: *
1741: * @param lookup_in_parent Once the lookup fails in the current node,
1742: * this variable allows to signal the function to also lookup the
1743: * value in the parent nodes recursively. This mechanism allows to
1744: * store data on parent nodes that are shared among all child nodes.
1745: *
1746: * @return The data associated to the key according to the lookup
1747: * configuration (lookup_in_parent and lookup_in_doc).
1748: */
1749: axlPointer axl_node_annotate_get (axlNode * node,
1750: const char * key,
1751: axl_bool lookup_in_parent)
1752: {
1753: axlPointer result = NULL;
1754: axlNode * parent;
1755:
1756: /* check node received before nothing */
1757: axl_return_val_if_fail (node, NULL);
1758: axl_return_val_if_fail (key, NULL);
1759:
1760: /* lookup the data in the current node */
1761: if (node->annotate_data != NULL) {
1762: /* lookup the data */
1763: result = axl_hash_get (node->annotate_data, (axlPointer) key);
1764:
1765: /* check result returned */
1766: if (result != NULL)
1767: return result;
1768: } /* end if */
1769:
1770: /* check if we have to lookup the data in parent nodes */
1771: if (lookup_in_parent) {
1772: /* get the first parent reference */
1773: parent = axl_item_get_parent (node->holder);
1774:
1775: /* for each parent, try to lookup the data */
1776: while (parent != NULL) {
1777: /* lookup the data */
1778: if (parent->annotate_data)
1779: result = axl_hash_get (parent->annotate_data, (axlPointer) key);
1780:
1781: /* check result returned */
1782: if (result != NULL)
1783: return result;
1784:
1785: /* get the next parent */
1786: parent = axl_item_get_parent (parent->holder);
1787: }
1788: }
1789:
1790: /* no node was found */
1791: return result;
1792: }
1793:
1794: /**
1795: * @internal definition to clasify node annotation.
1796: */
1797: typedef enum {
1798: /**
1799: * @internal definition to clasify int elements.
1800: */
1801: ANNOTATE_INT = 0,
1802: /**
1803: * @internal definition to clasify string elements.
1804: */
1805: ANNOTATE_STRING = 1,
1806: /**
1807: * @internal definition to clasify int elements.
1808: */
1809: ANNOTATE_DOUBLE = 2
1810: } AnnotateType;
1811:
1812: typedef struct _AnnotateNodeData {
1813: /**
1814: * @internal type annotated.
1815: */
1816: AnnotateType type;
1817:
1818: /**
1819: * @internal Value annotated: int, string or double.
1820: */
1821: union {
1822: int int_value;
1823: char * string_value;
1824: double double_value;
1825: } value;
1826: } AnnotateNodeData;
1827:
1828: void __axl_annotate_data_free (AnnotateNodeData * data)
1829: {
1830: if (data == NULL)
1831: return;
1832:
1833: /* free the string */
1834: if (data->type == ANNOTATE_STRING)
1835: axl_free (data->value.string_value);
1836:
1837: /* free the data */
1838: axl_free (data);
1839:
1840: return;
1841: }
1842:
1843: /**
1844: * @brief Allows to perform an annotation to the node at runtime,
1845: * storing a integer value.
1846: *
1847: * While using xml documents loaded into memory, each node could be
1848: * processed and annotated with particular information, indexed with a
1849: * key, that could be retrieved later for faster process.
1850: *
1851: * This data annotation doesn't perform any modification to the xml
1852: * document in any form. It is just a programming support that allows
1853: * developers to avoid creating complex and independent structures to
1854: * the xml document while developing XML based solutions.
1855: *
1856: * While using annotation support, you can use low level functions
1857: * that provide a simple way to store pointers associated to
1858: * particular nodes and retrieve them using:
1859: *
1860: * - \ref axl_node_annotate_data_full
1861: * - \ref axl_node_annotate_data
1862: * - \ref axl_node_annotate_get
1863: *
1864: * However, additional functions are provided to store and retreive
1865: * easily integers, strings and double data annotated. See the
1866: * following:
1867: *
1868: * - \ref axl_node_annotate_int
1869: * - \ref axl_node_annotate_string
1870: * - \ref axl_node_annotate_double
1871: *
1872: * If you use this function to store an integer data you must use \ref
1873: * axl_node_annotate_get_int to retreive data stored. You can't use
1874: * \ref axl_node_annotate_get.
1875: *
1876: * @param node The node where the annotation will be aplied.
1877: *
1878: * @param key The key to index the data annotated to the node.
1879: *
1880: * @param int_value An integer value that will be annotated to the
1881: * node received under the key provided.
1882: */
1883: void axl_node_annotate_int (axlNode * node,
1884: const char * key,
1885: int int_value)
1886: {
1887: AnnotateNodeData * data;
1888:
1889: /* check received values */
1890: axl_return_if_fail (node);
1891: axl_return_if_fail (key);
1892:
1893: /* allocate the node */
1894: data = axl_new (AnnotateNodeData, 1);
1895: data->type = ANNOTATE_INT;
1896: data->value.int_value = int_value;
1897:
1898: /* annotate the value */
1899: axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
1900:
1901: return;
1902: }
1903:
1904: /**
1905: * @brief Allows to perform an annotation to the node at runtime,
1906: * storing a string value.
1907: *
1908: * While using xml documents loaded into memory, each node could be
1909: * processed and annotated with particular information, indexed with a
1910: * key, that could be retrieved later for faster process.
1911: *
1912: * This data annotation doesn't perform any modification to the xml
1913: * document in any form. It is just a programming support that allows
1914: * developers to avoid creating complex and independent structures to
1915: * the xml document while developing XML based solutions.
1916: *
1917: * While using annotation support, you can use low level functions
1918: * that provide a simple way to store pointers associated to
1919: * particular nodes and retrieve them using:
1920: *
1921: * - \ref axl_node_annotate_data_full
1922: * - \ref axl_node_annotate_data
1923: * - \ref axl_node_annotate_get
1924: *
1925: * However, additional functions are provided to store and retreive
1926: * easily integers, strings and double data annotated. See the
1927: * following:
1928: *
1929: * - \ref axl_node_annotate_int
1930: * - \ref axl_node_annotate_string
1931: * - \ref axl_node_annotate_double
1932: *
1933: * If you use this function to store a string data you must use \ref
1934: * axl_node_annotate_get_string to retreive data stored. You can't use \ref axl_node_annotate_get.
1935: *
1936: * @param node The node where the annotation will be aplied.
1937: *
1938: * @param key The key to index the data annotated to the node.
1939: *
1940: * @param string_value A string value that will be annotated to the
1941: * node received under the key provided. This value will be copied and
1942: * released once the node is deallocated.
1943: */
1944: void axl_node_annotate_string (axlNode * node,
1945: const char * key,
1946: const char * string_value)
1947: {
1948: AnnotateNodeData * data;
1949:
1950: /* check received values */
1951: axl_return_if_fail (node);
1952: axl_return_if_fail (key);
1953: axl_return_if_fail (string_value);
1954:
1955: /* allocate the node */
1956: data = axl_new (AnnotateNodeData, 1);
1957: data->type = ANNOTATE_STRING;
1958: data->value.string_value = axl_strdup (string_value);
1959:
1960: /* annotate the value */
1961: axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
1962:
1963: return;
1964: }
1965:
1966: /**
1967: * @brief Allows to perform an annotation to the node at runtime,
1968: * storing a double value.
1969: *
1970: * While using xml documents loaded into memory, each node could be
1971: * processed and annotated with particular information, indexed with a
1972: * key, that could be retrieved later for faster process.
1973: *
1974: * This data annotation doesn't perform any modification to the xml
1975: * document in any form. It is just a programming support that allows
1976: * developers to avoid creating complex and independent structures to
1977: * the xml document while developing XML based solutions.
1978: *
1979: * While using annotation support, you can use low level functions
1980: * that provide a simple way to store pointers associated to
1981: * particular nodes and retrieve them using:
1982: *
1983: * - \ref axl_node_annotate_data_full
1984: * - \ref axl_node_annotate_data
1985: * - \ref axl_node_annotate_get
1986: *
1987: * However, additional functions are provided to store and retreive
1988: * easily integers, strings and double data annotated. See the
1989: * following:
1990: *
1991: * - \ref axl_node_annotate_int
1992: * - \ref axl_node_annotate_string
1993: * - \ref axl_node_annotate_double
1994: *
1995: * If you use this function to store a double data you must use \ref
1996: * axl_node_annotate_get_double to retreive data stored. You can't use \ref axl_node_annotate_get.
1997: *
1998: * @param node The node where the annotation will be aplied.
1999: *
2000: * @param key The key to index the data annotated to the node.
2001: *
2002: * @param double_value A string value that will be annotated to the node
2003: * received under the key provided.
2004: */
2005: void axl_node_annotate_double (axlNode * node,
2006: const char * key,
2007: double double_value)
2008: {
2009: AnnotateNodeData * data;
2010:
2011: /* check received values */
2012: axl_return_if_fail (node);
2013: axl_return_if_fail (key);
2014:
2015: /* allocate the node */
2016: data = axl_new (AnnotateNodeData, 1);
2017: data->type = ANNOTATE_DOUBLE;
2018: data->value.double_value = double_value;
2019:
2020: /* annotate the value */
2021: axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
2022:
2023: return;
2024: }
2025:
2026: /**
2027: * @brief Allows to retrieve the annotated int value stored on the
2028: * particular node, under the provided key.
2029: *
2030: * @param node The node that is required to return the annotated data.
2031: *
2032: * @param key The key to be used to lookup for the data annotated.
2033: *
2034: * @param lookup_in_parent Once the lookup fails, this variable allows
2035: * to signal the function to also lookup the value in the parent
2036: * nodes. This mechanism allows to store data on parent nodes that are
2037: * shared by child nodes.
2038: *
2039: * NOTE: To make this function work properly you must store double
2040: * values using \ref axl_node_annotate_int. Storing values using
2041: * other functions will lead to unpredictable results.
2042: *
2043: * @return The integer value stored using \ref
2044: * axl_node_annotate_int. If the key provided doesn't exists, the
2045: * function returns 0.
2046: */
2047: int axl_node_annotate_get_int (axlNode * node,
2048: const char * key,
2049: axl_bool lookup_in_parent)
2050: {
2051: AnnotateNodeData * data;
2052:
2053: /* check received values */
2054: axl_return_val_if_fail (node, 0);
2055: axl_return_val_if_fail (key, 0);
2056:
2057: /* get the annotated data */
2058: data = axl_node_annotate_get (node, key, lookup_in_parent);
2059:
2060: /* check for null value. */
2061: if (data == NULL)
2062: return 0;
2063:
2064: if (data->type != ANNOTATE_INT) {
2065: /* drop a log */
2066: __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as integer");
2067: return 0;
2068: }
2069:
2070: /* return the integer value inside */
2071: return data->value.int_value;
2072: }
2073:
2074: /**
2075: * @brief Allows to retrieve the annotated string value stored on the
2076: * particular node, under the provided key.
2077: *
2078: * @param node The node that is required to return the annotated data.
2079: *
2080: * @param key The key to be used to lookup for the data annotated.
2081: *
2082: * @param lookup_in_parent Once the lookup fails, this variable allows
2083: * to signal the function to also lookup the value in the parent
2084: * nodes. This mechanism allows to store data on parent nodes that are
2085: * shared by child nodes.
2086: *
2087: * NOTE: To make this function work properly you must store double
2088: * values using \ref axl_node_annotate_string. Storing values using
2089: * other functions will lead to unpredictable results.
2090: *
2091: * @return The string value stored using \ref
2092: * axl_node_annotate_string. If the key provided doesn't exists, the
2093: * function returns NULL.
2094: */
2095: char * axl_node_annotate_get_string (axlNode * node,
2096: const char * key,
2097: axl_bool lookup_in_parent)
2098: {
2099: AnnotateNodeData * data;
2100:
2101: /* check received values */
2102: axl_return_val_if_fail (node, NULL);
2103: axl_return_val_if_fail (key, NULL);
2104:
2105: /* get the annotated data */
2106: data = axl_node_annotate_get (node, key, lookup_in_parent);
2107:
2108: /* check for null value. */
2109: if (data == NULL)
2110: return NULL;
2111:
2112: if (data->type != ANNOTATE_STRING) {
2113: /* drop a log */
2114: __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as string");
2115: return NULL;
2116: }
2117:
2118: /* return the string value inside */
2119: return data->value.string_value;
2120: }
2121:
2122: /**
2123: * @brief Allows to retrieve the annotated double value stored on the
2124: * particular node, under the provided key.
2125: *
2126: * @param node The node that is required to return the annotated data.
2127: *
2128: * @param key The key to be used to lookup for the data annotated.
2129: *
2130: * @param lookup_in_parent Once the lookup fails, this variable allows
2131: * to signal the function to also lookup the value in the parent
2132: * nodes. This mechanism allows to store data on parent nodes that are
2133: * shared by child nodes.
2134: *
2135: * NOTE: To make this function work properly you must store double
2136: * values using \ref axl_node_annotate_double. Storing values using
2137: * other functions will lead to unpredictable results.
2138: *
2139: * @return The double value stored using \ref
2140: * axl_node_annotate_double. If the key provided doesn't exists, the
2141: * function returns 0.0.
2142: */
2143: double axl_node_annotate_get_double (axlNode * node,
2144: const char * key,
2145: axl_bool lookup_in_parent)
2146: {
2147: AnnotateNodeData * data;
2148:
2149: /* check received values */
2150: axl_return_val_if_fail (node, 0.0);
2151: axl_return_val_if_fail (key, 0.0);
2152:
2153: /* get the annotated data */
2154: data = axl_node_annotate_get (node, key, lookup_in_parent);
2155:
2156: /* check for null value. */
2157: if (data == NULL)
2158: return 0.0;
2159:
2160: if (data->type != ANNOTATE_DOUBLE) {
2161: /* drop a log */
2162: __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as double");
2163: return 0.0;
2164: }
2165:
2166: /* return the double value inside */
2167: return data->value.double_value;
2168: }
2169:
2170: /**
2171: * @}
2172: */
2173:
2174: /**
2175: * \addtogroup axl_node_module
2176: * @{
2177: */
2178:
2179: /**
2180: * @brief Allows to configure the given node to be empty.
2181: *
2182: * A \ref axlNode is empty when it is known that the node doesn't have
2183: * any content inside it as a child element. If the node has content,
2184: * and the value provided to this function is \ref axl_true, the function
2185: * will deallocate the content inside.
2186: *
2187: * You can use this function to clear all the node content (\ref
2188: * ITEM_CONTENT and \ref ITEM_CDATA) found inside the node, as follows:
2189: * \code
2190: * // clear all content inside
2191: * axl_node_set_is_empty (node, axl_true);
2192: * \endcode
2193: *
2194: * @param node The node to configure as empty.
2195: *
2196: * @param empty The value for emptyness to be used. axl_false will
2197: * mean that the node is not empty.
2198: */
2199: void axl_node_set_is_empty (axlNode * node, axl_bool empty)
2200: {
2201: axlItem * child;
2202: axlItem * aux;
2203: int removed = 0;
2204: int count = 0;
2205:
2206: axl_return_if_fail (node);
2207:
2208: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received set to empty node=<%s> is_empty=\"%s\"",
2209: node->name, empty ? "true" : "false");
2210:
2211: /* do no perform any operation if axl_false is received */
2212: if (! empty)
2213: return;
2214:
2215: /* get the first child and eliminate all content */
2216: child = node->first;
2217: while (child != NULL) {
2218:
2219: /* count each item found */
2220: count++;
2221:
2222: /* get a reference to the next */
2223: aux = child->next;
2224:
2225: /* check item node that represents content, and
2226: * therefore, an emptyless state */
2227: if (axl_item_get_type (child) == ITEM_CONTENT ||
2228: axl_item_get_type (child) == ITEM_CDATA) {
2229:
2230: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found item content and item CDATA..");
2231:
2232: /* remove the node */
2233: axl_item_remove (child, axl_true);
2234:
2235: /* count each item removed */
2236: removed++;
2237:
2238: } /* end if */
2239:
2240: /* update to the next */
2241: child = aux;
2242:
2243: } /* end while */
2244:
2245: /* now check if items removed are equal to items counted */
2246: if (removed == count) {
2247: /* then clear node references */
2248: node->first = NULL;
2249: node->last = NULL;
2250: }
2251:
2252: return;
2253: }
2254:
2255: /**
2256: * @brief Allows to get current xml node name.
2257: *
2258: * If it is required to check if the given \ref axlNode have a
2259: * particular name you can use the macro \ref NODE_CMP_NAME.
2260: *
2261: * Here is an example:
2262: * \code
2263: * void check_name (axlNode * node) {
2264: * if (NODE_CMP_NAME (node, "data")) {
2265: * // we got a xml node called "data"
2266: * }
2267: * // the node doesn't have that name
2268: * }
2269: * \endcode
2270: *
2271: * @param node The \ref axlNode where the name will be returned.
2272: *
2273: * @return A string reference containing the name. Returned value must
2274: * not deallocated. If a copy is required use \ref axl_strdup
2275: * function.
2276: */
2277: const char * axl_node_get_name (axlNode * node)
2278: {
2279: axl_return_val_if_fail (node, NULL);
2280:
2281: return node->name;
2282: }
2283:
2284: /**
2285: * @brief Allows to get the parent xml node (\ref axlNode) of the
2286: * provided xml node reference.
2287: *
2288: * @param node The xml node that is requested to return its parent
2289: * node.
2290: *
2291: * @return An internal reference to the parent node, that must not be
2292: * deallocated, or NULL if fails. The function will also return NULL
2293: * if the node provided is the document root. The function could only
2294: * fail if the provided reference is NULL.
2295: */
2296: axlNode * axl_node_get_parent (axlNode * node)
2297: {
2298: axl_return_val_if_fail (node, NULL);
2299:
2300: /* if holder is NULL, no parent is posible */
2301: if (node->holder == NULL) {
2302: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received a node without holder (an axlItem reference), unable to get the parent reference: %s",
2303: node->name);
2304: return NULL;
2305: }
2306:
2307: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node has a holder reference, returning current parent");
2308:
2309: /* return the parent */
2310: return node->holder->parent;
2311: }
2312:
2313: /**
2314: * @brief Allows to get the node that is located, at the same level,
2315: * on the next position on the child list.
2316: *
2317: * When a parent node holds more node childs, all of them have the
2318: * same parent child, and at the same time, all of them have a brother
2319: * relation. This relation makes that two nodes that are childs for a
2320: * parent node, are positioned sequentially as childs for the parent.
2321: *
2322: * This function allows to get the next child that is stored at the
2323: * next position, inside the same level, for the given child node.
2324: *
2325: * There are an alternative API that allows to get the next node,
2326: * following to the node selected, but providing the name to match. See
2327: * \ref axl_node_get_next_called.
2328: *
2329: * @param node The node to get the next xml node reference.
2330: *
2331: * @return Returns an internal reference to the next xml node or NULL
2332: * if fails. The function will also return NULL if no next xml node is
2333: * found starting from the provided reference. The root node will
2334: * always returns a NULL reference.
2335: */
2336: axlNode * axl_node_get_next (axlNode * node)
2337: {
2338: axlItem * item;
2339:
2340: axl_return_val_if_fail (node, NULL);
2341:
2342: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next node for=<%s>", axl_node_get_name (node));
2343:
2344: if (node->holder == NULL) {
2345: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received a node without item holder (maybe it wasn't inserted into a xml document)");
2346: return NULL;
2347: }
2348:
2349: /* get the next axlNode situated at the same level of the
2350: * provided axlNode reference */
2351: item = axl_item_get_next (node->holder);
2352:
2353: __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");
2354:
2355: /* while the item is not null and different from item node,
2356: * get the next */
2357: while (item != NULL) {
2358:
2359: /* get the item found */
2360: if (axl_item_get_type (item) == ITEM_NODE)
2361: return item->data;
2362:
2363: /* get next item */
2364: item = item->next;
2365:
2366: } /* end while */
2367:
2368: /* or null if no reference is defined */
2369: return NULL;
2370: }
2371:
2372: /**
2373: * @brief Allows to get the next node, following to the node provided,
2374: * matching the given name.
2375: *
2376: * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
2377: * use \ref axl_ns_node_get_next_called instead. See \ref
2378: * axl_ns_doc_validate. </i>
2379: *
2380: * @param node The node that is requested to return its next sibling
2381: * node.
2382: *
2383: * @param name The name to match for the next node.
2384: *
2385: * @return A reference to the next node or NULL if it fails. The
2386: * returned reference mustn't be deallocated.
2387: */
2388: axlNode * axl_node_get_next_called (axlNode * node,
2389: const char * name)
2390: {
2391: axlNode * next;
2392: axl_return_val_if_fail (node, NULL);
2393: axl_return_val_if_fail (name, NULL);
2394:
2395: /* while there is a next node */
2396: next = axl_node_get_next (node);
2397: while (next != NULL) {
2398: /* check the node */
2399: if (NODE_CMP_NAME (next, name))
2400: return next;
2401:
2402: /* update to the next */
2403: next = axl_node_get_next (next);
2404: } /* end while */
2405:
2406: /* no node was found */
2407: return NULL;
2408: }
2409:
2410: /**
2411: * @brief Allows to get the previous reference relative to the node
2412: * reference provided.
2413: *
2414: * See \ref axl_node_get_next. Previous reference is the considered
2415: * the previous node to the referenced provided that shares the same
2416: * parent and it is situated in the same level.
2417: *
2418: * @param node The node where the previous reference to the previous
2419: * node will be returned.
2420: *
2421: * @return The previous node reference or NULL if the node doesn't
2422: * have previous reference or NULL if the function fails (the function
2423: * only fails if the node reference provided is null).
2424: */
2425: axlNode * axl_node_get_previous (axlNode * node)
2426: {
2427: axlItem * item;
2428:
2429: axl_return_val_if_fail (node, NULL);
2430:
2431: /* get the previous axlNode situated at the same level of the
2432: * provided axlNode reference */
2433: item = axl_item_get_previous (node->holder);
2434:
2435: /* while the item is not null and different from item node,
2436: * get the previous */
2437: while ((item != NULL) && axl_item_get_type (item) !=ITEM_NODE)
2438: item = axl_item_get_previous (item);
2439:
2440: /* return the previous reference */
2441: if (item != NULL)
2442: return item->data;
2443:
2444: /* or null if no reference is defined */
2445: return NULL;
2446: }
2447:
2448: /**
2449: * @brief Allows to get the previous node, preceding to the node
2450: * provided, matching the given name.
2451: *
2452: * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
2453: * use \ref axl_ns_node_get_previous_called instead. See \ref
2454: * axl_ns_doc_validate. </i>
2455: *
2456: * @param node The node that is requested to return its previous sibling node.
2457: * @param name The name to match for the previous node.
2458: *
2459: * @return A reference to the previous node or NULL if it fails. The
2460: * returned reference mustn't be deallocated.
2461: */
2462: axlNode * axl_node_get_previous_called (axlNode * node,
2463: const char * name)
2464: {
2465: axlNode * previous;
2466:
2467: axl_return_val_if_fail (node, NULL);
2468: axl_return_val_if_fail (name, NULL);
2469:
2470: /* while there is a previous node */
2471: previous = axl_node_get_previous (node);
2472: while (previous != NULL) {
2473: /* check the node */
2474: if (NODE_CMP_NAME (previous, name))
2475: return previous;
2476:
2477: /* update to the next */
2478: previous = axl_node_get_previous (previous);
2479: } /* end while */
2480:
2481: /* no node was found */
2482: return NULL;
2483:
2484: }
2485:
2486:
2487: /**
2488: * @brief Allows to get the first child that holds the node.
2489: *
2490: * This function is considered inside the CHILDREN API, which is the
2491: * set of functions that are used to handle XML documents that have
2492: * node that contains more nodes or content, but not mixed.
2493: *
2494: * This function allows to get the first child found that is an \ref
2495: * axlNode. In the case your application is handling a document that
2496: * don't mix nodes and content at the same level inside another xml
2497: * nodes, you'll get the expected results.
2498: *
2499: * But, calling to this function on a node that contains content mixed
2500: * with another nodes, you will skip all items stored before the first
2501: * xml node found as child.
2502: *
2503: * Let's see some examples to clarify this. Provided the following xml
2504: * document:
2505: *
2506: * \code
2507: * <document>
2508: * <child>
2509: * Content
2510: * </child>
2511: * </document>
2512: * \endcode
2513: *
2514: * If you want to get a reference to the <b>child</b> node you can do
2515: * the following:
2516: *
2517: * \code
2518: * // supposing the document is already loaded in "doc"
2519: * axlNode * node = axl_doc_get_root (doc);
2520: *
2521: * // get the first child
2522: * node = axl_node_get_first_child (node);
2523: *
2524: * // now you have in "node" a reference to the child node.
2525: * \endcode
2526: *
2527: * However, in the case the previous content mix node with content as
2528: * follows:
2529: *
2530: * \code
2531: * <document>
2532: * Some content previous to the first child.
2533: * <child>
2534: * Content
2535: * </child>
2536: * </document>
2537: * \endcode
2538: *
2539: * Using this function will make you to skip the first content, that
2540: * is, <i>"Some content previous to the first child"</i>, which is found
2541: * before the <child> node. In the case you want to have full
2542: * access to all items stored as child for a particular node, check
2543: * \ref axl_item_get_first_child.
2544: *
2545: * @param node The node that is requested to return its first child.
2546: *
2547: * @return The first child node or NULL if it has no child node.
2548: */
2549: axlNode * axl_node_get_first_child (axlNode * node)
2550: {
2551: axlItem * item;
2552:
2553: /* check values */
2554: axl_return_val_if_fail (node, NULL);
2555:
2556: /* get first item child and lookup for the first child that is
2557: * a node */
2558: item = node->first;
2559: while (item != NULL) {
2560: /* check the item type */
2561: if (axl_item_get_type (item) == ITEM_NODE)
2562: return item->data;
2563:
2564: /* get the next */
2565: item = item->next;
2566: }
2567:
2568: /* return NULL: no child axlNode was found */
2569: return NULL;
2570: }
2571:
2572: /**
2573: * @brief Allows to get the last child that holds the node.
2574: *
2575: * See also \ref axl_node_get_first_child and \ref axl_item_get_last_child.
2576: *
2577: * @param node The node that is requested to return its last child.
2578: *
2579: * @return The last child node or NULL if it has no child node.
2580: */
2581: axlNode * axl_node_get_last_child (axlNode * node)
2582: {
2583: axlItem * item;
2584:
2585: /* check values */
2586: axl_return_val_if_fail (node, NULL);
2587:
2588: /* get first item child and lookup for the first child that is
2589: * a node */
2590: item = node->last;
2591: while (item != NULL) {
2592: /* check the item type */
2593: if (axl_item_get_type (item) == ITEM_NODE)
2594: return item->data;
2595:
2596: /* get the next */
2597: item = item->previous;
2598: }
2599:
2600: /* return NULL: no child axlNode was found */
2601: return NULL;
2602: }
2603:
2604: /**
2605: * @brief Allows to check if the provided \ref axlNode is empty.
2606: *
2607: * If a node have content, this function will return \ref
2608: * axl_false. The content must not be confused with the node childs. A
2609: * xml node (\ref axlNode) could be empty but have childs at the same
2610: * time (\ref axl_node_have_childs).
2611: *
2612: * The following xml code snipet shows a xml <data> node with
2613: * childs that have content, but the parent node, <data> do not
2614: * have content, therefore is empty.
2615: *
2616: * \code
2617: * <data>
2618: * <row>Some data</row>
2619: * <row>More content</row>
2620: * </data>
2621: * \endcode
2622: *
2623: * A node that is empty will return NULL data once called to \ref
2624: * axl_node_get_content.
2625: *
2626: * @param node The node to check for its empty status.
2627: *
2628: * @return \ref axl_true if the node is empty or \ref axl_false if
2629: * not.
2630: */
2631: axl_bool axl_node_is_empty (axlNode * node)
2632: {
2633: axlItem * child;
2634: axl_return_val_if_fail (node, axl_false);
2635:
2636: /* get the first child */
2637: child = node->first;
2638: while (child != NULL) {
2639:
2640: /* check item node that represents content, and
2641: * therefore, an emptyless state */
2642: if (axl_item_get_type (child) == ITEM_CONTENT ||
2643: axl_item_get_type (child) == ITEM_CDATA) {
2644:
2645: /* the node has content */
2646: return axl_false;
2647:
2648: } /* end if */
2649:
2650: /* go to the next */
2651: child = child->next;
2652:
2653: } /* end while */
2654:
2655: return axl_true;
2656: }
2657:
2658: /**
2659: * @brief Allows to get current xml node content (\ref axlNode).
2660: *
2661: * See \ref axl_node_is_empty for more details. This function allows
2662: * to get current xml node content, which is the free text enclosed
2663: * inside the node.
2664: *
2665: * Returned value is an internal reference to the content stored. So,
2666: * in the case a local copy is desired, you should check \ref
2667: * axl_node_get_content_copy.
2668: *
2669: * Keep in mind that the content returned could have references like
2670: * "&" or """ which are entities references not translated
2671: * into the application level values.
2672: *
2673: * This is done because while using the content, you may be interested
2674: * in getting the raw content to be passed to another xml parser which
2675: * is also able to process that entities.
2676: *
2677: * If you don't like this behaviour you can check \ref
2678: * axl_node_get_content_trans which returns a copy for the xml node
2679: * content with all entities references translated.
2680: *
2681: * Here is a summary of functions available to get the content of a
2682: * node:
2683: *
2684: * - \ref axl_node_get_content_copy (the same like this function but
2685: * producing an independent copy)
2686: *
2687: * - \ref axl_node_get_content_trans (the same like this function but
2688: * translating all entity references and producing an indenpendent
2689: * copy).
2690: *
2691: * - \ref axl_node_get_content_trim (the same like this function but
2692: * removing initial and trailing white spaces in the W3C sense: spaces,
2693: * tabulars, carry returns and line feed values).
2694: *
2695: * @param node The \ref axlNode node where the content will be retrieved.
2696: *
2697: * @param content_size Optional pointer to an integer variable where
2698: * the content size will be reported. If the variable is not set, the
2699: * function will not report the content size. If this value is
2700: * configured, it will contain the content size starting from 0 up to
2701: * the content size.
2702: *
2703: * @return Current xml node content. You must not deallocate reference
2704: * returned. If you want a permanet copy you should use \ref
2705: * axl_node_get_content_copy. Keep in mind that the function will always
2706: * return an string reference. In the case the node has no content, an
2707: * empty string will be returned, not NULL.
2708: */
2709: const char * axl_node_get_content (axlNode * node, int * content_size)
2710: {
2711: axlNodeContent * content;
2712: axlItem * child;
2713:
2714: axl_return_val_if_fail (node, NULL);
2715:
2716: /* get the first child */
2717: child = node->first;
2718: while (child != NULL) {
2719:
2720: /* check item node that represents content, and
2721: * therefore, an emptyless state */
2722: if (axl_item_get_type (child) == ITEM_CONTENT ||
2723: axl_item_get_type (child) == ITEM_CDATA) {
2724: /* cast a reference */
2725: content = child->data;
2726:
2727: /* return the content */
2728: if (content_size != NULL)
2729: *content_size = content->content_size;
2730:
2731: /* return a local reference */
2732: return content->content;
2733: } /* end if */
2734:
2735: /* get the next item */
2736: child = child->next;
2737:
2738: } /* end while */
2739:
2740: /* set content size to zero */
2741: if (content_size != NULL)
2742: *content_size = 0;
2743: return "";
2744: }
2745:
2746: /**
2747: * @brief Allows to set content to the given \ref axlNode instance.
2748: *
2749: * The xml node content is that part defined inside two balanced xml tags,
2750: * using the same label. Here is an example:
2751: * \code
2752: * <data>
2753: * Content inside the xml node.
2754: * </data>
2755: * \endcode
2756: *
2757: * The function perform a local copy from the content received, doing
2758: * all entity replacement required.
2759: *
2760: * The following table shows the set of characters that this function
2761: * will translate into its corresponding entity:
2762: *
2763: * <table>
2764: * <tr><td><b>Character</b></td><td>Entity name</td></tr>
2765: * <tr><td>'</td><td>&apos;</td></tr>
2766: * <tr><td><</td><td>&lt;</td></tr>
2767: * <tr><td>></td><td>&gt;</td></tr>
2768: * <tr><td>&</td><td>&amp;</td></tr>
2769: * <tr><td>"</td><td>&quot;</td></tr>
2770: * </table>
2771: *
2772: * @param node The xml node, represented by an already initialized
2773: * \ref axlNode, where the node content will be set.
2774: *
2775: * @param content The content to set to the \ref axlNode. The function
2776: * will perform a local copy from it.
2777: *
2778: * @param content_size The content size that is being provided. If -1
2779: * is used, the function will use strlen function to get current
2780: * content size.
2781: */
2782: void axl_node_set_content (axlNode * node,
2783: const char * content,
2784: int content_size)
2785: {
2786: axlNodeContent * itemContent;
2787: int additional_size = 0;
2788:
2789: axl_return_if_fail (node);
2790: axl_return_if_fail (content);
2791:
2792: /* get current content in the case a -1 is provided */
2793: if (content_size == -1)
2794: content_size = strlen (content);
2795:
2796: /* allocate the content */
2797: itemContent = axl_new (axlNodeContent, 1);
2798:
2799: /* check if the string received have escapable characters */
2800: if (axl_node_has_invalid_chars (content, content_size,
2801: &additional_size)) {
2802: /* copy content */
2803: itemContent->content = __axl_node_content_copy_and_escape (content,
2804: content_size,
2805: additional_size,
2806: axl_false);
2807: /* set node content size */
2808: itemContent->content_size = content_size + additional_size;
2809: }else {
2810: /* set current content */
2811: itemContent->content_size = content_size;
2812: itemContent->content = axl_new (char, content_size + 1);
2813:
2814: /* copy content */
2815: memcpy (itemContent->content, content, itemContent->content_size);
2816: }
2817:
2818: /* add it to the current node */
2819: axl_item_set_child (node, ITEM_CONTENT, itemContent);
2820:
2821:
2822: /* job done */
2823: return;
2824: }
2825:
2826: /**
2827: * @internal Common implementation for axl_node_set_content_ref and
2828: * axl_node_set_content_from_factory.
2829: */
2830: void __axl_node_set_content_common_ref (axlFactory * factory,
2831: axlNode * node,
2832: char * content,
2833: int content_size,
2834: axl_bool from_factory,
2835: axl_bool cdata)
2836: {
2837:
2838: axlNodeContent * itemContent;
2839:
2840: axl_return_if_fail (node);
2841: axl_return_if_fail (content);
2842:
2843: /* get current content in the case a -1 is provided */
2844: if (content_size == -1)
2845: content_size = strlen (content);
2846:
2847: /* create a content checking it it comes from the
2848: * factory. Because the string received could come from the
2849: * factory, already allocated, do not call to allocate */
2850: if (from_factory && factory)
2851: itemContent = axl_factory_get (factory);
2852: else
2853: itemContent = axl_new (axlNodeContent, 1);
2854:
2855: /* configure content size */
2856: itemContent->content_size = content_size;
2857:
2858: /* set current content */
2859: itemContent->content = content;
2860:
2861: if (from_factory) {
2862: if (cdata) {
2863: /* store it */
2864: axl_item_set_child (node, ITEM_CDATA | ITEM_CONTENT_FROM_FACTORY, itemContent);
2865: } else {
2866: /* store it */
2867: axl_item_set_child (node, ITEM_CONTENT | ITEM_CONTENT_FROM_FACTORY, itemContent);
2868: }
2869: } else {
2870: /* store it */
2871: if (cdata) {
2872: /* store as cdata */
2873: axl_item_set_child (node, ITEM_CDATA, itemContent);
2874: } else {
2875: /* store as parsed xml content */
2876: axl_item_set_child (node, ITEM_CONTENT, itemContent);
2877: }
2878: } /* end if */
2879:
2880: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting xml node (name: %s) content (size: %d) %s",
2881: node->name, itemContent->content_size, itemContent->content);
2882:
2883: return;
2884: }
2885:
2886: /**
2887: * @brief Set the content for the provided node, reusing the reference
2888: * provided, without making a local copy.
2889: *
2890: * This function works like \ref axl_node_set_content_ref but without
2891: * copy memory provided. This allows reduce memory allocations if the
2892: * memory was already allocated by the user space.
2893: *
2894: * Because this function doesn't perform a copy, if the content
2895: * received has to be escaped, the function will fail. To use this
2896: * function the caller must ensure that entity references are used to
2897: * especify the &, ', ", < or >.
2898: *
2899: * If the node have content already configured, it is deallocated,
2900: * configuring new content received.
2901: *
2902: * @param node The \ref axlNode where the content will be set.
2903: *
2904: * @param content The user space allocated content to be set to the
2905: * node.
2906: *
2907: * @param content_size The content size.
2908: */
2909: void axl_node_set_content_ref (axlNode * node,
2910: char * content,
2911: int content_size)
2912: {
2913:
2914: /* call to set content without signaling that the content
2915: * wasn't allocated by a factory. */
2916: __axl_node_set_content_common_ref (NULL, node, content, content_size, axl_false, axl_false);
2917:
2918: /* job done */
2919: return;
2920: }
2921:
2922: /**
2923: * @internal Internal API used by the axl doc module to signal that
2924: * the content was allocated though the string factory and shouldn't
2925: * be deallocated.
2926: */
2927: void axl_node_set_content_from_factory (axlFactory * factory,
2928: axlNode * node,
2929: char * content,
2930: int content_size)
2931: {
2932: /* call to set content without signaling that the content was
2933: * allocated by a factory. */
2934: __axl_node_set_content_common_ref (factory, node, content, content_size, axl_true, axl_false);
2935:
2936: /* job done */
2937: return;
2938: }
2939:
2940: /**
2941: * @brief Allows to store CDATA enclosed content on the provided node.
2942: *
2943: * Some characters are not allowed to be stored "as is" inside a
2944: * parseable XML document. The basic set of them are: &, ', ", < or >.
2945: *
2946: * In order to store content containing previous characters inside an
2947: * xml node, and to remain valid, functions like \ref
2948: * axl_node_set_content will translate those value, into the accepted
2949: * escape sequences.
2950: *
2951: * As an alternative, the XML node content could be stored enclosed as
2952: * a CDATA section: <![CDATA[..]]>, which allows to store unparsed
2953: * characters, including those not allowed.
2954: *
2955: * NOTE: In the case content received includes a ]]> declaration, it
2956: * is escaped to allow it. This is provided not to allow nested CDATA
2957: * declarations which is not allowed by XML 1.0 standard but to allow
2958: * binary content to be stored that may include a ]]> declaration.
2959: *
2960: * @param node The node where the CDATA will be stored.
2961: *
2962: * @param content The content to store.
2963: *
2964: * @param content_size The content size or -1 if required Axl to
2965: * figure out current sizes.
2966: */
2967: void axl_node_set_cdata_content (axlNode * node,
2968: const char * content,
2969: int content_size)
2970: {
2971: char * copy;
2972: int additional_size = 0;
2973:
2974: axl_return_if_fail (node);
2975: axl_return_if_fail (content);
2976:
2977: /* reconfigure content_size if found -1 value */
2978: if (content_size == -1)
2979: content_size = strlen (content);
2980:
2981: if (axl_node_has_invalid_chars_cdata (content, content_size, &additional_size)) {
2982: /* call to get escaped version */
2983: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "CDATA found content to scape (content size: %d): '%s'",
2984: content_size, content);
2985: copy = __axl_node_content_copy_and_escape (content, content_size, additional_size, axl_true);
2986: content_size += additional_size;
2987: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "CDATA content escaped (content size: %d): '%s'",
2988: content_size, copy);
2989: } else {
2990: /* call to set node content */
2991: copy = axl_strdup (content);
2992: } /* end if */
2993:
2994: /* set content */
2995: __axl_node_set_content_common_ref (NULL, node, copy, content_size, axl_false, axl_true);
2996:
2997: return;
2998: }
2999:
3000: /**
3001: * @internal Internal API used by the axl doc module to signal that
3002: * the content was allocated though the string factory and shouldn't
3003: * be deallocated, and the content was found inside cdata
3004: * declarations.
3005: */
3006: void axl_node_set_cdata_content_from_factory (axlFactory * factory,
3007: axlNode * node,
3008: char * content,
3009: int content_size)
3010: {
3011: /* call to set content without signaling that the content was
3012: * allocated by a factory. */
3013: __axl_node_set_content_common_ref (factory, node, content, content_size, axl_true, axl_true);
3014:
3015: /* job done */
3016: return;
3017: }
3018:
3019: /**
3020: * @brief Allows to configure a new comment (<!-- xml comment -->) that will be
3021: * stored as a child for the node provided.
3022: *
3023: * The comment will be placed at the end of the current child
3024: * list. So, if you want to place a xml comment before a xml node,
3025: * call first to this function and then to \ref axl_node_set_child.
3026: *
3027: * @param node The node that will contain the comment.
3028: *
3029: * @param comment The comment to be stored. The function will perform
3030: * a copy from it.
3031: *
3032: * @param comment_size The comment size or -1 to make the function to
3033: * calculate it.
3034: */
3035: void axl_node_set_comment (axlNode * node,
3036: char * comment,
3037: int comment_size)
3038: {
3039: axlNodeContent * content;
3040:
3041: axl_return_if_fail (node);
3042: axl_return_if_fail (comment);
3043:
3044: /* check current coment size */
3045: if (comment_size == -1)
3046: comment_size = strlen (comment);
3047:
3048: /* create the comment */
3049: content = axl_new (axlNodeContent, 1);
3050: content->content = axl_new (char, comment_size + 1);
3051: content->content_size = comment_size;
3052:
3053: /* copy the content */
3054: memcpy (content->content, comment, comment_size);
3055:
3056: /* now store it on the node */
3057: axl_item_set_child (node, ITEM_COMMENT, content);
3058:
3059: return;
3060: }
3061:
3062:
3063: /**
3064: * @brief Allows to get a copy for the content stored inside the given
3065: * \ref axlNode reference.
3066: *
3067: * This function works the same way than \ref axl_node_get_content but
3068: * returning a copy from the internal content, that the caller is
3069: * responsible of deallocating it.
3070: *
3071: * @param node The \ref axlNode where the content is being required.
3072: *
3073: * @param content_size An optional reference to an integer variable
3074: * where the content size will be returned. The function will return
3075: * the content size (if the variable is defined) ranging from 0 up to
3076: * the content size.
3077: *
3078: * @return A newly allocated string representing the node content.
3079: */
3080: char * axl_node_get_content_copy (axlNode * node, int * content_size)
3081: {
3082: int _content_size;
3083: char * result;
3084: const char * content;
3085:
3086: /* get the content and check if it is defined */
3087: if (content_size)
3088: content = axl_node_get_content (node, content_size);
3089: else
3090: content = axl_node_get_content (node, &_content_size);
3091:
3092: /* check result */
3093: if (content == NULL || strlen (content) == 0) {
3094: return axl_strdup ("");
3095: }
3096:
3097: /* allocate enough memory for the result */
3098: if (content_size) {
3099: result = axl_new (char, (*content_size) + 1);
3100: memcpy (result, content, *content_size);
3101: }else {
3102: result = axl_new (char, _content_size + 1);
3103: memcpy (result, content, _content_size);
3104: }
3105:
3106: /* return a newly allocated reference to the content */
3107: return result;
3108: }
3109:
3110: /**
3111: * @brief Allows to get the content inside the provided node, trimming
3112: * the head and trailing white spaces found.
3113: *
3114: * Note that calling to this function will modify the node content,
3115: * removing beginig and ending "white spaces" found. Once the function
3116: * is called, the node content will be returned by \ref
3117: * axl_node_get_content already trimmed.
3118: *
3119: * @param node The node where the content will be trimmed and
3120: * returned.
3121: *
3122: * @param content_size The node content size reference where the
3123: * content size will be reported.
3124: *
3125: * @return The reference returned is an internal copy that must not be
3126: * deallocated. The function always return content. If the node has no
3127: * content, the function will return an empty string (but never a NULL
3128: * value).
3129: */
3130: char * axl_node_get_content_trim (axlNode * node,
3131: int * content_size)
3132: {
3133: int trimmed;
3134:
3135: axlNodeContent * content;
3136: axlItem * child;
3137:
3138: axl_return_val_if_fail (node, NULL);
3139:
3140: /* get the first child */
3141: child = node->first;
3142: while (child != NULL) {
3143:
3144: /* check item node that represents content, and
3145: * therefore, an emptyless state */
3146: if (axl_item_get_type (child) == ITEM_CONTENT ||
3147: axl_item_get_type (child) == ITEM_CDATA) {
3148: /* cast a reference */
3149: content = child->data;
3150:
3151: /* trim the content */
3152: axl_stream_trim_with_size (content->content, &trimmed);
3153:
3154: /* updates current internal content size */
3155: content->content_size -= trimmed;
3156:
3157: /* return the content */
3158: if (content_size != NULL)
3159: *content_size = content->content_size;
3160:
3161: /* return a local reference */
3162: return content->content;
3163: } /* end if */
3164:
3165: /* get the next item */
3166: child = child->next;
3167:
3168: } /* end while */
3169:
3170: /* set content size to zero */
3171: if (content_size != NULL)
3172: *content_size = 0;
3173: return "";
3174: }
3175:
3176: void axl_node_get_content_trans_count (axlItem * item, int * count, int *total_size)
3177: {
3178: axlNodeContent * content;
3179:
3180: /* reset counters received */
3181: (*count) = 0;
3182: (*total_size) = 0;
3183: while (item != NULL) {
3184:
3185: /* check item time stored and increase counting */
3186: if (axl_item_get_type (item) == ITEM_CONTENT ||
3187: axl_item_get_type (item) == ITEM_CDATA) {
3188: /* found item */
3189: (*count)++;
3190:
3191: /* update totals */
3192: content = item->data;
3193: (*total_size) += content->content_size;
3194: }
3195:
3196: /* next item */
3197: item = item->next;
3198: } /* end while */
3199:
3200: return;
3201: }
3202:
3203:
3204: void axl_node_get_content_trans_copy (axlItem * item, char * result)
3205: {
3206: axlNodeContent * content;
3207: int desp;
3208:
3209: /* reset counters received */
3210: desp = 0;
3211: while (item != NULL) {
3212:
3213: /* check item time stored and increase counting */
3214: if (axl_item_get_type (item) == ITEM_CONTENT ||
3215: axl_item_get_type (item) == ITEM_CDATA) {
3216: /* update totals */
3217: content = item->data;
3218:
3219: /* copy content */
3220: memcpy (result + desp, content->content, content->content_size);
3221:
3222: /* update iterator */
3223: desp += content->content_size;
3224: }
3225:
3226: /* next item */
3227: item = item->next;
3228: } /* end while */
3229:
3230: return;
3231: }
3232:
3233: /**
3234: * @brief Allows to the get node content, performing a memory
3235: * allocation for the returned result, translating default entities
3236: * values with its replacement text.
3237: *
3238: * @param node The XML node where the content is being requested to be
3239: * translated.
3240: *
3241: * @param content_size An optional reference to an integer variable to
3242: * return the node content size.
3243: *
3244: * @return A newly allocated string, representing the node content,
3245: * with all entities references already translated into the
3246: * replacement text.
3247: */
3248: char * axl_node_get_content_trans (axlNode * node, int * content_size)
3249: {
3250: char * result;
3251: int _content_size = 0;
3252: int count;
3253: int total_size;
3254:
3255: /* check received reference */
3256: axl_return_val_if_fail (node, NULL);
3257:
3258: /* check if the node has one item content inside the node or
3259: * several CDATA or content items */
3260: axl_node_get_content_trans_count (node->first, &count, &total_size);
3261:
3262: /* accoring to the number of items found */
3263: switch (count) {
3264: case 0:
3265: /* report content size */
3266: if (content_size)
3267: *content_size = 0;
3268: /* nothing found return */
3269: return NULL;
3270: case 1:
3271: /* get a copy for the node content, getting the node
3272: * content size. If the user don't provide a
3273: * reference, use a local one. */
3274: if (content_size)
3275: result = axl_node_get_content_copy (node, content_size);
3276: else
3277: result = axl_node_get_content_copy (node, &_content_size);
3278: break;
3279: default:
3280: /* if reached this place, only positive values from 2
3281: * up to N are found */
3282: result = axl_new (char, total_size + 1);
3283: if (content_size)
3284: *content_size = total_size;
3285: else
3286: _content_size = total_size;
3287:
3288: /* now copy all content found */
3289: axl_node_get_content_trans_copy (node->first, result);
3290: }
3291:
3292:
3293: /* check result returned */
3294: if (result == NULL || strlen (result) == 0) {
3295: /* do not perform a copy here, it is already done by
3296: * get_content_copy, even in error */
3297: return result;
3298: }
3299:
3300: /* translate all references that performs the entities to the
3301: * replacement text. */
3302: if (content_size)
3303: return axl_node_content_translate_defaults (result, content_size);
3304: return axl_node_content_translate_defaults (result, &_content_size);
3305: }
3306:
3307:
3308: /**
3309: * @brief Allows to configure a child node to the given parent.
3310: *
3311: * This is a fundamental function while building xml document inside
3312: * memory. The way the xml nodes are linked to conform the xml
3313: * document structure relay on this function.
3314: *
3315: * The idea is that every call to this function makes the <b>child
3316: * </b> xml node to be placed at the end of the current item child
3317: * set, that represents current child list for the provided
3318: * <b>parent</b>.
3319: *
3320: * One important question while using this function is that you must
3321: * not reuse the same xml node reference, adding it several time to
3322: * the same parent (or different parents). You must create a new xml
3323: * node reference (axl_node_create) for every call you do to this
3324: * function.
3325: *
3326: * So, to build the following structure:
3327: * \code
3328: * <document>
3329: * <child1 />
3330: * <child2 />
3331: * </document>
3332: * \endcode
3333: *
3334: * You must perform the following operations:
3335: * \code
3336: * axlNode * parent;
3337: * axlNode * child;
3338: *
3339: * // create the parent node
3340: * parent = axl_node_create ("document");
3341: *
3342: * // create the first child
3343: * child = axl_node_create ("child1");
3344: *
3345: * // set it to the parent
3346: * axl_node_set_child (parent, child);
3347: *
3348: * // create the second child
3349: * child = axl_node_create ("child2");
3350: *
3351: * // set it to the parent
3352: * axl_node_set_child (parent, child);
3353: *
3354: * \endcode
3355: *
3356: * See also \ref axl_node_set_child_after which could help you adding
3357: * new nodes not using a parent node as a reference but a brother
3358: * node.
3359: *
3360: * @param parent The parent node.
3361: *
3362: * @param child The child node. The child node must be a deep
3363: * copy. Passing several references, pointing to the same value, will
3364: * cause to seg fault the program at the time the parent child is
3365: * deallocated.
3366: */
3367: void axl_node_set_child (axlNode * parent, axlNode * child)
3368: {
3369: axl_return_if_fail (parent);
3370: axl_return_if_fail (child);
3371:
3372: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received parent=0x%x and child=0x%x", parent, child);
3373:
3374: /* set a xml node child */
3375: axl_item_set_child (parent, ITEM_NODE, child);
3376:
3377: return;
3378: }
3379:
3380: /**
3381: * @brief Sets a new child after the node provided, using it as a
3382: * reference.
3383: *
3384: * This function is useful to allow configuring new childs placed
3385: * after some particular node. The child configured will be placed
3386: * after the reference and child of the reference's parent node.
3387: *
3388: * @param reference The xml node acting as a reference.
3389: * @param child The new xml node child to configure.
3390: */
3391: void axl_node_set_child_after (axlNode * reference,
3392: axlNode * child)
3393: {
3394: /* call to the item implementation */
3395: axl_item_set_after (reference->holder, ITEM_NODE, child);
3396:
3397: return;
3398: }
3399:
3400: /**
3401: * @brief Allows to replace a selected node with a new reference
3402: * inside its context (updating all references: next, previous and
3403: * parent).
3404: *
3405: * The \ref axlNode replaced will be unreference according to dealloc
3406: * value.
3407: *
3408: * @param node The node to be replaced by <b>new_node</b> reference.
3409: *
3410: * @param new_node The node that will replace <b>node</b> reference.
3411: *
3412: * @param dealloc Signal if <b>node</b> must be deallocated after the
3413: * replace operation.
3414: */
3415: void axl_node_replace (axlNode * node,
3416: axlNode * new_node,
3417: axl_bool dealloc)
3418: {
3419: axlItem * p_item;
3420:
3421: axl_return_if_fail (node);
3422: axl_return_if_fail (new_node);
3423:
3424: if (axl_item_get_parent (node->holder) == NULL) {
3425: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "replacing the root node=<%s> with <%s>..",
3426: axl_node_get_name (node), axl_node_get_name (new_node));
3427: /* seems to be a root document */
3428: if (axl_item_get_doc (node->holder) != NULL) {
3429: axl_doc_set_root (axl_item_get_doc (node->holder), new_node);
3430: }
3431: } else {
3432:
3433: /* check for holder reference */
3434: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "replacing a non-root node=<%s> with <%s>..",
3435: axl_node_get_name (node), axl_node_get_name (new_node));
3436: if (node->holder != NULL) {
3437:
3438: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "axl item holder is defined for node=<%s>",
3439: axl_node_get_name (node));
3440: /* get a reference to the holder item */
3441: p_item = node->holder;
3442:
3443: /* configure the new node */
3444: p_item->data = new_node;
3445:
3446: /* nullify the holder reference, and configure
3447: * the holder reference in the node */
3448: node->holder = NULL;
3449: new_node->holder = p_item;
3450:
3451: } /* end if */
3452: }
3453:
3454: /* dealloc node if configured so */
3455: if (dealloc) {
3456: /* free the node */
3457: axl_node_free (node);
3458: }
3459:
3460: return;
3461: }
3462:
3463: /**
3464: * @brief Allows to remove the selected reference from the document
3465: * containing it.
3466: *
3467: * The function remove the selected reference from the document. If
3468: * the node asked to be removed is the root one, the node won't be
3469: * removed because the \ref axl_doc_set_root doesn't accept to remove
3470: * the root node.
3471: *
3472: * All childs hold by the node removed from the document will also be
3473: * removed if dealloc is selected.
3474: *
3475: * @param node The node to remove.
3476: *
3477: * @param dealloc \ref axl_true to also dealloc the memory used by the
3478: * node. Setting this parameter to \ref axl_false only unlinks the
3479: * node from the document making possible to reuse the node in another
3480: * part of the document or to move the node to a different document.
3481: */
3482: void axl_node_remove (axlNode * node,
3483: axl_bool dealloc)
3484: {
3485: axlItem * item;
3486: axl_return_if_fail (node);
3487:
3488: /* get a reference to the item element */
3489: item = node->holder;
3490:
3491: /* check if the node is the root node of its document */
3492: if (item != NULL && item->doc != NULL) {
3493: if (axl_doc_get_root (item->doc) == node) {
3494: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "attempting to dettach the root node from the document, nullify");
3495: axl_doc_set_root (item->doc, NULL);
3496: } /* end if */
3497: } /* end if */
3498:
3499: if (axl_item_get_parent (item) != NULL) {
3500:
3501: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "doing reference relocation (remove operation) for=<%s>",
3502: node->name);
3503:
3504: /* make previous node to point to the new node */
3505: if (item->previous != NULL) {
3506: item->previous->next = item->next;
3507: }
3508:
3509: /* make next node to point to the new node */
3510: if (item->next != NULL) {
3511: item->next->previous = item->previous;
3512: }
3513:
3514: /* now, update the parent reference */
3515: if (item->previous == NULL) {
3516: /* seems the node is the first child of the parent,
3517: * update the reference */
3518: item->parent->first = item->next;
3519: }
3520:
3521: if (item->next == NULL) {
3522: /* seems the node is the last child of the parent,
3523: * update the reference */
3524: item->parent->last = item->previous;
3525: }
3526:
3527: if (item != NULL) {
3528: /* disconnect the item */
3529: item->previous = NULL;
3530: item->next = NULL;
3531: } /* end if */
3532:
3533: } /* end if */
3534:
3535: /* dealloc node if configured so */
3536: if (dealloc) {
3537: /* free the node */
3538: axl_node_free (node);
3539: }
3540:
3541: return;
3542: }
3543:
3544: /**
3545: * @brief Supposing the node is attached to a xml document (\ref
3546: * axlDoc), this function allows to deattach the node from the
3547: * document that is holding it.
3548: *
3549: * This function is useful while requiring to reallocate nodes from
3550: * parent to parent, making the parent node that is holding it to
3551: * cancel its references to the node, decreasing all internal counts
3552: * to the node, etc.
3553: *
3554: * If the node isn't attached to any document, the function does
3555: * nothing.
3556: *
3557: * @param node The node to deattach.
3558: */
3559: void axl_node_deattach (axlNode * node)
3560: {
3561: axl_return_if_fail (node);
3562:
3563: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "deattaching node..");
3564:
3565: /* call to remove */
3566: axl_node_remove (node, axl_false);
3567:
3568: return;
3569: }
3570:
3571: /**
3572: * @brief Allows to configure that the given node have child nodes.
3573: *
3574: * <b>DEPRECATED:</b> The function doesn't perform any operation. See
3575: * \ref axl_node_have_childs.
3576: *
3577: * @param node The node to configure.
3578: *
3579: * @param childs The child configuration, \ref axl_true to notify that
3580: * the node have childs, otherwise, \ref axl_false is returned.
3581: */
3582: void axl_node_set_have_childs (axlNode * node, axl_bool childs)
3583: {
3584: /* do nothing */
3585: return;
3586: }
3587:
3588: /**
3589: * @brief Allows to get current childs configuration from the given
3590: * xml node (\ref axlNode).
3591: *
3592: * An xml node (represented by an \ref axlNode) is considered to have
3593: * childs only if it has more xml child nodes. The content is not
3594: * considered be a child. See \ref axl_node_is_empty for more
3595: * information.
3596: *
3597: * @param node The \ref axlNode reference.
3598: *
3599: * @return An \ref axl_true if the \ref axlNode have childs or \ref
3600: * axl_false if not.
3601: */
3602: axl_bool axl_node_have_childs (axlNode * node)
3603: {
3604: axlItem * item;
3605:
3606: axl_return_val_if_fail (node, axl_false);
3607:
3608: item = node->first;
3609: while (item != NULL) {
3610: /* check item type */
3611: if (axl_item_get_type (item) == ITEM_NODE)
3612: return axl_true;
3613:
3614: /* go to the next */
3615: item = item->next;
3616:
3617: } /* end while */
3618:
3619: /* return axl_false because no item was found with ITEM_NODE
3620: * type */
3621: return axl_false;
3622: }
3623:
3624: /**
3625: * @internal Function that allows to check if the provided node have
3626: * childs, including in the list, nodes, comments,
3627: *
3628: * @param node
3629: *
3630: * @return
3631: */
3632: axl_bool axl_node_have_childs_aux (axlNode * node)
3633: {
3634: axlItem * item;
3635:
3636: axl_return_val_if_fail (node, axl_false);
3637:
3638: item = node->first;
3639: while (item != NULL) {
3640: /* check item type */
3641: if (axl_item_get_type (item) == ITEM_NODE ||
3642: axl_item_get_type (item) == ITEM_PI ||
3643: axl_item_get_type (item) == ITEM_COMMENT)
3644: return axl_true;
3645:
3646: /* go to the next */
3647: item = item->next;
3648:
3649: } /* end while */
3650:
3651: /* return axl_false because no item was found with ITEM_NODE
3652: * type */
3653: return axl_false;
3654: }
3655:
3656: /**
3657: * @brief Allows to get a particular child node from the given node
3658: * (\ref axlNode).
3659: *
3660: * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
3661: * use \ref axl_ns_node_get_child_called instead. See \ref
3662: * axl_ns_doc_validate. </i>
3663: *
3664: * @param parent The parent node where the child will be looked up.
3665: *
3666: * @param name The name for the child to search.
3667: *
3668: * @return A refernce to a \ref axlNode or NULL if no child exists
3669: * called by the name provided, inside the node provided.
3670: */
3671: axlNode * axl_node_get_child_called (axlNode * parent, const char * name)
3672: {
3673: axlNode * node;
3674: axlItem * item;
3675:
3676: axl_return_val_if_fail (parent, NULL);
3677: axl_return_val_if_fail (name, NULL);
3678:
3679: /* if the child list is not defined, assume there is no node
3680: * called the name requested */
3681: if (parent->first == NULL)
3682: return NULL;
3683:
3684: /* if no childs, no result */
3685: item = parent->first;
3686: while (item != NULL) {
3687: /* check item type */
3688: if (axl_item_get_type (item) == ITEM_NODE) {
3689: /* get a reference to the node */
3690: node = item->data;
3691:
3692: /* compare for find the child */
3693: if (NODE_CMP_NAME (node, name))
3694: return node;
3695:
3696: } /* end if */
3697:
3698: /* next child */
3699: item = axl_item_get_next (item);
3700: }
3701:
3702: /* no child was found */
3703: return NULL;
3704: }
3705:
3706: /**
3707: * @brief Allows to find the first child called <b>name</b>, inside
3708: * all childs (including its descendants) held by the parent provided.
3709: *
3710: * This function is similar to \ref axl_node_get_child_called but
3711: * though it will also look for a child node called as provided not
3712: * only in direct childs but also on its all descendants.
3713: *
3714: * If you are looking for a function to search for a particular child
3715: * node inside direct childs stored for the provided parent, then you
3716: * must use \ref axl_node_get_child_called.
3717: *
3718: * There is also a convenience function that allows to perform a
3719: * lookup using as a reference a document (using the root node from
3720: * it): \ref axl_doc_find_called.
3721: *
3722: * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
3723: * use \ref axl_ns_node_find_called instead. See \ref
3724: * axl_ns_doc_validate. </i>
3725: *
3726: * @param parent The parent where the lookup will be produced.
3727: *
3728: * @param name The name of the child to be looked up.
3729: *
3730: * @return A reference to the node found (first instaned matching the
3731: * name) or NULL if it fails to find a child.
3732: */
3733: axlNode * axl_node_find_called (axlNode * parent, const char * name)
3734: {
3735: axlNode * node;
3736: axlNode * child;
3737:
3738: /* for the first child found */
3739: node = axl_node_get_first_child (parent);
3740: while (node != NULL) {
3741: /* check and return the node found */
3742: if (NODE_CMP_NAME (node, name))
3743: return node;
3744:
3745: /* get next */
3746: node = axl_node_get_next (node);
3747: } /* end while */
3748:
3749: /* now, for all childs, try to look for the node */
3750: node = axl_node_get_first_child (parent);
3751: while (node != NULL) {
3752: /* make the search */
3753: child = axl_node_find_called (node, name);
3754:
3755: /* child found, return the reference */
3756: if (child != NULL)
3757: return child;
3758:
3759: /* get next */
3760: node = axl_node_get_next (node);
3761: } /* end while */
3762:
3763: /* child note found */
3764: return NULL;
3765: }
3766:
3767: /**
3768: * @brief Allows to get the child that is located at the given
3769: * position, inside the given parent node.
3770: *
3771: * @param parent The parent node where the child will be looked up.
3772: *
3773: * @param position The position where the child will be looked up. The
3774: * values for the position ranges from 0 up to (N - 1).
3775: *
3776: * @return A reference to the child node \ref axlNode or NULL if fails.
3777: */
3778: axlNode * axl_node_get_child_nth (axlNode * parent, int position)
3779: {
3780: int iterator;
3781: axlItem * item;
3782:
3783: /* perform some environment checks */
3784: axl_return_val_if_fail (parent, NULL);
3785:
3786: /* check for first reference */
3787: if (parent->first == NULL) {
3788: return NULL;
3789: }
3790:
3791: /* get the first item */
3792: item = parent->first;
3793:
3794: /* get the first node found */
3795: iterator = 0;
3796: while (item != NULL) {
3797: /* check the item type */
3798: if (axl_item_get_type (item) == ITEM_NODE) {
3799: if (iterator == position) {
3800: return item->data;
3801: } else
3802: iterator++;
3803: } /* end if */
3804:
3805: /* get the next */
3806: item = item->next;
3807:
3808: } /* end while */
3809:
3810: /* no first child found */
3811: return NULL;
3812: }
3813:
3814: /**
3815: * @brief Allows to get the number of childs that the provided node
3816: * has.
3817: *
3818: * @param parent The node where the number of childs is being queried.
3819: *
3820: * @return The number of childs or -1 if fails.
3821: */
3822: int axl_node_get_child_num (axlNode * parent)
3823: {
3824: int count;
3825: axlItem * item;
3826:
3827: /* perform some environment checks */
3828: axl_return_val_if_fail (parent, -1);
3829:
3830: /* init values */
3831: count = 0;
3832: item = parent->first;
3833:
3834: /* for each child inside the parent node */
3835: while (item != NULL) {
3836:
3837: /* check item type */
3838: if (axl_item_get_type (item) == ITEM_NODE)
3839: count++;
3840:
3841: /* get the next */
3842: item = item->next;
3843:
3844: } /* end while */
3845:
3846: /* return the number of chils */
3847: return count;
3848: }
3849:
3850:
3851: /**
3852: * @brief Allows to get childs nodes from the given xml node (\ref
3853: * axlNode).
3854: *
3855: * This function creates a newly allocated list. In the case you want
3856: * to iterate over all nodes, it is better to use something similar to
3857: * this:
3858: *
3859: * \code
3860: * axlNode * child;
3861: *
3862: * // get the first child
3863: * child = axl_node_get_first_child (parent);
3864: *
3865: * // iterate over all nodes
3866: * while (child != NULL) {
3867: *
3868: * // do something with the child
3869: * do_some_work (child);
3870: *
3871: * // update the reference to the next child
3872: * child = axl_node_get_next (child);
3873: * }
3874: * \endcode
3875: *
3876: * @param node The node where the childs will be returned.
3877: *
3878: * @return An \ref axlList containing \ref axlNode items or NULL if it
3879: * fails. The list returned MUST be deallocated.
3880: */
3881: axlList * axl_node_get_childs (axlNode * node)
3882: {
3883: axlItem * child;
3884: axlList * result;
3885:
3886: axl_return_val_if_fail (node, NULL);
3887:
3888: /* create the result list without destroy function */
3889: result = axl_list_new (__axl_node_equal, NULL);
3890:
3891: /* get the first child */
3892: child = node->first;
3893:
3894: while (child != NULL) {
3895: /* check the node type */
3896: if (axl_item_get_type (child) == ITEM_NODE) {
3897: /* add the child to the list */
3898: axl_list_add (result, child->data);
3899:
3900: } /* end if */
3901:
3902: /* update the reference to the next child */
3903: child = child->next;
3904: } /* end while */
3905:
3906: /* return current childs */
3907: return result;
3908: }
3909:
3910: axl_bool __axl_node_are_equal_attr (axlPointer key,
3911: axlPointer value,
3912: axlPointer user_data,
3913: axlPointer user_data2)
3914: {
3915: char * value2;
3916: axl_bool * result = user_data2;
3917:
3918: /* get the attr value and compare it with data */
3919: value2 = axl_hash_get ((axlHash *) user_data, (char *) key);
3920:
3921: if (! axl_cmp ((char *) value, value2)) {
3922: /* flag that node attributes aren't equal */
3923: (* result) = axl_false;
3924:
3925: /* stop foreach */
3926: return axl_true;
3927: }
3928:
3929: /* make the process to continue */
3930: return axl_false;
3931: }
3932:
3933: /**
3934: * @brief Allows to check if the provided references represents two
3935: * equivalent nodes.
3936: *
3937: * The function will check node name, node content and node attributes
3938: * and its values.
3939: *
3940: * @param node The node to check.
3941: * @param node2 The second node to check.
3942: * @param error Optional reference to an \ref axlError where the particular differ is reported.
3943: *
3944: * @return axl_true if both nodes are equivalent or axl_false if not.
3945: */
3946: axl_bool axl_node_are_equal_full (axlNode * node, axlNode * node2, axlError ** error)
3947: {
3948: axl_bool result;
3949:
3950: if (node == NULL) {
3951: axl_error_report (error, -1, "Nodes differs because first node reference is NULL");
3952: return axl_false;
3953: } /* end if */
3954: if (node2 == NULL) {
3955: axl_error_report (error, -1, "Nodes differs because second node reference is NULL");
3956: return axl_false;
3957: } /* end if */
3958:
3959: /* check document root name */
3960: if (! axl_cmp (axl_node_get_name (node), axl_node_get_name (node2))) {
3961: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node names aren't equal <%s> != <%s>",
3962: node->name, node2->name);
3963: axl_error_report (error, -1, "node names aren't equal <%s> != <%s>",
3964: node->name, node2->name);
3965: return axl_false;
3966: }
3967:
3968: /* check empty ness configuration */
3969: if (axl_node_is_empty (node) != axl_node_is_empty (node2)) {
3970: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "emptyness configuration differs <%s> != <%s>",
3971: node->name, node2->name);
3972:
3973: axl_error_report (error, -1, "emptyness configuration differs <%s> != <%s>",
3974: node->name, node2->name);
3975: return axl_false;
3976: }
3977:
3978: /* check childs configuration */
3979: if (axl_node_have_childs (node) != axl_node_have_childs (node2)) {
3980: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "childs configuration differs <%s> != <%s>",
3981: node->name, node2->name);
3982: axl_error_report (error, -1, "childs configuration differs <%s> != <%s>",
3983: node->name, node2->name);
3984: return axl_false;
3985: }
3986:
3987: /* check childs number */
3988: if (axl_node_get_child_num (node) != axl_node_get_child_num (node2)) {
3989: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "child number differs <%s>(%d) != <%s>(%d)",
3990: node->name, axl_node_get_child_num (node), node2->name, axl_node_get_child_num (node2));
3991: axl_error_report (error, -1, "childs configuration differs <%s> != <%s>",
3992: node->name, node2->name);
3993: return axl_false;
3994: }
3995:
3996: /* check attribute values */
3997: if ((node->attributes != NULL && node2->attributes != NULL)) {
3998:
3999: /* check the number of attributes that has the hash */
4000: if (node->attr_num != node2->attr_num) {
4001: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "both nodes have different number of attributes (<%s>:%d != <%s>:%d)",
4002: node->name, node->attr_num,
4003: node2->name, node2->attr_num);
4004: axl_error_report (error, -1, "both nodes have different number of attributes (<%s>:%d != <%s>:%d)",
4005: node->name, node->attr_num,
4006: node2->name, node2->attr_num);
4007: return axl_false;
4008: }
4009:
4010: /* now both hashes */
4011: result = axl_true;
4012: if (node->attr_num <= 10) {
4013: /* check both list are equal */
4014: result = __axl_node_attr_list_is_equal ((axlNodeAttr *) node->attributes, (axlNodeAttr *) node2->attributes);
4015: } else {
4016: /* check both hashes are equal */
4017: axl_hash_foreach2 ((axlHash *) node->attributes, __axl_node_are_equal_attr, (axlHash *) node2->attributes, &result);
4018: }
4019:
4020: if (! result) {
4021: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node attributes differs <%s> != <%s>",
4022: node->name, node2->name);
4023: axl_error_report (error, -1, "node attributes differs <%s> != <%s>",
4024: node->name, node2->name);
4025: /* attribute missmatch */
4026: return axl_false;
4027: }
4028: } else {
4029: if (node->attributes == NULL && node2->attributes != NULL) {
4030: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node <%s> has no attributes but <%s> has",
4031: axl_node_get_name (node), axl_node_get_name (node2));
4032: axl_error_report (error, -1, "node <%s> has no attributes but <%s> has",
4033: axl_node_get_name (node), axl_node_get_name (node2));
4034: return axl_false;
4035: }
4036:
4037: if (node2->attributes == NULL && node->attributes != NULL) {
4038: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node <%s> has no attributes but <%s> has",
4039: axl_node_get_name (node2), axl_node_get_name (node));
4040: axl_error_report (error, -1, "node <%s> has no attributes but <%s> has",
4041: axl_node_get_name (node2), axl_node_get_name (node));
4042: return axl_false;
4043: }
4044:
4045: } /* end if */
4046:
4047: /* both nodes seems to be equal */
4048: return axl_true;
4049: }
4050:
4051: /**
4052: * @brief Allows to check if the provided references represents two
4053: * equivalent nodes.
4054: *
4055: * The function will check node name, node content and node attributes
4056: * and its values.
4057: *
4058: * @param node The node to check.
4059: * @param node2 The second node to check.
4060: *
4061: * @return axl_true if both nodes are equivalent or axl_false if not.
4062: */
4063: axl_bool axl_node_are_equal (axlNode * node, axlNode * node2)
4064: {
4065: /* use common implementation */
4066: return axl_node_are_equal_full (node, node2, NULL);
4067: }
4068:
4069: /**
4070: * @brief Allows to associate a PI element, including its content to
4071: * the provided node.
4072: *
4073: * See the following function for more information: \ref
4074: * axl_doc_add_pi_target.
4075: *
4076: * @param node The \ref axlNode where the PI element (\ref axlPI) will
4077: * be added.
4078: *
4079: * @param target The PI target name to add.
4080: *
4081: * @param content Optional PI content.
4082: */
4083: void axl_node_add_pi_target (axlNode * node,
4084: char * target,
4085: char * content)
4086: {
4087: axlPI * pi;
4088:
4089: /* perform some environmental checks */
4090: axl_return_if_fail (node);
4091: axl_return_if_fail (target);
4092:
4093: /* create the PI element */
4094: pi = axl_pi_create (target, content);
4095:
4096: /* set the new process instruction found */
4097: axl_item_set_child (node, ITEM_PI, pi);
4098:
4099: return;
4100: }
4101:
4102:
4103: /**
4104: * @brief Allows to check if the provided Processing instruction
4105: * target is defined on the given xml node document (\ref axlNode).
4106: *
4107: * Processing instruction are a way to configure the xml node document
4108: * with processing information to instruct the application level that
4109: * is going to consume the XML information.
4110: *
4111: * @param node The \ref axlNode where the processing instruction will
4112: * be read.
4113: *
4114: * @param pi_target The process instruction name.
4115: *
4116: * @return axl_true is the processing instruction is defined,
4117: * otherwise axl_false is returned.
4118: */
4119: axl_bool axl_node_has_pi_target (axlNode * node,
4120: char * pi_target)
4121: {
4122: axlPI * pi;
4123: axlItem * item;
4124:
4125: axl_return_val_if_fail (node, axl_false);
4126: axl_return_val_if_fail (pi_target, axl_false);
4127:
4128: /* assume the pi target doesn't exist if it is not
4129: * initialized */
4130: item = node->first;
4131: while (item != NULL) {
4132:
4133: /* check the type */
4134: if (axl_item_get_type (item) == ITEM_PI) {
4135: /* get a reference */
4136: pi = item->data;
4137:
4138: /* only check the first ocurrency */
4139: if (axl_cmp (axl_pi_get_name (pi), pi_target))
4140: return axl_true;
4141: } /* end if */
4142:
4143: /* get the next item */
4144: item = item->next;
4145:
4146: } /* end while */
4147:
4148: return axl_false;
4149: }
4150:
4151: /**
4152: * @brief Allows to get current processing instruction content.
4153: *
4154: * @param node The document where the processing instruction is placed.
4155: *
4156: * @param pi_target The processing instruction target to get current
4157: * content.
4158: *
4159: * @return An internal reference to the process instruction target
4160: * content. Value returned mustn't be deallocated
4161: */
4162: char * axl_node_get_pi_target_content (axlNode * node,
4163: char * pi_target)
4164: {
4165: axlPI * pi;
4166: axlItem * item;
4167:
4168: axl_return_val_if_fail (node, NULL);
4169: axl_return_val_if_fail (pi_target, NULL);
4170:
4171: /* assume the pi target doesn't exist if it is not
4172: * initialized */
4173: item = node->first;
4174: while (item != NULL) {
4175:
4176: /* check the type */
4177: if (axl_item_get_type (item) == ITEM_PI) {
4178: /* get a reference */
4179: pi = item->data;
4180:
4181: /* only check the first ocurrency */
4182: if (axl_cmp (axl_pi_get_name (pi), pi_target))
4183: return axl_pi_get_content (pi);
4184: } /* end if */
4185:
4186: /* get the next item */
4187: item = item->next;
4188:
4189: } /* end while */
4190:
4191: return NULL;
4192: }
4193:
4194: /**
4195: * @brief Allows to transfer (move from) all childs (including
4196: * comments, content, PI, nodes, etc) from the old parent to the new
4197: * parent.
4198: *
4199: * This function is particular useful while moving content from nodes.
4200: *
4201: * @param old_parent The old parent node where all childs will be
4202: * removed and placed in the new parent.
4203: *
4204: * @param new_parent The parent node where the content will be
4205: * placed. If the parent node already have childs, the content will be
4206: * appended.
4207: */
4208: void axl_node_transfer_childs (axlNode * old_parent,
4209: axlNode * new_parent)
4210: {
4211: axlItem * item;
4212: axlItem * item_aux;
4213:
4214: /* get the first child for the old parent */
4215: item = old_parent->first;
4216: while (item != NULL) {
4217:
4218: /* get a reference to the next before adding */
4219: item_aux = item->next;
4220:
4221: /* set the item to parent for the new node */
4222: axl_item_set_child_ref (new_parent, item);
4223:
4224:
4225: /* get the next */
4226: item = item_aux;
4227:
4228: } /* end while */
4229:
4230: /* clear reference from previous parent */
4231: old_parent->first = NULL;
4232: old_parent->last = NULL;
4233:
4234: return;
4235: }
4236:
4237: /**
4238: * @internal Implementation for the public API provided to dump node content.
4239: */
4240: axl_bool __axl_node_dump_common (axlNode * node, char ** content, int * size, axl_bool pretty_print, int level, int tabular)
4241: {
4242: int _size;
4243: int index;
4244: char * result;
4245:
4246: /* check refererences received */
4247: axl_return_val_if_fail (node, axl_false);
4248: axl_return_val_if_fail (content, axl_false);
4249:
4250: /* get dump size */
4251: _size = axl_node_get_flat_size (node, pretty_print, level, tabular);
4252:
4253: /* dump the content */
4254: result = axl_new (char, _size + 1);
4255: index = axl_node_dump_at (node, result, 0, pretty_print, level, tabular);
4256:
4257: /* check result */
4258: if (index != _size) {
4259: __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "failed to dump xml node, size dump operation mismatch: %d != %d",
4260: index, _size);
4261: /* free allocated result */
4262: axl_free (result);
4263:
4264: /* nullify content */
4265: if (size)
4266: *size = -1;
4267: *content = NULL;
4268:
4269: return axl_false;
4270: } /* end if */
4271:
4272: /* fill the size */
4273: if (size)
4274: *size = _size;
4275: *content = result;
4276:
4277: /* return content */
4278: return axl_true;
4279: }
4280:
4281: /**
4282: * @brief Allows to dump the xml content taking as starting point the
4283: * xml node provided.
4284: *
4285: * @param node The \ref axlNode used as reference and starting point
4286: * to dump.
4287: *
4288: * @param content The reference where the result will be returned.
4289: *
4290: * @param size The reference where the document content size will be
4291: * returned.
4292: *
4293: * @return The function returns \ref axl_true if the dump operation
4294: * was performed. Otherwise \ref axl_false is returned.
4295: */
4296: axl_bool axl_node_dump (axlNode * node,
4297: char ** content,
4298: int * size)
4299: {
4300: /* use common implementation for all functions */
4301: return __axl_node_dump_common (node, content, size, axl_false, 0, 0);
4302: }
4303:
4304: /**
4305: * @brief Allows to perform a pretty print operation using as
4306: * reference (starting point) the node provided.
4307: *
4308: * @param node The node to be used as reference for the dump operation.
4309: *
4310: * @param content A reference to a user defined pointer where the
4311: * content will be placed. Non optional parameter.
4312: *
4313: * @param size A reference to a user defined pointer where the content
4314: * size will be placed. Optional parameter.
4315: *
4316: * @param tabular How many spaces to be placed on each level.
4317: *
4318: * @return \ref axl_true if the dump operation was properly done, otherwise
4319: * \ref axl_false is returned.
4320: */
4321: axl_bool axl_node_dump_pretty (axlNode * node,
4322: char ** content,
4323: int * size,
4324: int tabular)
4325: {
4326: /* use common implementation for all functions */
4327: return __axl_node_dump_common (node, content, size, axl_true, 0, tabular);
4328: }
4329:
4330: /**
4331: * @brief Allows to dump the xml document using as reference the node
4332: * provided, at the file path provided.
4333: *
4334: * @param node The document node reference to use to build the
4335: * content.
4336: *
4337: * @param file_path File path where place the result.
4338: *
4339: * @return \ref axl_true if the dump operation was done, otherwise \ref axl_false is
4340: * returned.
4341: */
4342: axl_bool axl_node_dump_to_file (axlNode * node,
4343: char * file_path)
4344: {
4345: char * content;
4346: int size;
4347: FILE * fd;
4348: int written;
4349:
4350: /* use common implementation for all functions */
4351: if (! __axl_node_dump_common (node, &content, &size, axl_true, 0, 0))
4352: return axl_false;
4353:
4354: /* open the file and check */
4355: #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
4356: if (fopen_s (&fd, file_path, "w") != 0) {
4357: #else
4358: if ((fd = fopen (file_path, "w")) == NULL) {
4359: #endif
4360: /* failed to open the file to dump the content */
4361: axl_free (content);
4362:
4363: return axl_false;
4364: }
4365:
4366: /* dump the content */
4367: written = fwrite (content, 1, size, fd);
4368:
4369: /* free the content */
4370: axl_free (content);
4371:
4372: /* close file */
4373: fclose (fd);
4374:
4375: /* return if we have failed to dump all the content to the
4376: * file or not. */
4377: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "returning that the dump was: %s (written:%d == size:%d)",
4378: (written == size) ? "OK" : "FAILED",
4379: written, size);
4380:
4381: return (written == size);
4382:
4383: }
4384:
4385: /**
4386: * @brief Allows to pretty print dump the xml document using as
4387: * reference the node provided, at the file path provided.
4388: *
4389: * @param node The document node reference to use to build the
4390: * content.
4391: *
4392: * @param file_path File path where place the result.
4393: *
4394: * @param tabular How many spaces to be placed at each level.
4395: *
4396: * @return \ref axl_true if the dump operation was done, otherwise \ref axl_false is
4397: * returned.
4398: */
4399: axl_bool axl_node_dump_pretty_to_file (axlNode * node,
4400: char * file_path,
4401: int tabular)
4402: {
4403: char * content;
4404: int size;
4405: FILE * fd;
4406: int written;
4407:
4408: /* use common implementation for all functions */
4409: if (! __axl_node_dump_common (node, &content, &size, axl_true, 0, tabular))
4410: return axl_false;
4411:
4412: /* open the file and check */
4413: #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
4414: if (fopen_s (&fd, file_path, "w") != 0) {
4415: #else
4416: if ((fd = fopen (file_path, "w")) == NULL) {
4417: #endif
4418: /* failed to open the file to dump the content */
4419: axl_free (content);
4420:
4421: return axl_false;
4422: }
4423:
4424: /* dump the content */
4425: written = fwrite (content, 1, size, fd);
4426:
4427: /* free the content */
4428: axl_free (content);
4429:
4430: /* close file */
4431: fclose (fd);
4432:
4433: /* return if we have failed to dump all the content to the
4434: * file or not. */
4435: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "returning that the dump was: %s (written:%d == size:%d)",
4436: (written == size) ? "OK" : "FAILED",
4437: written, size);
4438:
4439: return (written == size);
4440: }
4441:
4442: /**
4443: * @brief Allows to get a list which contains \ref axlPI nodes,
4444: * representing all process instruction that the \ref axlNode (xml
4445: * document node) has.
4446: *
4447: * While using PI, you can use the following functions to get PI
4448: * information:
4449: *
4450: * - \ref axl_node_has_pi_target
4451: * - \ref axl_node_get_pi_target_content
4452: *
4453: * However, this function will return first ocurrence for PI found
4454: * inside the xml document. If you don't use repeated PI elements, you
4455: * won't find problems, but, if you need to iterate ever all PI found
4456: * or you are using repeated PI, you can use this function as follows
4457: * to get current pi elements:
4458: *
4459: * \code
4460: * void show_all_pi (axlNode * node)
4461: * {
4462: * int iterator;
4463: * axlPI * pi;
4464: * axlList * PIs;
4465: *
4466: * // get all PI target that the node has
4467: * PIs = axl_node_get_pi_target_list (node);
4468: * iterator = 0;
4469: *
4470: * while (iterator < axl_list_length (PIs)) {
4471: * // get next pi stored
4472: * pi = axl_list_get_nth (PIs, iterator);
4473: *
4474: * // do some stuff
4475: * printf ("PI found target name=%s, content=%s\n",
4476: * axl_pi_get_name (pi),
4477: * axl_pi_get_content (pi));
4478: *
4479: * // update the iterator
4480: * iterator++;
4481: * }
4482: *
4483: * // once finished, free the list
4484: * axl_list_free (PIs);
4485: * return;
4486: * }
4487: * \endcode
4488: *
4489: * @param node The xml node (\ref axlNode) where the process
4490: * instruction will be returned.
4491: *
4492: * @return A reference to the list of processing instruction that the
4493: * xml node (\ref axlNode) has. The returned list, if defined, must be
4494: * deallocated.
4495: */
4496: axlList * axl_node_get_pi_target_list (axlNode * node)
4497: {
4498: axlList * result = NULL;
4499: axlItem * item;
4500:
4501: axl_return_val_if_fail (node, NULL);
4502:
4503: /* assume the pi target doesn't exist if it is not
4504: * initialized */
4505: item = node->first;
4506: while (item != NULL) {
4507:
4508: /* check the type */
4509: if (axl_item_get_type (item) == ITEM_PI) {
4510: /* create the result list */
4511: if (result == NULL)
4512: result = axl_list_new (axl_list_always_return_1, (axlDestroyFunc) axl_pi_free);
4513:
4514: /* add the list */
4515: axl_list_add (result, item->data);
4516:
4517: } /* end if */
4518:
4519: /* get the next item */
4520: item = item->next;
4521:
4522: } /* end while */
4523:
4524: return result;
4525: }
4526:
4527: axl_bool __axl_node_get_flat_size_attributes_foreach (axlPointer attr,
4528: axlPointer value,
4529: axlPointer user_data)
4530: {
4531: int * length = user_data;
4532:
4533: /* " attribute='value' */
4534: (*length) += 4 + strlen ((char*) attr) + strlen ((char*) value);
4535:
4536: /* make the process to continue */
4537: return axl_false;
4538: }
4539:
4540: /**
4541: * @internal
4542: * @brief Returns the space required to write the attribute part.
4543: */
4544: int __axl_node_get_flat_size_attributes (axlNode * node)
4545: {
4546:
4547: int length = 0;
4548: axlNodeAttr * attr = NULL;
4549:
4550: /* if attribute list is not defined just return 0 */
4551: if (node->attributes == NULL)
4552: return 0;
4553:
4554: /* perform a foreach and accumulate */
4555: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "get flat size for node <%s>",
4556: axl_node_get_name (node));
4557: if (node->attr_num <= 10) {
4558: /* get the first reference */
4559: attr = (axlNodeAttr *) node->attributes;
4560: while (attr != NULL) {
4561: /* call to get length */
4562: __axl_node_get_flat_size_attributes_foreach (attr->attribute, attr->value, &length);
4563:
4564: /* get the next */
4565: attr = attr->next;
4566: }
4567:
4568: } else {
4569: /* perform a foreach */
4570: axl_hash_foreach ((axlHash *) node->attributes, __axl_node_get_flat_size_attributes_foreach, &length);
4571: }
4572:
4573: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "after foreach flat size for node <%s> is %d",
4574: axl_node_get_name (node), length);
4575:
4576: /* return the length */
4577: return length;
4578: }
4579:
4580: /**
4581: * @internal
4582: *
4583: * Returns which the size that the node and its childs will hold if
4584: * the are represented into a flat xml stream.
4585: *
4586: * @param node The node that is requested its stream xml size.
4587: *
4588: * @param pretty_print If pretty print is activated.
4589: *
4590: * @param level Which is the relative level of the node respected to
4591: * the root node.
4592: *
4593: * @return The stream size or -1 if fails.
4594: */
4595: int axl_node_get_flat_size (axlNode * node, axl_bool pretty_print, int level, int tabular)
4596: {
4597: int result = 0;
4598: axlItem * item;
4599: axlNodeContent * content;
4600: axl_bool is_empty;
4601: axl_bool have_childs;
4602:
4603: axl_return_val_if_fail (node, -1);
4604:
4605: /* get values */
4606: is_empty = axl_node_is_empty (node);
4607: have_childs = axl_node_have_childs_aux (node);
4608:
4609: if (have_childs || (!have_childs && !is_empty)) {
4610: /* the node is emtpy because it has no content but it has
4611: * childs:
4612: *
4613: * "<" + strlen (node-name) + ">" + ... + "</" + strlen (node-name) + ">" */
4614: result = 5 + (2 * strlen (node->name)) + __axl_node_get_flat_size_attributes (node);
4615:
4616: /* check pretty_print */
4617: if (pretty_print) {
4618: /* two tabulations plus two carry return \r\n
4619: * on windows and \n on unix */
4620: if (have_childs)
4621: result += (level * tabular * 2) + 2;
4622: else
4623: result += (level * tabular) + 1;
4624: #ifdef __AXL_OS_WIN32__
4625: if (have_childs)
4626: result += 2;
4627: else
4628: result ++;
4629: #endif
4630: }
4631: } else {
4632: if (is_empty) {
4633: /* "<" + strlen (node-name) + " />" */
4634: result = strlen (node->name) + 4 + __axl_node_get_flat_size_attributes (node);
4635:
4636: /* check pretty print */
4637: if (pretty_print) {
4638: /* one tabular plus one carry return
4639: * \r\n on windows and \n on unix */
4640: result += (level * tabular) + 1;
4641: #ifdef __AXL_OS_WIN32__
4642: result += 1;
4643: #endif
4644: }
4645:
4646: /* return sum */
4647: return result;
4648: }
4649: }
4650:
4651: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node=<%s> count=%d", node->name, result);
4652:
4653: /* get first child */
4654: item = node->first;
4655: while (item != NULL) {
4656: /* according to the type, check a size */
4657: switch (axl_item_get_type (item)) {
4658: case ITEM_NODE:
4659: /* count how many bytes the node holds */
4660: result += axl_node_get_flat_size (item->data, pretty_print, level + 1, tabular);
4661: break;
4662: case ITEM_CONTENT:
4663: /* content */
4664: content = (axlNodeContent *) item->data;
4665: result += content->content_size;
4666: break;
4667: case ITEM_CDATA:
4668: /* content + '<![CDATA[' + ']]>' */
4669: content = (axlNodeContent *) item->data;
4670: result += content->content_size + 12;
4671: break;
4672: case ITEM_PI:
4673: /* get current size */
4674: result += axl_pi_get_size (item->data);
4675: break;
4676: case ITEM_COMMENT:
4677: /* content + '<!-- ' + ' -->' */
4678: content = (axlNodeContent *) item->data;
4679:
4680: /* check if the content has already defined white spaces */
4681: if (content->content[0] == ' ' && content->content[content->content_size - 1] == ' ')
4682: result += content->content_size + 7;
4683: else if (content->content[0] != ' ' && content->content[content->content_size - 1] == ' ')
4684: result += content->content_size + 8;
4685: else if (content->content[0] == ' ' && content->content[content->content_size - 1] != ' ')
4686: result += content->content_size + 8;
4687: else
4688: result += content->content_size + 9;
4689: if (pretty_print) {
4690: /* tabular indent + \n */
4691: result += ((level + 1) * tabular) + 1;
4692: #ifdef __AXL_OS_WIN32__
4693: /* \r\n */
4694: result += 1;
4695: #endif
4696: }
4697:
4698: break;
4699: case ITEM_REF:
4700: /* item ref + '&' + ';' */
4701: content = (axlNodeContent *) item->data;
4702: result += content->content_size + 2;
4703: break;
4704: case ITEM_FROM_FACTORY:
4705: case ITEM_CONTENT_FROM_FACTORY:
4706: /* never reached */
4707: break;
4708: }
4709: /* get next item */
4710: item = item->next;
4711:
4712: } /* end while */
4713:
4714: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "child processing finished for: parent=<%s>, count=%d", node->name, result);
4715:
4716: /* return the result */
4717: return result;
4718: }
4719:
4720: axl_bool __axl_node_dump_attributes_at_foreach (axlPointer key,
4721: axlPointer value,
4722: axlPointer user_data,
4723: axlPointer user_data2)
4724: {
4725: char * content = user_data;
4726: int * _desp = user_data2;
4727: axl_bool terminator = axl_false;
4728: int desp = (*_desp);
4729: int length;
4730:
4731: memcpy (content + desp, " ", 1);
4732: desp += 1;
4733:
4734: length = strlen ((char*) key);
4735: memcpy (content + desp, (char *) key, length);
4736: desp += length;
4737:
4738: /* check if the content contains a ' so, enclose the attribute
4739: * with " */
4740: if (strstr (value, "'") == NULL) {
4741: memcpy (content + desp, "='", 2);
4742: desp += 2;
4743: }else {
4744: terminator = axl_true;
4745: memcpy (content + desp, "=\"", 2);
4746: desp += 2;
4747: }
4748:
4749: length = strlen ((char*) value);
4750: memcpy (content + desp, (char*) value, length);
4751: desp += length;
4752:
4753: /* dump attribute termination */
4754: if (terminator) {
4755: memcpy (content + desp, "\"", 1);
4756: }else {
4757: memcpy (content + desp, "'", 1);
4758: }
4759: desp += 1;
4760:
4761: /* update desp */
4762: (*_desp) = desp;
4763:
4764: /* make the process to continue */
4765: return axl_false;
4766: }
4767:
4768: void __axl_node_dump_at_the_end (axlNodeAttr * attr, char * content, int * desp)
4769: {
4770: /* return if no attribute must be dumped */
4771: if (attr == NULL)
4772: return;
4773:
4774: /* call to dump next attributes first */
4775: __axl_node_dump_at_the_end (attr->next, content, desp);
4776:
4777: /* now dump our attribute */
4778: __axl_node_dump_attributes_at_foreach (attr->attribute, attr->value, content, desp);
4779:
4780: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping attribute: %s=%s", attr->attribute, attr->value);
4781:
4782: return;
4783: }
4784:
4785: /**
4786: * @internal
4787: *
4788: * Internal support function which dumps current attribute
4789: * configuration into the given memory using the provided desp.
4790: */
4791: int axl_node_dump_attributes_at (axlNode * node, char * content, int desp)
4792: {
4793: axlNodeAttr * attr = NULL;
4794:
4795: /* if attribute list is not defined just return 0 */
4796: if (node->attributes == NULL)
4797: return desp;
4798:
4799: /* according to the attribute num */
4800: if (node->attr_num <= 10) {
4801: /* get the first reference */
4802: attr = (axlNodeAttr *) node->attributes;
4803: __axl_node_dump_at_the_end (attr, content, &desp);
4804:
4805: } else {
4806: /* foreach attribute dump */
4807: axl_hash_foreach2 ((axlHash *) node->attributes, __axl_node_dump_attributes_at_foreach, content, &desp);
4808: }
4809:
4810: /* return the length */
4811: return desp;
4812: }
4813:
4814: /**
4815: * @internal Writes the indentation according to the tabular size and
4816: * the indent level.
4817: *
4818: * @param content The reference to the content where the dump
4819: * operation will be performed.
4820: *
4821: * @param tabular The tabular size to be applied for each level.
4822: *
4823: * @param level The indent level to be applied.
4824: *
4825: * @return The number of bytes written.
4826: */
4827: int __axl_node_dump_at_write_indent (char * content, int tabular, int level)
4828: {
4829: int iterator = 0;
4830:
4831: while (iterator < (tabular * level)) {
4832: /* write tabular info */
4833: memcpy (content + iterator, " ", 1);
4834:
4835: /* update iterator */
4836: iterator++;
4837: } /* end while */
4838:
4839: return iterator;
4840: }
4841:
4842: /* dump content */
4843: int __axl_node_dump_items (axlItem * item, char * content, int level, axl_bool pretty_print, int desp, int tabular)
4844: {
4845:
4846: axlNodeContent * nodeContent;
4847: char * string_aux;
4848:
4849: /* get first child */
4850: while (item != NULL) {
4851: /* according to the type, check a size */
4852: switch (axl_item_get_type (item)) {
4853: case ITEM_NODE:
4854: /* write axl node content */
4855: desp = axl_node_dump_at (item->data, content, desp, pretty_print, level + 1, tabular);
4856: break;
4857: case ITEM_CONTENT:
4858: /* write content information */
4859: nodeContent = (axlNodeContent *)item->data;
4860: memcpy (content + desp, nodeContent->content, nodeContent->content_size);
4861: desp += nodeContent->content_size;
4862: break;
4863: case ITEM_CDATA:
4864: /* write content information */
4865: nodeContent = (axlNodeContent *)item->data;
4866:
4867: /* write cdata content */
4868: memcpy (content + desp, "<![CDATA[", 9);
4869: desp += 9;
4870:
4871: /* write content */
4872: memcpy (content + desp, nodeContent->content, nodeContent->content_size);
4873: desp += nodeContent->content_size;
4874:
4875: /* write cdata end */
4876: memcpy (content + desp, "]]>", 3);
4877: desp += 3;
4878: break;
4879: case ITEM_PI:
4880: /* write pi start */
4881: memcpy (content + desp, "<?", 2);
4882: desp += 2;
4883:
4884: /* write pi name */
4885: string_aux = axl_pi_get_name (item->data);
4886: memcpy (content + desp, string_aux, strlen (string_aux));
4887: desp += strlen (string_aux);
4888:
4889: /* write pi start */
4890: memcpy (content + desp, " ", 1);
4891: desp += 1;
4892:
4893: /* write pi content */
4894: string_aux = axl_pi_get_content (item->data);
4895: memcpy (content + desp, string_aux, strlen (string_aux));
4896: desp += strlen (string_aux);
4897:
4898: /* write pi start */
4899: memcpy (content + desp, "?>", 2);
4900: desp += 2;
4901: break;
4902: case ITEM_COMMENT:
4903:
4904: /* check for pretty print to write indent */
4905: if (pretty_print) {
4906: desp += __axl_node_dump_at_write_indent (content + desp, tabular, level + 1);
4907: }
4908:
4909: /* get a reference to the content */
4910: nodeContent = (axlNodeContent *)item->data;
4911:
4912: /* add an space if the content is found to not
4913: * have one */
4914: if (nodeContent->content [0] == ' ') {
4915: memcpy (content + desp, "<!--", 4);
4916: desp += 4;
4917: } else {
4918: memcpy (content + desp, "<!-- ", 5);
4919: desp += 5;
4920: }
4921:
4922:
4923:
4924: /* write content */
4925: memcpy (content + desp, nodeContent->content, nodeContent->content_size);
4926: desp += nodeContent->content_size;
4927:
4928: /* add an space if the content is found to not
4929: * have one */
4930: if (nodeContent->content [nodeContent->content_size - 1] == ' ') {
4931: memcpy (content + desp, "-->", 3);
4932: desp += 3;
4933: } else {
4934: memcpy (content + desp, " -->", 4);
4935: desp += 4;
4936: } /* end if */
4937:
4938: if (pretty_print) {
4939: #ifdef __AXL_OS_WIN32__
4940: memcpy (content + desp, "\r\n", 2);
4941: desp += 2;
4942: #else
4943: memcpy (content + desp, "\n", 1);
4944: desp += 1;
4945: #endif
4946: }
4947:
4948: break;
4949: case ITEM_REF:
4950: /* content + '&' + ';' */
4951: memcpy (content + desp, "&", 1);
4952: desp += 1;
4953:
4954: /* get a reference to the content */
4955: nodeContent = (axlNodeContent *)item->data;
4956:
4957: /* write content */
4958: memcpy (content + desp, nodeContent->content, nodeContent->content_size);
4959: desp += nodeContent->content_size;
4960:
4961: memcpy (content + desp, ";", 1);
4962: desp += 1;
4963: break;
4964: case ITEM_FROM_FACTORY:
4965: case ITEM_CONTENT_FROM_FACTORY:
4966: /* never reached */
4967: break;
4968: }
4969:
4970: /* get next item */
4971: item = item->next;
4972:
4973: } /* end while */
4974:
4975: /* return desp calculated */
4976: return desp;
4977:
4978: } /* end __axl_node_dump_items */
4979:
4980: /**
4981: * @internal
4982: *
4983: * Writes the node information represented by the node provided at the
4984: * given position into the buffer provided.
4985: *
4986: * @param node The node to dump and its childs.
4987: *
4988: * @param content The memory buffer where the content will be dumped.
4989: *
4990: * @param desp A memory desp where to dump the node content inside the
4991: * memory provided.
4992: *
4993: * @return The new desp value to be used on the next dump.
4994: */
4995: int axl_node_dump_at (axlNode * node,
4996: char * content,
4997: int desp,
4998: axl_bool pretty_print,
4999: int level,
5000: int tabular)
5001: {
5002: axlItem * item;
5003: axl_bool have_childs;
5004:
5005: axl_return_val_if_fail (node, -1);
5006:
5007: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping node=<%s> at %d",
5008: axl_node_get_name (node), desp);
5009:
5010: /* get current have childs status */
5011: have_childs = axl_node_have_childs_aux (node);
5012:
5013: /* check for pretty print and tabular */
5014: if (pretty_print) {
5015: desp += __axl_node_dump_at_write_indent (content + desp, tabular, level);
5016: } /* end if */
5017:
5018: /* check if the node is empty */
5019: if (axl_node_is_empty (node)) {
5020: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node <%s> is empty",
5021: axl_node_get_name (node));
5022:
5023: if (! have_childs) {
5024: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping an empty node without childs=<%s>",
5025: axl_node_get_name (node));
5026:
5027: /* "<" + strlen (node-name) + " />" */
5028: memcpy (content + desp, "<", 1);
5029: desp += 1;
5030:
5031: memcpy (content + desp, node->name, strlen (node->name));
5032: desp += strlen (node->name);
5033:
5034: /* dump attribute values */
5035: desp = axl_node_dump_attributes_at (node, content, desp);
5036:
5037: memcpy (content + desp, " />", 3);
5038: desp += 3;
5039:
5040: /* write traling node information */
5041: if (pretty_print) {
5042: #ifdef __AXL_OS_WIN32__
5043: memcpy (content + desp, "\r\n", 2);
5044: desp += 2;
5045: #else
5046: memcpy (content + desp, "\n", 1);
5047: desp += 1;
5048: #endif
5049: }
5050:
5051: return desp;
5052: }
5053: }
5054:
5055: /* the node is empty because it doesn't have content but it
5056: * has childs
5057: * "<" + strlen (node-name) + ">" + strlen (node-content) +
5058: * "</" + strlen (node-name) + ">" */
5059: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting content for: <%s>", axl_node_get_name (node));
5060:
5061: /* dump node start tag */
5062: memcpy (content + desp, "<", 1);
5063: desp += 1;
5064:
5065: memcpy (content + desp, node->name, strlen (node->name));
5066: desp += strlen (node->name);
5067:
5068: /* dump attribute values */
5069: desp = axl_node_dump_attributes_at (node, content, desp);
5070:
5071: memcpy (content + desp, ">", 1);
5072: desp += 1;
5073:
5074: /* if the node have childs */
5075: if (have_childs) {
5076:
5077: /* write traling node information */
5078: if (pretty_print) {
5079: #ifdef __AXL_OS_WIN32__
5080: memcpy (content + desp, "\r\n", 2);
5081: desp += 2;
5082: #else
5083: memcpy (content + desp, "\n", 1);
5084: desp += 1;
5085: #endif
5086: } /* end if */
5087:
5088: /* dump content */
5089: item = node->first;
5090: desp = __axl_node_dump_items (item, content, level, pretty_print, desp, tabular);
5091:
5092: /* check for pretty print and tabular */
5093: if (pretty_print) {
5094: desp += __axl_node_dump_at_write_indent (content + desp, tabular, level);
5095: } /* end if */
5096:
5097: }else {
5098: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node is not empty and have no childs");
5099:
5100: /* dump content */
5101: item = node->first;
5102: desp = __axl_node_dump_items (item, content, level, pretty_print, desp, tabular);
5103: } /* end if */
5104:
5105: /* dump close tag */
5106: memcpy (content + desp, "</", 2);
5107: desp += 2;
5108:
5109: memcpy (content + desp, node->name, strlen (node->name));
5110: desp += strlen (node->name);
5111:
5112: memcpy (content + desp, ">", 1);
5113: desp += 1;
5114:
5115: /* write traling node information */
5116: if (pretty_print) {
5117: #ifdef __AXL_OS_WIN32__
5118: memcpy (content + desp, "\r\n", 2);
5119: desp += 2;
5120: #else
5121: memcpy (content + desp, "\n", 1);
5122: desp += 1;
5123: #endif
5124: }
5125:
5126: /* return the result */
5127: return desp;
5128: }
5129:
5130: /**
5131: * @internal Function used by axl_node_has_invalid_chars which also
5132: * provides features for CDATA sections.
5133: */
5134: axl_bool axl_node_has_invalid_chars_internal (const char * content,
5135: int content_size,
5136: int * added_size,
5137: axl_bool cdata)
5138: {
5139: int iterator = 0;
5140: axl_bool result = axl_false;
5141: axl_return_val_if_fail (content, axl_false);
5142:
5143: /* reset additional size value */
5144: if (added_size != NULL)
5145: *added_size = 0;
5146:
5147: /* calculate the content size */
5148: if (content_size == -1)
5149: content_size = strlen (content);
5150:
5151: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking valid sequence: content size=%d", content_size);
5152:
5153: /* iterate over all content defined */
5154: while (iterator < content_size) {
5155: /* check for ' */
5156: if (content [iterator] == '\'') {
5157: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='\\'");
5158: result = axl_true;
5159: if (added_size != NULL)
5160: (*added_size) += 5;
5161: }
5162:
5163: /* check for " */
5164: if (content [iterator] == '"') {
5165: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='\"'");
5166: result = axl_true;
5167: if (added_size != NULL)
5168: (*added_size) += 5;
5169: }
5170:
5171: /* check for & */
5172: if (content [iterator] == '&') {
5173: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='&'");
5174: result = axl_true;
5175: if (added_size != NULL)
5176: (*added_size) += 4;
5177: }
5178:
5179: /* check for > */
5180: if (content [iterator] == '>') {
5181: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='>'");
5182: result = axl_true;
5183: if (added_size != NULL)
5184: (*added_size) += 3;
5185: }
5186:
5187: /* check for < */
5188: if (content [iterator] == '<') {
5189: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='<'");
5190: result = axl_true;
5191: if (added_size != NULL)
5192: (*added_size) += 3;
5193: }
5194:
5195: /* check for ]]> */
5196: if (content [iterator] == ']' && content [iterator + 1] == ']' && content [iterator + 2] == '>') {
5197: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence=']]>'");
5198: result = axl_true;
5199: if (cdata) {
5200: /* inside CDATA section that is, we
5201: * have to escape this value and
5202: * reopen a new CDATA section to match
5203: * with the last terminator */
5204: if (added_size != NULL)
5205: (*added_size) += 15;
5206: } else {
5207: if (added_size != NULL)
5208: (*added_size) += 3;
5209: }
5210: iterator += 3;
5211: continue;
5212: } /* end if */
5213:
5214: /* update the iterator */
5215: iterator++;
5216: }
5217:
5218: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "valid sequence checking result=%d: content size=%d, additional size=%d resul=%s",
5219: result, content_size, (added_size != NULL) ? *added_size : 0, result ? "HAS INVALID SEQUENCES" : "HAS NO INVALID SEQUENCES");
5220:
5221: /* return results */
5222: return result;
5223: }
5224:
5225: /**
5226: * @brief Allows to check if the provided string have invalid chars
5227: * that must be escaped by using the entity reference rather the value
5228: * itself.
5229: *
5230: * This function is useful in the sense it allows to know if a
5231: * particular content will contain elements not allowed by the XML 1.0
5232: * definition to be placed directly (like &, <, ;, ' and ").
5233: *
5234: *
5235: * This function use usually complemented with \ref axl_node_content_copy_and_escape.
5236: *
5237: * @param content The content to check.
5238: *
5239: * @param content_size The size of the content to be checked. If -1 is
5240: * provided, the function will calculate the content length.
5241: *
5242: * @param added_size An integer reference where the additional size
5243: * variable will be added. This additional size will be the space
5244: * required to replace non-valid characters with entity
5245: * references. This parameter is optional, so passing a NULL value is
5246: * allowed.
5247: *
5248: * @return \ref axl_true if the string contains non valid chars
5249: * that must be escaped using entity references.
5250: */
5251: axl_bool axl_node_has_invalid_chars (const char * content,
5252: int content_size,
5253: int * added_size)
5254: {
5255: /* call to internal implementation supposing this is for a
5256: * node without CDATA section */
5257: return axl_node_has_invalid_chars_internal (content, content_size, added_size, axl_false);
5258: }
5259:
5260: /**
5261: * @brief Allows to check if the provided string have escape sequences
5262: * that must be defined by using the entity reference rather the value
5263: * itself, taking into consideration the content will be used for a
5264: * <![CDATA[..]]> section.
5265: *
5266: * This function is useful in the sense it allows to know if a
5267: * particular content will contain elements not allowed by the XML 1.0
5268: * definition to be placed directly (like &, <, ;, ' and ").
5269: *
5270: * This function use usually complemented with \ref axl_node_content_copy_and_escape_cdata.
5271: *
5272: * @param content The content to check.
5273: *
5274: * @param content_size The size of the content to be checked. If -1 is
5275: * provided, the function will calculate the content length.
5276: *
5277: * @param added_size An integer reference where the additional size
5278: * variable will be added. This additional size will be the space
5279: * required to replace non-valid characters with entity
5280: * references. This parameter is optional, so passing a NULL value is
5281: * allowed.
5282: *
5283: * @return axl_true if the string contains non valid sequences that
5284: * must be escaped using entity references.
5285: */
5286: axl_bool axl_node_has_invalid_chars_cdata (const char * content,
5287: int content_size,
5288: int * added_size)
5289: {
5290: /* call to internal implementation supposing this is for a
5291: * node with CDATA section */
5292: return axl_node_has_invalid_chars_internal (content, content_size, added_size, axl_true);
5293: }
5294:
5295: /**
5296: * @brief Allows to perform a copy from the content provided, doing an
5297: * xml character escaping for non allowed values (&, <, >, ' and ").
5298: *
5299: * This function must be used with \ref axl_node_has_invalid_chars to
5300: * check if the content has escapable chars an to get the additional
5301: * content that must be allocated by this function.
5302: *
5303: * Here is an example:
5304: * \code
5305: * char * content = "Some content with invalid chars & < >";
5306: * int additional_size;
5307: * char * new_content
5308: *
5309: * if (axl_node_has_invalid_chars (content, strlen (content), &additional_size)) {
5310: * // found that the string has invalid chars, escape them
5311: * new_content = axl_node_content_copy_and_escape (content, strlen (content), additional_size);
5312: * }
5313: *
5314: * \endcode
5315: *
5316: * @param content The content to be escaped. If this parameter is
5317: * NULL, the function returns NULL.
5318: *
5319: * @param content_size The content size for the first parameter.
5320: *
5321: * @param additional_size The additional size calculated from \ref axl_node_has_invalid_chars.
5322: *
5323: * @return A newly allocated string with all characters escaped. Use
5324: * \ref axl_free to dealloc the result.
5325: */
5326: char * axl_node_content_copy_and_escape (const char * content,
5327: int content_size,
5328: int additional_size)
5329: {
5330: axl_return_val_if_fail (content, NULL);
5331:
5332: /* call to the internal implementation */
5333: return __axl_node_content_copy_and_escape (content, content_size, additional_size, axl_false);
5334: }
5335:
5336: /**
5337: * @brief Allows to perform a copy for the content provided, doing an
5338: * xml character escaping for non allowed values (&, <, >, ' and ")
5339: * taking into consideration the content will be placed inside a
5340: * <![CDATA[..]]> declaration.
5341: *
5342: * This function must be used with \ref axl_node_has_invalid_chars_cdata to
5343: * check if the content has escapable chars an to get the additional
5344: * content that must be allocated by this function.
5345: *
5346: * Here is an example:
5347: * \code
5348: * char * content = "Some content with invalid chars & < >";
5349: * int additional_size;
5350: * char * new_content
5351: *
5352: * if (axl_node_has_invalid_chars_cdata (content, strlen (content), &additional_size)) {
5353: * // found that the string has invalid chars, escape them
5354: * new_content = axl_node_content_copy_and_escape_cdata (content, strlen (content), additional_size);
5355: * }
5356: * \endcode
5357: *
5358: * @param content The content to be escaped. If this parameter is
5359: * null, the function returns NULL.
5360: *
5361: * @param content_size The content size for the first parameter.
5362: *
5363: * @param additional_size The additional size calculated from \ref axl_node_has_invalid_chars_cdata.
5364: *
5365: * @return A newly allocated string with all characters escaped. Use
5366: * \ref axl_free to dealloc the result.
5367: */
5368: char * axl_node_content_copy_and_escape_cdata (const char * content,
5369: int content_size,
5370: int additional_size)
5371: {
5372: axl_return_val_if_fail (content, NULL);
5373:
5374: /* call to the internal implementation */
5375: return __axl_node_content_copy_and_escape (content, content_size, additional_size, axl_true);
5376: }
5377:
5378: void __axl_node_free_internal (axlNode * node, axl_bool also_childs)
5379: {
5380: axlItem * item;
5381: axlItem * itemAux;
5382:
5383: axl_return_if_fail (node);
5384:
5385: /* free current node */
5386: if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
5387: axl_free (node->name);
5388:
5389: /* release memory hold by attributes */
5390: if (node->attributes != NULL) {
5391: if (node->attr_num <= 10)
5392: __axl_node_free_attr_list ((axlNodeAttr *) node->attributes);
5393: else
5394: axl_hash_free ((axlHash *) node->attributes);
5395: }
5396:
5397: /* release memory hold by childs */
5398: if (node->first != NULL && also_childs) {
5399: /* get the first item */
5400: item = node->first;
5401:
5402: /* foreach item stored */
5403: while (item != NULL) {
5404:
5405: /* get the next item */
5406: itemAux = item->next;
5407:
5408: /* free the item */
5409: axl_item_free (item, axl_true);
5410:
5411: /* update reference */
5412: item = itemAux;
5413:
5414: } /* end while */
5415:
5416: } /* end if */
5417:
5418: /* free the item itself */
5419: if (node->holder != NULL) {
5420: if ((node->holder->type & ITEM_FROM_FACTORY) == 0) {
5421: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG,
5422: "item holder found to be not from a factory, dealloc reference=0x%x, node=0x%x, type=%d",
5423: node->holder, node, node->holder->type);
5424: axl_free (node->holder);
5425: node->holder = NULL;
5426: }
5427: }
5428:
5429: /* do not free the node itself */
5430: return;
5431: }
5432:
5433: /**
5434: * @brief Destroy the given node provided by the reference.
5435: *
5436: * The function will check for nodes that are NULL references,
5437: * returning immediately.
5438: *
5439: * @param node The node to destroy.
5440: */
5441: void axl_node_free (axlNode * node)
5442: {
5443: axlHash * hash;
5444: axl_return_if_fail (node);
5445:
5446: /* get a reference to the hash */
5447: hash = node->annotate_data;
5448:
5449: /* free internal content */
5450: __axl_node_free_internal (node, axl_true);
5451:
5452: /* free attributes */
5453: if (! (node->conf & NODE_FROM_FACTORY))
5454: axl_free (node);
5455:
5456: /* annotate data deallocation must be done here because it is
5457: * used by the application user and the library to store
5458: * reference that could be pointing to internal structures
5459: * deallocated by the __axl_node_free_internal */
5460: axl_hash_free (hash);
5461:
5462: /* the node to release */
5463: return;
5464: }
5465:
5466: /**
5467: * @brief Allows to remove the provided node, optionally without
5468: * removing childs inside it.
5469: *
5470: * @param node The node to deallocate.
5471: *
5472: * @param also_childs Signal the function to also dealloc childs or
5473: * not.
5474: */
5475: void axl_node_free_full (axlNode * node, axl_bool also_childs)
5476: {
5477: axlHash * hash;
5478: axl_return_if_fail (node);
5479:
5480: /* get a reference to the hash */
5481: hash = node->annotate_data;
5482:
5483: /* free node */
5484: __axl_node_free_internal (node, axl_false);
5485:
5486: /* free the node itself */
5487: if (!(node->conf & NODE_FROM_FACTORY))
5488: axl_free (node);
5489:
5490: /* annotate data deallocation must be done here because it is
5491: * used by the application user and the library to store
5492: * reference that could be pointing to internal structures
5493: * deallocated by the __axl_node_free_internal */
5494: axl_hash_free (hash);
5495:
5496: return;
5497: }
5498:
5499: /**
5500: * @}
5501: */
5502:
5503: /**
5504: * \defgroup axl_node_attribute_cursor Axl Node Attribute iteration: An interface provided to iterate attribute nodes without knowing them.
5505: */
5506:
5507: /**
5508: * \addtogroup axl_node_attribute_cursor
5509: * @{
5510: */
5511:
5512:
5513: /**
5514: * @brief Allows to get a cursor to iterate attributes found in the
5515: * provided node in a linear and efficient way.
5516: *
5517: * The \ref axlAttrCursor could be used to iterate attributes
5518: * inside a particular node in an efficient way because it stores
5519: * current state (position), hiding all module details, providing
5520: * access to attributes without knowing them. Then using the following
5521: * functions you can modify the state (current position to get):
5522: *
5523: * - \ref axl_node_attr_cursor_first
5524: * - \ref axl_node_attr_cursor_next
5525: *
5526: * Finally, the following functions are provided to get the key and
5527: * the value data associated to the current selected attribute,
5528: * pointed by the current status of the cursor:
5529: *
5530: * - \ref axl_node_attr_cursor_get_key (returns the key of the current attribute selected)
5531: * - \ref axl_node_attr_cursor_get_value (returns the value of the current attribute selected)
5532: *
5533: * Here is an example:
5534: * \code
5535: * axlPointer key;
5536: * axlPointer value;
5537: * axlAttrCursor * cursor;
5538: *
5539: * // create the cursor
5540: * cursor = axl_node_attr_cursor_new (node);
5541: *
5542: * // while there are more elements
5543: * while (axl_node_attr_cursor_has_item (cursor)) {
5544: *
5545: * // get the value and key
5546: * key = axl_node_attr_cursor_get_key (cursor);
5547: * value = axl_node_attr_cursor_get_value (cursor);
5548: *
5549: * // get the next
5550: * axl_node_attr_cursor_next (cursor);
5551: *
5552: * }
5553: *
5554: * // free the cursor
5555: * axl_node_attr_cursor_free (cursor);
5556: * \endcode
5557: *
5558: * Once created the \ref axlAttrCursor you must release it and create
5559: * a new one if you modify your \ref axlNode attribute configuration
5560: * adding more items.
5561: *
5562: * @param node The node that is requested to create the \ref
5563: * axlAttrCursor reference to iterate all attributes inside.
5564: *
5565: * @return A newly created \ref axlAttrCursor used to iterate
5566: * attributes inside the node provided. Once finished you must call to
5567: * \ref axl_node_attr_cursor_free.
5568: */
5569: axlAttrCursor * axl_node_attr_cursor_new (axlNode * node)
5570: {
5571: axlAttrCursor * cursor;
5572:
5573: axl_return_val_if_fail (node, NULL);
5574:
5575: /* create and configure basics */
5576: cursor = axl_new (axlAttrCursor, 1);
5577: cursor->node = node;
5578: cursor->count = node->attr_num;
5579:
5580: /* according to the number of attributes configure the hash or
5581: * the linked attribte list */
5582: if (cursor->count <= 10) {
5583: /* just point to the first attribute (managed as AxlNodeAttr) */
5584: cursor->data = node->attributes;
5585: } else {
5586: /* create an axl hash cursor */
5587: cursor->data = axl_hash_cursor_new ((axlHash *) node->attributes);
5588: } /* end if */
5589:
5590: /* return created cursor */
5591: return cursor;
5592: }
5593:
5594: /**
5595: * @brief Allows to configure the provided cursor to point to the
5596: * first attribute found inside the node.
5597: *
5598: * @param cursor The cursor that is going to be configured.
5599: */
5600: void axl_node_attr_cursor_first (axlAttrCursor * cursor)
5601: {
5602: axl_return_if_fail (cursor);
5603:
5604: /* check attribute configuration */
5605: if (cursor->count != cursor->node->attr_num) {
5606: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5607: return;
5608: } /* end if */
5609:
5610: if (cursor->count <= 10) {
5611: /* just point to the first attribute (managed as AxlAttribute) */
5612: cursor->data = cursor->node->attributes;
5613: } else {
5614: /* make hash cursor to point to the first */
5615: axl_hash_cursor_first (cursor->data);
5616: } /* end if */
5617:
5618: return;
5619: }
5620:
5621: /**
5622: * @brief Configures the provided attribute cursor to point to the
5623: * next attribute.
5624: *
5625: * @param cursor The attribute cursor to be configured.
5626: */
5627: void axl_node_attr_cursor_next (axlAttrCursor * cursor)
5628: {
5629: axl_return_if_fail (cursor);
5630:
5631: /* check attribute configuration */
5632: if (cursor->count != cursor->node->attr_num) {
5633: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5634: return;
5635: } /* end if */
5636:
5637: if (cursor->count <= 10) {
5638: /* check null values */
5639: if (cursor->data == NULL)
5640: return;
5641:
5642: /* just point to the first attribute (managed as AxlAttribute) */
5643: cursor->data = ((axlNodeAttr *) cursor->data)->next;
5644:
5645: return;
5646: } /* end if */
5647:
5648: /* make hash cursor to point to the first */
5649: axl_hash_cursor_next (cursor->data);
5650:
5651:
5652: return;
5653: }
5654:
5655: /**
5656: * @brief Allows to check if the is a next attribute, following
5657: * current attribute selected.
5658: *
5659: * @param cursor The cursor to be configured.
5660: *
5661: * @return \ref axl_true if it has next element, otherwise \ref axl_false.
5662: */
5663: axl_bool axl_node_attr_cursor_has_next (axlAttrCursor * cursor)
5664: {
5665: axl_return_val_if_fail (cursor, axl_false);
5666:
5667: if (cursor->count != cursor->node->attr_num) {
5668: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5669: return axl_false;
5670: } /* end if */
5671:
5672: if (cursor->count <= 10) {
5673: /* just point to the first attribute (managed as AxlAttribute) */
5674: return (((axlNodeAttr *) cursor->data)->next) != NULL;
5675: } /* end if */
5676:
5677: /* make hash cursor to point to the first */
5678: return axl_hash_cursor_has_next (cursor->data);
5679: }
5680:
5681: /**
5682: * @brief Allows to check if the current position selected has an
5683: * attribute reference.
5684: *
5685: * @param cursor The cursor that is being queried.
5686: *
5687: * @return \ref axl_true if it has item element, otherwise \ref axl_false.
5688: */
5689: axl_bool axl_node_attr_cursor_has_item (axlAttrCursor * cursor)
5690: {
5691: axl_return_val_if_fail (cursor, axl_false);
5692:
5693: /* check attribute configuration */
5694: if (cursor->count != cursor->node->attr_num) {
5695: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5696: return axl_false;
5697: } /* end if */
5698:
5699: if (cursor->count <= 10) {
5700: /* just point to the first attribute (managed as AxlAttribute) */
5701: return cursor->data != NULL;
5702: } /* end if */
5703:
5704: /* make hash cursor to point to the first */
5705: return axl_hash_cursor_has_item (cursor->data);
5706: }
5707:
5708: /**
5709: * @brief Allows to get the attribute key associated to the current
5710: * attribute selected by the cursor.
5711: *
5712: * @param cursor The cursor that is being queried.
5713: *
5714: * @return A reference to the attribute key or NULL if it fails.
5715: */
5716: const char * axl_node_attr_cursor_get_key (axlAttrCursor * cursor)
5717: {
5718: axl_return_val_if_fail (cursor, NULL);
5719:
5720: /* check attribute configuration */
5721: if (cursor->count != cursor->node->attr_num) {
5722: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5723: return NULL;
5724: } /* end if */
5725:
5726: if (cursor->count <= 10) {
5727: /* just point to the first attribute (managed as AxlAttribute) */
5728: return ((axlNodeAttr *) cursor->data)->attribute;
5729: } /* end if */
5730:
5731: /* make hash cursor to point to the first */
5732: return axl_hash_cursor_get_key (cursor->data);
5733: }
5734:
5735: /**
5736: * @brief Allows to get the attribute value associated to the
5737: * attribute selected by the cursor.
5738: *
5739: * @param cursor The cursor that is being queried.
5740: *
5741: * @return A reference to the attribute value or NULL if it fails.
5742: */
5743: const char * axl_node_attr_cursor_get_value (axlAttrCursor * cursor)
5744: {
5745: axl_return_val_if_fail (cursor, NULL);
5746:
5747: /* check attribute configuration */
5748: if (cursor->count != cursor->node->attr_num) {
5749: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
5750: return NULL;
5751: } /* end if */
5752:
5753: if (cursor->count <= 10) {
5754: /* just point to the first attribute (managed as AxlAttribute) */
5755: return ((axlNodeAttr *) cursor->data)->value;
5756: } /* end if */
5757:
5758: /* make hash cursor to point to the first */
5759: return axl_hash_cursor_get_value (cursor->data);
5760: }
5761:
5762: /**
5763: * @brief Allows to release \ref axlAttrCursor.
5764: *
5765: * @param cursor The cursor to release.
5766: */
5767: void axl_node_attr_cursor_free (axlAttrCursor * cursor)
5768: {
5769: axl_return_if_fail (cursor);
5770:
5771: /* free hash cursor */
5772: if (cursor->count > 10)
5773: axl_hash_cursor_free (cursor->data);
5774:
5775: /* free the cursor */
5776: axl_free (cursor);
5777:
5778: return;
5779: }
5780:
5781:
5782: /**
5783: * @internal Function that helps axl_node_attr_foreach to iterate all
5784: * attributes.
5785: */
5786: axl_bool __axl_node_attr_foreach_aux (axlPointer key, axlPointer data, axlPointer user_data, axlPointer user_data2, axlPointer user_data3)
5787: {
5788: return ((axlNodeAttrForeachFunc) user_data) (key, data, user_data2, user_data3);
5789: }
5790:
5791: /**
5792: * @brief Allows to provide a function which is called for each
5793: * attribute installed on the provided node.
5794: *
5795: * This function will allow you to operate on every attribute
5796: * installed, doing an foreach operation. This is an alternative API
5797: * to the \ref axlAttrCursor, which could be used to save allocations.
5798: *
5799: * @param node The node for which the provided function will be called
5800: * for each attribute found.
5801: *
5802: * @param func The foreach function to be called.
5803: *
5804: * @param data User defined data to be passed to the foreach function.
5805: *
5806: * @param data2 Second user defined data to be passed to the foreach
5807: * function.
5808: */
5809: void axl_node_attr_foreach (axlNode * node,
5810: axlNodeAttrForeachFunc func,
5811: axlPointer data,
5812: axlPointer data2)
5813: {
5814: axlNodeAttr * attr;
5815: axl_return_if_fail (node);
5816: axl_return_if_fail (func);
5817:
5818: /* if no attributes no foreach operation */
5819: if (node->attributes == NULL)
5820: return;
5821:
5822: /* store the attribute using the general case */
5823: if (node->attr_num < 11) {
5824: /* handled as a simple list */
5825: attr = (axlNodeAttr *) node->attributes;
5826: while (attr != NULL) {
5827: /* call to notify each attribute */
5828: if (func (attr->attribute, attr->value, data, data2))
5829: return;
5830:
5831: /* get the next */
5832: attr = attr->next;
5833: } /* end while */
5834: } else {
5835: /* handled as a hash */
5836: axl_hash_foreach3 ((axlHash *) node->attributes, __axl_node_attr_foreach_aux, func, data, data2);
5837: } /* end if */
5838:
5839: return;
5840: }
5841:
5842: /**
5843: * @}
5844: */
5845:
5846: /**
5847: * \defgroup axl_item_module Axl Item: A basic item abstraction that represents a child node that could be another node, content, xml comment, etc.
5848: */
5849:
5850: /**
5851: * \addtogroup axl_item_module
5852: * @{
5853: */
5854:
5855: /**
5856: * @brief Allows to create an \ref axlItem, with the provided type and
5857: * holding the provided data.
5858: *
5859: * The function won't configure the parent node holding the
5860: * item. There is an alternative API that allows to create an \ref
5861: * axlItem without performing a copy: \ref axl_item_new_ref.
5862: *
5863: * @param type The type that will represent the \ref axlItem created.
5864: *
5865: * @param data Data associated to the axlItem. In the case the \ref
5866: * axlItem being created will represent content (\ref ITEM_CONTENT),
5867: * an entity ref (\ref ITEM_REF), a comment (\ref ITEM_COMMENT) or
5868: * cdata (\ref ITEM_CDATA), the function will create a local copy. In
5869: * the case of a \ref ITEM_NODE, the function will copy the entire
5870: * node, and all its childs.
5871: *
5872: * @return A newly allocated \ref axlItem with no parent and holding
5873: * the data provided.
5874: */
5875: axlItem * axl_item_new (AxlItemType type,
5876: axlPointer data)
5877: {
5878: axlItem * item = NULL;
5879: axlNode * node;
5880: axlNodeContent * content;
5881:
5882: /* allocate an item type */
5883: item = axl_new (axlItem, 1);
5884: item->type = type;
5885:
5886: switch (axl_item_get_type (item)) {
5887: case ITEM_NODE:
5888: /* item the node */
5889: node = axl_node_copy (item->data, axl_true, axl_true);
5890: node->holder = item;
5891: item->data = node;
5892: break;
5893: case ITEM_CONTENT:
5894: case ITEM_CDATA:
5895: case ITEM_COMMENT:
5896: /* item content */
5897: content = axl_new (axlNodeContent, 1);
5898: content->content = axl_strdup ((const char *) data);
5899: content->content_size = strlen ((const char *) data);
5900:
5901: /* item content */
5902: item->data = content;
5903: break;
5904: case ITEM_PI:
5905: /* item pi */
5906: item->data = axl_pi_copy (data);
5907: break;
5908: case ITEM_REF:
5909: /* not implemented yet */
5910: break;
5911: case ITEM_FROM_FACTORY:
5912: case ITEM_CONTENT_FROM_FACTORY:
5913: /* never reached */
5914: break;
5915: } /* end switch */
5916:
5917: /* return item created */
5918: return item;
5919: }
5920:
5921: /**
5922: * @brief Allows to create an \ref axlItem, with the provided type and
5923: * holding the provided data.
5924: *
5925: * The function won't configure the parent node holding the item.
5926: *
5927: * @param type The type that will represent the \ref axlItem created.
5928: *
5929: * @param data Data associated to the axlItem. This function won't
5930: * perform any copy for the data received. The user calling to this
5931: * API must check that the data is only owned by the \ref axlItem
5932: * created (that is, used by this function).
5933: *
5934: * @return A newly allocated \ref axlItem with no parent and holding
5935: * the data provided.
5936: */
5937: axlItem * axl_item_new_ref (AxlItemType type,
5938: axlPointer data)
5939: {
5940: axlItem * item = NULL;
5941: axlNode * node;
5942: axlNodeContent * content;
5943:
5944: /* allocate an item type */
5945: item = axl_new (axlItem, 1);
5946: item->type = type;
5947:
5948: switch (axl_item_get_type (item)) {
5949: case ITEM_NODE:
5950: /* item the node */
5951: node = data;
5952: node->holder = item;
5953: item->data = node;
5954: break;
5955: case ITEM_CONTENT:
5956: case ITEM_CDATA:
5957: case ITEM_COMMENT:
5958: /* item content */
5959: content = axl_new (axlNodeContent, 1);
5960: content->content = data;
5961: content->content_size = strlen ((const char *) data);
5962:
5963: /* item content */
5964: item->data = content;
5965: break;
5966: case ITEM_PI:
5967: /* item pi */
5968: item->data = data;
5969: break;
5970: case ITEM_REF:
5971: /* not implemented yet */
5972: break;
5973: case ITEM_FROM_FACTORY:
5974: case ITEM_CONTENT_FROM_FACTORY:
5975: /* never reached */
5976: break;
5977: } /* end switch */
5978:
5979: /* return item created */
5980: return item;
5981: }
5982:
5983:
5984: /**
5985: * @brief Allows to get the reference to the document that is holding
5986: * the provided item without taking into consideration the item type.
5987: *
5988: * @param item The item that is required to return its document.
5989: *
5990: * @return A reference to the \ref axlDoc that is holding the item.
5991: */
5992: axlDoc * axl_item_get_doc (axlItem * item)
5993: {
5994: /* do not report an error since it is usual to have a node
5995: * without an item hold configured: for example after
5996: * axl_node_create */
5997: if (item == NULL)
5998: return NULL;
5999:
6000: /* return the document reference */
6001: return item->doc;
6002: }
6003:
6004: /**
6005: * @internal Internal function that allows to configure the document
6006: * that is holding the item provided.
6007: *
6008: * @param item The axlItem to be configured.
6009: * @param doc The axlDoc reference to configure.
6010: */
6011: void axl_item_set_doc (axlItem * item, axlDoc * doc)
6012: {
6013: axl_return_if_fail (item);
6014:
6015: /* configure document */
6016: item->doc = doc;
6017:
6018: return;
6019: }
6020:
6021: /**
6022: * @brief Allows to get the parent that is containing the \ref axlItem
6023: * provider. The parent of a \ref axlItem is always a node.
6024: *
6025: * @param item The \ref axlItem reference that is required to return
6026: * its parent.
6027: *
6028: * @return A reference to the \ref axlNode.
6029: */
6030: axlNode * axl_item_get_parent (axlItem * item)
6031: {
6032: /* return that we don't have parent */
6033: if (item == NULL)
6034: return NULL;
6035:
6036: /* return the parent */
6037: return item->parent;
6038: }
6039:
6040: /**
6041: * @brief Allows to get the following element that is next to the item
6042: * reference provided (\ref axlItem), and at the same level.
6043: *
6044: * @param item The item that is required to return its next reference.
6045: *
6046: * @return A reference to the next element or NULL if it fails or no
6047: * element is found next to the element provided.
6048: */
6049: axlItem * axl_item_get_next (axlItem * item)
6050: {
6051: axl_return_val_if_fail (item, NULL);
6052:
6053: /* return the next element */
6054: return item->next;
6055: }
6056:
6057: /**
6058: * @brief Returns the following \ref axlItem to the \ref axlNode
6059: * reference, in the same level.
6060: *
6061: * @param node The node that is required to return the following item
6062: * to it.
6063: *
6064: * @return An reference to the following or NULL.
6065: */
6066: axlItem * axl_item_node_next (axlNode * node)
6067: {
6068: axl_return_val_if_fail (node, NULL);
6069:
6070: if (node->holder != NULL) {
6071: /* return the next */
6072: return node->holder->next;
6073: }
6074:
6075: /* no holder, no next */
6076: return NULL;
6077:
6078: }
6079:
6080: /**
6081: * @brief Allows to get the following element that is previous to the
6082: * item reference provided (\ref axlItem), and at the same level.
6083: *
6084: * @param item The item that is required to return its previous
6085: * reference.
6086: *
6087: * @return A reference to the previous element or NULL if it fails or
6088: * no element is found previous to the element provided.
6089: */
6090: axlItem * axl_item_get_previous (axlItem * item)
6091: {
6092: axl_return_val_if_fail (item, NULL);
6093:
6094: /* return the previous element */
6095: return item->previous;
6096: }
6097:
6098: /**
6099: * @brief Returns the previous \ref axlItem to the \ref axlNode
6100: * reference, in the same level.
6101: *
6102: * @param node The node that is required to return the previous item
6103: * to it.
6104: *
6105: * @return An reference to the previous or NULL.
6106: */
6107: axlItem * axl_item_node_previous (axlNode * node)
6108: {
6109: axl_return_val_if_fail (node, NULL);
6110:
6111: if (node->holder != NULL) {
6112: /* return the previousx */
6113: return node->holder->previous;
6114: }
6115:
6116: /* no holder, no previous */
6117: return NULL;
6118: }
6119:
6120: /**
6121: * @brief Allows to get the \ref axlItem reference that is holding the
6122: * node provided.
6123: *
6124: * @param node The node that is required to return its holding item.
6125: *
6126: * @return The item reference or NULL if it fails or it isn't set.
6127: */
6128: axlItem * axl_item_node_holder (axlNode * node)
6129: {
6130: axl_return_val_if_fail (node, NULL);
6131:
6132: /* return the holder */
6133: return node->holder;
6134: }
6135:
6136: /**
6137: * @brief Allows to get the very first child item stored on the
6138: * provided \ref axlNode.
6139: *
6140: * This function is similar to \ref axl_node_get_first_child, but
6141: * returning the first \ref axlItem no matter its type.
6142: *
6143: * This function is mainly used inside the MIXED API where nodes are
6144: * expected to enclose content mixed with another xml nodes. See \ref
6145: * axl_node_get_first_child for more details.
6146: *
6147: * @param node The \ref axlNode reference that is required to return
6148: * is first child reference (\ref axlItem).
6149: *
6150: * @return The \ref axlItem reference or NULL if the axlNode is empty
6151: * (\ref axl_node_is_empty) and have no childs (\ref
6152: * axl_node_have_childs). The function also returns NULL if it fails
6153: * (when it receives a NULL reference).
6154: */
6155: axlItem * axl_item_get_first_child (axlNode * node)
6156: {
6157: /* check reference received */
6158: axl_return_val_if_fail (node, NULL);
6159:
6160: /* return the first item reference */
6161: return node->first;
6162: }
6163:
6164: /**
6165: * @brief Allows to get the very last child item stored on the
6166: * provided \ref axlNode.
6167: *
6168: * This function is similar to \ref axl_node_get_last_child, but
6169: * returning the last \ref axlItem no matter its type.
6170: *
6171: * This function is mainly used inside the MIXED API where nodes are
6172: * expected to enclose content mixed with another xml nodes. See \ref
6173: * axl_node_get_last_child for more details.
6174: *
6175: * @param node The \ref axlNode reference that is required to return
6176: * is last child reference (\ref axlItem).
6177: *
6178: * @return The \ref axlItem reference or NULL if the axlNode is empty
6179: * (\ref axl_node_is_empty) and have no childs (\ref
6180: * axl_node_have_childs). The function also returns NULL if it fails
6181: * (when it receives a NULL reference).
6182: */
6183: axlItem * axl_item_get_last_child (axlNode * node)
6184: {
6185: /* check reference received */
6186: axl_return_val_if_fail (node, NULL);
6187:
6188: /* return the last item reference */
6189: return node->last;
6190: }
6191:
6192: /**
6193: * @brief Allows to get the item type that represents the reference
6194: * received (\ref axlItem).
6195: *
6196: * Every \ref axlItem represents a particular content that could be
6197: * found inside an xml document parsed by the library (\ref
6198: * axlDoc). This function allows to return the type associated to the
6199: * element encapsulated by the \ref axlItem. See \ref AxlItemType for
6200: * more details.
6201: *
6202: * @param item The reference that is required to return its type.
6203: *
6204: * @return The type that is inside the reference or -1 if it fails.
6205: */
6206: AxlItemType axl_item_get_type (axlItem * item)
6207: {
6208: /* return stored type */
6209: return item->type & (~ (ITEM_FROM_FACTORY | ITEM_CONTENT_FROM_FACTORY));
6210: }
6211:
6212: /**
6213: * @brief Returns the item data that is stored inside the \ref axlItem
6214: * received.
6215: *
6216: * According to the type that is representing the \ref axlItem
6217: * received, it will return a particular type. Check \ref AxlItemType
6218: * for more information.
6219: *
6220: * @param item The item that is required to return the data
6221: * encapsulated on it.
6222: *
6223: * @return A pointer to the data stored, or NULL if it fails. The
6224: * pointer returned, in the case it is defined, mustn't be
6225: * released. It is a internal reference to the content.
6226: */
6227: axlPointer axl_item_get_data (axlItem * item)
6228: {
6229: axl_return_val_if_fail (item, NULL);
6230:
6231: /* return stored type */
6232: return item->data;
6233: }
6234:
6235: /**
6236: * @brief Convenience API that allows to get the content stored (and
6237: * its size) from the received \ref axlItem, supposing it is storing
6238: * an \ref ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref ITEM_REF.
6239: *
6240: * @param item The \ref axlItem that is supposed to store an item with
6241: * type: \ref ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref
6242: * ITEM_REF.
6243: *
6244: * @param size Optional variable reference. If defined, if returns the
6245: * content size.
6246: *
6247: * @return An internal reference to the content stored and optionally
6248: * the content size notified on the variable received. In the case the
6249: * function receives an incompatible \ref axlItem (which is not \ref
6250: * ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref ITEM_REF),
6251: * the function will return NULL, and the optional variable will be
6252: * filled with -1.
6253: */
6254: char * axl_item_get_content (axlItem * item,
6255: int * size)
6256: {
6257: axlNodeContent * content;
6258:
6259: /* check content received */
6260: if (size != NULL)
6261: *size = -1;
6262:
6263: /* check if the item reference is NULL */
6264: axl_return_val_if_fail (item,
6265: NULL);
6266: axl_return_val_if_fail (axl_item_get_type (item) != ITEM_NODE && axl_item_get_type (item) != ITEM_PI,
6267: NULL);
6268:
6269: /* get the content */
6270: content = item->data;
6271:
6272: /* fill the size */
6273: if (size != NULL)
6274: *size = content->content_size;
6275:
6276: /* return a pointer to the content */
6277: return content->content;
6278: }
6279:
6280: /* prepare the item to be added to the xml document */
6281: axlItem * __axl_item_common_configure (axlNode * parent, AxlItemType type, axlPointer data)
6282: {
6283: axlNode * node = NULL;
6284: axlItem * item = NULL;
6285:
6286: /* return if the parent is defined */
6287: axl_return_val_if_fail (parent, NULL);
6288:
6289: /* check if the node received already have a pointer to a
6290: * holder created */
6291: if (type & ITEM_NODE) {
6292: /* get a reference to the node */
6293: node = (axlNode *) data;
6294:
6295: /* get a reference to the holder */
6296: item = node->holder;
6297:
6298: /* check if the current item was allocated from a
6299: * factory to ensure we don't loose that
6300: * information */
6301: if ((item != NULL) && (item->type & ITEM_FROM_FACTORY))
6302: type = type | ITEM_FROM_FACTORY;
6303: }
6304:
6305: /* create an item to hold the child, configuring the node, the
6306: * parent and the document */
6307: if (item == NULL) {
6308: if ((parent->holder != NULL) && (parent->holder->doc != NULL)) {
6309: item = axl_item_factory_get (axl_doc_get_item_factory (parent->holder->doc));
6310: type = type | ITEM_FROM_FACTORY;
6311: } else
6312: item = axl_new (axlItem, 1);
6313: }
6314: item->type = type;
6315: item->data = data;
6316: item->doc = (parent->holder != NULL) ? parent->holder->doc : NULL;
6317:
6318: if (item->type & ITEM_NODE) {
6319: /* now configure the item that will hold the new child */
6320: node->holder = item;
6321: } /* end if */
6322:
6323: /* return item created */
6324: return item;
6325: }
6326:
6327: /**
6328: * @internal Function that helps adding a new item to the provided
6329: * parent node.
6330: *
6331: * The new item will be added as flaged by the type provided. The
6332: * function isn't exposed to the public API because there are better
6333: * alternatives to add items to a \ref axlNode. Don't use this API
6334: * directly.
6335: *
6336: * @param parent The axl node that will receive the new content.
6337: *
6338: * @param type The type to configure to the new item.
6339: *
6340: * @param data The data associated to the data being stored.
6341: *
6342: * NOTE: the function doesn't check data received as it is supposed to
6343: * receive calls from the library.
6344: */
6345: void axl_item_set_child (axlNode * parent, AxlItemType type, axlPointer data)
6346: {
6347: axlItem * item;
6348:
6349: /* prepare the item to be added to the xml document */
6350: item = __axl_item_common_configure (parent, type, data);
6351:
6352: /* call to set child with a created item */
6353: axl_item_set_child_ref (parent, item);
6354:
6355: return;
6356: }
6357:
6358: /**
6359: * @brief Allows to configure xml content just after the item used as
6360: * reference.
6361: *
6362: * @param item The item used as reference to place the content after
6363: * it.
6364: *
6365: * @param type AxlItemType to configure the content to be placed.
6366: *
6367: * @param data Pointer that is associated to the type.
6368: */
6369: void axl_item_set_after (axlItem * item,
6370: AxlItemType type,
6371: axlPointer data)
6372: {
6373: axlItem * new_item = NULL;
6374:
6375: /* prepare the item to be added to the xml document */
6376: new_item = __axl_item_common_configure (item->parent, type, data);
6377:
6378: /* configure the parent node */
6379: new_item->parent = item->parent;
6380:
6381: /* configure new item references */
6382: new_item->previous = item;
6383: new_item->next = item->next;
6384:
6385: /* configure item references */
6386: if (item->next != NULL)
6387: item->next->previous = new_item;
6388: else
6389: item->parent->last = new_item;
6390: item->next = new_item;
6391:
6392: return;
6393: }
6394:
6395: /* call to set child with a created item */
6396: void axl_item_set_child_ref (axlNode * parent, axlItem * item)
6397: {
6398: axl_return_if_fail (parent);
6399: axl_return_if_fail (item);
6400:
6401: /* configure the parent node */
6402: item->parent = parent;
6403:
6404: /* get the current last child */
6405: if (parent->first == NULL) {
6406: /* init first and last reference to the only one
6407: * child */
6408: parent->first = item;
6409: parent->last = item;
6410: }else {
6411: /* configure the next item to the current last
6412: * child */
6413: parent->last->next = item;
6414:
6415: /* update the last child reference */
6416: item->previous = parent->last;
6417: item->next = NULL;
6418: parent->last = item;
6419: }
6420:
6421: return;
6422: }
6423:
6424: /**
6425: * @brief Copy the reference provided creating a newly allocated
6426: * reference, including the content inside.
6427: *
6428: * @param item The item to copy.
6429: *
6430: * @param set_parent Optionally, allows to provide the parent to be
6431: * configured to the item created. This is really required while
6432: * copying items that contains nodes.
6433: *
6434: * @return A newly allocated \ref axlItem reference, containing the
6435: * same data (a deep copy) and optionally configured with the provided
6436: * parent.
6437: */
6438: axlItem * axl_item_copy (axlItem * item, axlNode * set_parent)
6439: {
6440: axlItem * copy;
6441: axlNode * node;
6442: axlNodeContent * content;
6443:
6444: /* check values received */
6445: axl_return_val_if_fail (item, NULL);
6446:
6447: /* allocate an copy type */
6448: copy = axl_new (axlItem, 1);
6449: copy->type = axl_item_get_type (item);
6450: copy->parent = set_parent;
6451:
6452: switch (axl_item_get_type (item)) {
6453: case ITEM_NODE:
6454: /* copy the node */
6455: node = axl_node_copy (item->data, axl_true, axl_true);
6456: node->holder = copy;
6457: copy->data = node;
6458: break;
6459: case ITEM_CONTENT:
6460: case ITEM_CDATA:
6461: case ITEM_COMMENT:
6462: /* copy content */
6463: content = axl_new (axlNodeContent, 1);
6464: content->content = axl_strdup (((axlNodeContent * ) item->data)->content);
6465: content->content_size = ((axlNodeContent * ) item->data)->content_size;
6466:
6467: /* copy content */
6468: copy->data = content;
6469: break;
6470: case ITEM_PI:
6471: /* copy pi */
6472: copy->data = axl_pi_copy (item->data);
6473: break;
6474: case ITEM_REF:
6475: /* not implemented yet */
6476: break;
6477: case ITEM_FROM_FACTORY:
6478: case ITEM_CONTENT_FROM_FACTORY:
6479: /* never reached */
6480: break;
6481: } /* end switch */
6482:
6483: /* return copy created */
6484: return copy;
6485: }
6486:
6487: /**
6488: * @brief Allows to remove the \ref axlItem instance from the document
6489: * that is currently holding it, optionally deallocating the memory
6490: * used by the structure.
6491: *
6492: * @param item The item to remove from its container (without taking
6493: * into consideration the item type).
6494: *
6495: * @param dealloc Deallocs the memory used by the \ref axlItem
6496: * reference.
6497: */
6498: void axl_item_remove (axlItem * item,
6499: axl_bool dealloc)
6500: {
6501:
6502: /* free the item */
6503: axl_return_if_fail (item);
6504:
6505: /* realloc references */
6506: if (item->previous != NULL)
6507: item->previous->next = item->next;
6508:
6509: if (item->next != NULL)
6510: item->next->previous = item->previous;
6511:
6512: /* realloc parent references in the case of a node */
6513: if (axl_item_get_type (item) == ITEM_NODE) {
6514: if (item->previous == NULL)
6515: item->parent->first = item->next;
6516:
6517: if (item->next == NULL)
6518: item->parent->last = item->previous;
6519: } /* end if */
6520:
6521: /* free the item */
6522: item->next = NULL;
6523: item->previous = NULL;
6524:
6525: if (dealloc) {
6526: axl_item_free (item, axl_true);
6527: } /* end if */
6528:
6529: return;
6530:
6531: } /* end axl_item_remove */
6532:
6533: /**
6534: * @brief Allows to replace the content held by the \ref axlItem
6535: * reference with a new \ref axlItem, updating all references, and
6536: * optionally, deallocating the memory used by the previous item
6537: * reference.
6538: *
6539: * @param item The item to be replaced.
6540: *
6541: * @param new_item The new item to be placed where the previous one is
6542: * located.
6543: *
6544: * @param dealloc Signal to function to dealloc the memory hold the
6545: * the item replaced.
6546: */
6547: void axl_item_replace (axlItem * item,
6548: axlItem * new_item,
6549: axl_bool dealloc)
6550: {
6551: /* free the item */
6552: axl_return_if_fail (item);
6553: axl_return_if_fail (new_item);
6554:
6555: /* realloc references */
6556: if (item->previous != NULL) {
6557: item->previous->next = new_item;
6558: new_item->previous = item->previous;
6559: }
6560:
6561: if (item->next != NULL) {
6562: item->next->previous = new_item;
6563: new_item->next = item->next;
6564: }
6565:
6566: /* realloc parent references in the case of a node */
6567: if (axl_item_get_type (item) == ITEM_NODE) {
6568: if (item->previous == NULL)
6569: item->parent->first = new_item;
6570:
6571: if (item->next == NULL)
6572: item->parent->last = new_item;
6573: } /* end if */
6574:
6575: /* free the item */
6576: item->next = NULL;
6577: item->previous = NULL;
6578:
6579: /* configure values */
6580: new_item->parent = item->parent;
6581: new_item->doc = item->doc;
6582:
6583: if (dealloc) {
6584: axl_item_free (item, axl_true);
6585:
6586: } /* end if */
6587:
6588: return;
6589:
6590: } /* end axl_item_replace */
6591:
6592: /**
6593: * @brief Allows to transfer all childs contained inside the provided
6594: * \ref axlNode (old_parent) placed after the provided axlItem
6595: * (item_ref) on the same level.
6596: *
6597: * This function allows to manipulate a xml document loaded inside
6598: * memory, by transfering all childs (including xml nodes, xml
6599: * comments, content, process instructions and entity references) from
6600: * the selected parent (the old parent) provided by the
6601: * <i>old_parent</i> attribute, to be placed at the same level, where
6602: * the <i>item_ref</i> is situated following it.
6603: *
6604: *
6605: * @param old_parent Previous parent, where the childs to be
6606: * transfered will be found.
6607: *
6608: * @param item_ref The \ref axlItem that will act as a reference
6609: * placing all childs following the item.
6610: */
6611: void axl_item_transfer_childs_after (axlNode * old_parent,
6612: axlItem * item_ref)
6613: {
6614: axlItem * item;
6615: axlItem * item_aux;
6616:
6617: /* get the first child for the old parent */
6618: item = old_parent->first;
6619:
6620: /* check if the parent node contains childs to be
6621: * transferred. If no child is found, just return */
6622: if (item == NULL)
6623: return;
6624:
6625: /* remember previous next */
6626: item_aux = item_ref->next;
6627:
6628: /* make the first child to follow the item ref */
6629: item_ref->next = item;
6630: item->previous = item_ref;
6631:
6632: /* set the next at the end of all items transferred, and the
6633: * new parent node */
6634: while (item != NULL) {
6635: /* configure the new parent */
6636: item->parent = item_ref->parent;
6637:
6638: /* check the item to be the last */
6639: if (item->next == NULL) {
6640: /* the last item was found, configure it */
6641: item->next = item_aux;
6642:
6643: /* configure it to point to the last item
6644: * transferred */
6645: if (item_aux != NULL)
6646: item_aux->previous = item;
6647:
6648: /* break the loop! */
6649: break;
6650: } /* end if */
6651:
6652: /* get the next */
6653: item = item->next;
6654:
6655: } /* end while */
6656:
6657: /* check that the item selected to be reference isn't the last
6658: * child inside new parent node. If it is, update the new
6659: * last */
6660: if (item_aux == NULL) {
6661: /* because item is pointing to the last item in the
6662: * level, use it as the new last */
6663: item->parent->last = item;
6664: } /* end if */
6665:
6666: /* clear reference from previous parent */
6667: old_parent->first = NULL;
6668: old_parent->last = NULL;
6669:
6670: return;
6671: }
6672:
6673: /**
6674: * @brief Allows to check if both items are equal, considering the
6675: * item type and the content associated to the item type.
6676: *
6677: * @param item The first item to check.
6678: *
6679: * @param item2 The second item to check.
6680: *
6681: * @param trimmed This paramenter allows to configure how the equal
6682: * check is performed for content element (\ref ITEM_CONTENT, \ref
6683: * ITEM_CDATA, \ref ITEM_COMMENT and \ref ITEM_REF).
6684: *
6685: * @param error Optional \ref axlError reference where textual
6686: * diagnostic is reported.
6687: *
6688: *
6689: * @return \ref axl_true if the both items represents the same
6690: * information, otherwise \ref axl_false is returned. If the function
6691: * receives a null value it will return axl_false.
6692: */
6693: axl_bool axl_item_are_equal_full (axlItem * item,
6694: axlItem * item2,
6695: axl_bool trimmed,
6696: axlError ** error)
6697: {
6698: axlNodeContent * content;
6699: axlNodeContent * content2;
6700:
6701: /* trim content */
6702: char * trim;
6703: char * trim2;
6704: axl_bool result;
6705:
6706: axl_return_val_if_fail (item, axl_false);
6707: axl_return_val_if_fail (item2, axl_false);
6708:
6709: /* basic type check */
6710: if (axl_item_get_type (item) != axl_item_get_type (item2)) {
6711: axl_error_report (error, -1, "Items types differs (%d != %d)",
6712: axl_item_get_type (item), axl_item_get_type (item2));
6713: return axl_false;
6714: }
6715:
6716: /* according the type */
6717: switch (axl_item_get_type (item)) {
6718: case ITEM_NODE:
6719: /* check that both nodes are equal */
6720: return axl_node_are_equal_full (item->data, item2->data, error);
6721: case ITEM_CONTENT:
6722: case ITEM_CDATA:
6723: case ITEM_COMMENT:
6724: case ITEM_REF:
6725: /* get the contenet */
6726: content = item->data;
6727: content2 = item2->data;
6728:
6729: if (! trimmed) {
6730: /* check first content length */
6731: if (content->content_size != content2->content_size) {
6732: axl_error_report (error, -1, "Items content size differs (%s:%d != %s:%d)",
6733: content->content,
6734: content->content_size,
6735: content2->content,
6736: content2->content_size);
6737: return axl_false;
6738: }
6739:
6740: /* now check content value */
6741: return axl_cmp (content->content, content2->content);
6742: }else {
6743: /* duplicate the content */
6744: trim = axl_strdup (content->content);
6745: trim2 = axl_strdup (content2->content);
6746:
6747: /* trim content */
6748: axl_stream_trim (trim);
6749: axl_stream_trim (trim2);
6750:
6751: /* do the comparision */
6752: result = axl_cmp (trim, trim2);
6753:
6754: if (! result) {
6755: axl_error_report (error, -1, "Trimmed content differs ('%s' != '%s')", trim, trim2);
6756: } /* end if */
6757:
6758: /* free data */
6759: axl_free (trim);
6760: axl_free (trim2);
6761:
6762: return result;
6763:
6764: }
6765: case ITEM_PI:
6766: /* pi case */
6767: return axl_pi_are_equal (item->data, item2->data);
6768: default:
6769: /* no case identified, not equal */
6770: break;
6771: } /* end switch */
6772:
6773: axl_error_report (error, -1, "Item type not found, unable to check");
6774: return axl_false;
6775: }
6776:
6777: /**
6778: * @brief Allows to check if both items are equal, considering the
6779: * item type and the content associated to the item type.
6780: *
6781: *
6782: * @param item The first item to check.
6783: *
6784: * @param item2 The second item to check.
6785: *
6786: * @param trimmed This paramenter allows to configure how equal
6787: * checking is performed for content element (\ref ITEM_CONTENT, \ref
6788: * ITEM_CDATA, \ref ITEM_COMMENT and \ref ITEM_REF).
6789: *
6790: * @return \ref axl_true if the both items represents the same
6791: * information, otherwise \ref axl_false is returned. If the function
6792: * receives a null value it will return axl_false.
6793: */
6794: axl_bool axl_item_are_equal (axlItem * item,
6795: axlItem * item2,
6796: axl_bool trimmed)
6797: {
6798: /* call to check if both items are equal */
6799: return axl_item_are_equal_full (item, item2, trimmed, NULL);
6800: }
6801:
6802: /**
6803: * @brief Allows to release the memory hold the item reference
6804: * provided, and the value stored inside it.
6805: *
6806: * @param item The item to dealloc.
6807: *
6808: * @param dealloc \ref axl_true to also dealloc the value inside.
6809: */
6810: void axl_item_free (axlItem * item,
6811: axl_bool dealloc)
6812: {
6813: axl_return_if_fail (item);
6814:
6815:
6816: /* according the type */
6817: switch (axl_item_get_type (item)) {
6818: case ITEM_NODE:
6819: /* free the node */
6820: axl_node_free (item->data);
6821: break;
6822: case ITEM_CONTENT:
6823: case ITEM_CDATA:
6824: case ITEM_COMMENT:
6825: case ITEM_REF:
6826: /* all of them, managed equally */
6827:
6828: /* check and free content */
6829: if ((item->type & ITEM_CONTENT_FROM_FACTORY) == 0) {
6830: axl_free (((axlNodeContent *)item->data)->content);
6831:
6832: /* free node */
6833: axl_free ((axlNodeContent *)item->data);
6834: }
6835:
6836: if ((item->type & ITEM_FROM_FACTORY) == 0)
6837: axl_free (item);
6838: break;
6839: case ITEM_PI:
6840: /* an process instruction */
6841: axl_pi_free (item->data);
6842:
6843: /* free the item */
6844: if ((item->type & ITEM_FROM_FACTORY) == 0)
6845: axl_free (item);
6846: break;
6847: case ITEM_FROM_FACTORY:
6848: case ITEM_CONTENT_FROM_FACTORY:
6849: /* never reached */
6850: break;
6851:
6852: } /* end switch */
6853:
6854:
6855: return;
6856: }
6857:
6858: axlFactory * axl_item_factory_create (void)
6859: {
6860: return axl_factory_create (sizeof (axlItem));
6861: }
6862:
6863: axlItem * axl_item_factory_get (axlFactory * factory)
6864: {
6865: return axl_factory_get (factory);
6866: }
6867:
6868: axlFactory * axl_node_factory_create (void)
6869: {
6870: return axl_factory_create (sizeof (axlNode));
6871: }
6872:
6873: axlNode * axl_node_factory_get (axlFactory * factory)
6874: {
6875: /* get a node */
6876: axlNode * node = axl_factory_get (factory);
6877:
6878: /* configure it */
6879: node->conf = NODE_FROM_FACTORY;
6880:
6881: return node;
6882: }
6883:
6884: axlFactory * axl_item_content_factory_create (void)
6885: {
6886: /* create a factory for axlNodeContent elements */
6887: return axl_factory_create (sizeof (axlNodeContent));
6888: }
6889:
6890: axlFactory * axl_item_attr_factory_create (void)
6891: {
6892: /* create a factory for axlNodeAttr elements */
6893: return axl_factory_create (sizeof (axlNodeAttr));
6894: }
6895:
6896: /* @} */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>