Added a new XML-2-JSON utility for converting XMLized OpenSRF objects to their intern...
[OpenSRF.git] / src / objson / xml2json.c
1 #include "xml2json.h"
2
3 struct osrfXMLGatewayParserStruct {
4     osrfList* objStack;
5     osrfList* keyStack;
6     jsonObject* obj;
7     short inString;
8     short inNumber;
9     short error;
10 };
11 typedef struct osrfXMLGatewayParserStruct osrfXMLGatewayParser;
12
13 /** returns the attribute value with the given attribute name */
14 static char* getXMLAttr(const xmlChar** atts, char* attr_name) {
15     int i;
16     if (atts != NULL) {
17         for(i = 0; (atts[i] != NULL); i++) {
18             if(strcmp((char*) atts[i++], attr_name) == 0) {
19                 if(atts[i] != NULL) 
20                     return (char*) atts[i];
21             }
22         }
23     }
24     return NULL;
25 }
26
27
28 static void appendChild(osrfXMLGatewayParser* p, jsonObject* obj) {
29
30     if(p->obj == NULL) 
31         p->obj = obj;
32
33     if(p->objStack->size == 0)
34         return;
35     
36     jsonObject* parent = OSRF_LIST_GET_INDEX(p->objStack, p->objStack->size - 1);
37
38     if(parent->type == JSON_ARRAY) {
39         jsonObjectPush(parent, obj);
40     } else {
41         char* key = osrfListPop(p->keyStack);
42         jsonObjectSetKey(parent, key, obj);
43         free(key); /* the list is not setup for auto-freeing */
44     }
45 }
46
47
48
49 static void startElementHandler(
50     void *parser, const xmlChar *name, const xmlChar **atts) {
51
52     osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
53     jsonObject* obj;
54
55     char* hint = getXMLAttr(atts, "class_hint");
56
57     if(!strcmp((char*) name, "null")) {
58         appendChild(p, jsonNewObject(NULL));
59         return;
60     }
61
62     if(!strcmp((char*) name, "string")) {
63         p->inString = 1;
64         return;
65     }
66
67     if(!strcmp((char*) name, "element")) {
68        osrfListPush(p->keyStack, strdup(getXMLAttr(atts, "key")));
69        return;
70     }
71
72     if(!strcmp((char*) name, "object")) {
73         obj = jsonNewObject(NULL);
74         jsonObjectSetClass(obj, hint); /* OK if hint is NULL */
75         obj->type = JSON_HASH;
76         appendChild(p, obj);
77         osrfListPush(p->objStack, obj);
78         return;
79     }
80
81     if(!strcmp((char*) name, "array")) {
82         obj = jsonNewObject(NULL);
83         jsonObjectSetClass(obj, hint); /* OK if hint is NULL */
84         obj->type = JSON_ARRAY;
85         appendChild(p, obj);
86         osrfListPush(p->objStack, obj);
87         return;
88     }
89
90
91     if(!strcmp((char*) name, "number")) {
92         p->inNumber = 1;
93         return;
94     }
95
96     if(!strcmp((char*) name, "boolean")) {
97         obj = jsonNewObject(NULL);
98         obj->type = JSON_BOOL;
99         char* val = getXMLAttr(atts, "value");
100         if(val && !strcmp(val, "true"))
101             obj->value.b = 1;
102         
103         return;
104     }
105 }
106
107 static void endElementHandler( void *parser, const xmlChar *name) {
108     if(!strcmp((char*) name, "array") || !strcmp((char*) name, "object")) {
109         osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
110         osrfListPop(p->objStack);
111     }
112 }
113
114 static void characterHandler(void *parser, const xmlChar *ch, int len) {
115
116     char data[len+1];
117     strncpy(data, (char*) ch, len);
118     data[len] = '\0';
119     osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
120
121     if(p->inString) {
122         appendChild(p, jsonNewObject(data));
123         p->inString = 0;
124         return;
125     }
126
127     if(p->inNumber) {
128         appendChild(p, jsonNewNumberObject(atof(data)));
129         p->inNumber = 0;
130         return;
131     }
132 }
133
134 static void parseWarningHandler(void *parser, const char* msg, ...) {
135     VA_LIST_TO_STRING(msg);
136     fprintf(stderr, "Parser warning %s\n", VA_BUF);
137     fflush(stderr);
138 }
139
140 static void parseErrorHandler(void *parser, const char* msg, ...) {
141
142     VA_LIST_TO_STRING(msg);
143     fprintf(stderr, "Parser error %s\n", VA_BUF);
144     fflush(stderr);
145
146     osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
147
148     /*  keyStack as strdup'ed strings.  The list may
149      *  not be empty, so tell it to free the items
150      *  when it's freed (from the main routine)
151      */
152     osrfListSetDefaultFree(p->keyStack);
153     jsonObjectFree(p->obj);
154
155     p->obj = NULL;
156     p->error = 1;
157 }
158
159
160
161
162 static xmlSAXHandler SAXHandlerStruct = {
163     NULL,                            /* internalSubset */
164     NULL,                            /* isStandalone */
165     NULL,                            /* hasInternalSubset */
166     NULL,                            /* hasExternalSubset */
167     NULL,                            /* resolveEntity */
168     NULL,                            /* getEntity */
169     NULL,                            /* entityDecl */
170     NULL,                            /* notationDecl */
171     NULL,                            /* attributeDecl */
172     NULL,                            /* elementDecl */
173     NULL,                            /* unparsedEntityDecl */
174     NULL,                            /* setDocumentLocator */
175     NULL,                            /* startDocument */
176     NULL,                            /* endDocument */
177     startElementHandler,        /* startElement */
178     endElementHandler,      /* endElement */
179     NULL,                            /* reference */
180     characterHandler,           /* characters */
181     NULL,                            /* ignorableWhitespace */
182     NULL,                            /* processingInstruction */
183     NULL,                            /* comment */
184     parseWarningHandler,     /* xmlParserWarning */
185     parseErrorHandler,       /* xmlParserError */
186     NULL,                            /* xmlParserFatalError : unused */
187     NULL,                            /* getParameterEntity */
188     NULL,                            /* cdataBlock; */
189     NULL,                            /* externalSubset; */
190     1,
191     NULL,
192     NULL,                            /* startElementNs */
193     NULL,                            /* endElementNs */
194     NULL                            /* xmlStructuredErrorFunc */
195 };
196
197 static const xmlSAXHandlerPtr SAXHandler = &SAXHandlerStruct;
198
199 jsonObject* jsonXMLToJSONObject(const char* xml) {
200
201     osrfXMLGatewayParser parser;
202
203     /* don't define freeItem, since objects will be cleaned by freeing the parent */
204     parser.objStack = osrfNewList(); 
205     /* don't define freeItem, since the list eill end up empty if there are no errors*/
206     parser.keyStack = osrfNewList(); 
207     parser.obj = NULL;
208     parser.inString = 0;
209     parser.inNumber = 0;
210
211     xmlParserCtxtPtr ctxt = xmlCreatePushParserCtxt(SAXHandler, &parser, "", 0, NULL);
212     xmlParseChunk(ctxt, xml, strlen(xml), 1);
213
214     osrfListFree(parser.objStack);
215     osrfListFree(parser.keyStack);
216     xmlFreeParserCtxt(ctxt);
217     xmlCleanupCharEncodingHandlers();
218     xmlDictCleanup();
219     xmlCleanupParser();
220
221     return parser.obj;
222 }
223
224
225
226
227
228
229