1. Change xmlSaxAttr() to return const char* instead of
[OpenSRF.git] / src / libopensrf / xml_utils.c
1 #include <opensrf/xml_utils.h>
2
3 /* helper function */
4 static jsonObject* _xmlToJSON(xmlNodePtr node, jsonObject*);
5
6 /**
7         @brief Write then contents of an xmlNode to standard output.
8         @param node Pointer to an xmlNode
9
10         Write the text content of an xmlNode, and all its dependent nodes recursively, to
11         standard output.
12 */
13 void recurse_doc( xmlNodePtr node ) {
14         if( node == NULL ) return;
15         printf("Recurse: %s =>  %s", node->name, node->content );
16         xmlNodePtr t = node->children;
17         while(t) {
18                 recurse_doc(t);
19                 t = t->next;
20         }
21 }
22
23 jsonObject* xmlDocToJSON(xmlDocPtr doc) {
24         if(!doc) return NULL;
25         return _xmlToJSON(xmlDocGetRootElement(doc), NULL);
26 }
27
28 static jsonObject* _xmlToJSON(xmlNodePtr node, jsonObject* obj) {
29
30         if(!node) return NULL;
31         if(xmlIsBlankNode(node)) return NULL;
32         if(obj == NULL) obj = jsonNewObject(NULL);
33
34         if(node->type == XML_TEXT_NODE) {
35                 jsonObjectSetString(obj, (char*) node->content);
36
37         } else if(node->type == XML_ELEMENT_NODE || node->type == XML_ATTRIBUTE_NODE ) {
38
39                 jsonObject* new_obj = jsonNewObject(NULL);
40
41                 jsonObject* old;
42
43                 /* do the duplicate node / array shuffle */
44                 if( (old = jsonObjectGetKey(obj, (char*) node->name)) ) {
45                         if(old->type == JSON_ARRAY ) {
46                                 jsonObjectPush(old, new_obj);
47                         } else {
48                                 jsonObject* arr = jsonNewObject(NULL);
49                                 jsonObjectPush(arr, jsonObjectClone(old));
50                                 jsonObjectPush(arr, new_obj);
51                                 jsonObjectSetKey(obj, (char*) node->name, arr);
52                         }
53                 } else {
54                         jsonObjectSetKey(obj, (char*) node->name, new_obj);
55                 }
56
57                 xmlNodePtr child = node->children;
58                 if (child) { // at least one...
59                         if (child != node->last) { // more than one -- ignore TEXT nodes
60                                 while(child) {
61                                         if (child->type != XML_TEXT_NODE) _xmlToJSON(child, new_obj);
62                                         child = child->next;
63                                 }
64                         } else {
65                                 _xmlToJSON(child, new_obj);
66                         }
67                 }
68         }
69
70         return obj;
71 }
72
73
74 char* xmlDocToString(xmlDocPtr doc, int full) {
75
76         if(!doc) return NULL;
77
78         char* xml;
79
80         if(full) {
81
82                 xmlChar* xmlbuf;
83                 int size;
84                 xmlDocDumpMemory(doc, &xmlbuf, &size);
85                 xml = strdup((char*) (xmlbuf));
86                 xmlFree(xmlbuf);
87                 return xml;
88
89         } else {
90
91                 xmlBufferPtr xmlbuf = xmlBufferCreate();
92                 xmlNodeDump( xmlbuf, doc, xmlDocGetRootElement(doc), 0, 0);
93                 xml = strdup((char*) (xmlBufferContent(xmlbuf)));
94                 xmlBufferFree(xmlbuf);
95                 return xml;
96
97         }
98 }
99
100 /**
101         @brief Search for the value of a given attribute in an attribute array.
102         @param atts Pointer to the attribute array to be searched.
103         @param atts Pointer to the attribute name to be sought.
104         @return A pointer to the attribute value if found, or NULL if not.
105
106         The @a atts parameter points to a ragged array of strings.  The @a atts[0] pointer points
107         to an attribute name, and @a atts[1] points to the corresponding attribute value.  The
108         remaining pointers likewise point alternately to names and values.  The end of the
109         list is marked by a NULL.
110
111         In practice, the @a atts array is constructed by the XML parser and passed to a callback
112         function.
113
114 */
115 const char* xmlSaxAttr( const xmlChar** atts, const char* name ) {
116         if( atts && name ) {
117                 int i;
118                 for(i = 0; (atts[i] != NULL); i++) {
119                         if(!strcmp((char*) atts[i], name)) {
120                                 if(atts[++i])
121                                         return (const char*) atts[i];
122                         }
123                 }
124         }
125         return NULL;
126 }
127
128 /**
129         @brief Add a series of attributes to an xmlNode.
130         @param node Pointer to the xmlNode to which the attributes will be added.
131         @param atts Pointer to the attributes to be added.
132         @return Zero in all cases.
133
134         The @a atts parameter points to a ragged array of strings.  The @a atts[0] pointer points
135         to an attribute name, and @a atts[1] points to the corresponding attribute value.  The
136         remaining pointers likewise point alternately to names and values.  The end of the
137         list is marked by a NULL.
138
139         In practice, the @a atts array is constructed by the XML parser and passed to a callback
140         function.
141 */
142 int xmlAddAttrs( xmlNodePtr node, const xmlChar** atts ) {
143         if( node && atts ) {
144                 int i;
145                 for(i = 0; (atts[i] != NULL); i++) {
146                         if(atts[i+1]) {
147                                 xmlSetProp(node, atts[i], atts[i+1]);
148                                 i++;
149                         }
150                 }
151         }
152         return 0;
153 }
154