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