1 #include <opensrf/osrf_json_xml.h>
3 #ifdef OSRF_JSON_ENABLE_XML_UTILS
5 struct osrfXMLGatewayParserStruct {
13 typedef struct osrfXMLGatewayParserStruct osrfXMLGatewayParser;
15 /** returns the attribute value with the given attribute name */
16 static char* getXMLAttr(const xmlChar** atts, const char* attr_name) {
19 for(i = 0; (atts[i] != NULL); i++) {
20 if(strcmp((char*) atts[i++], attr_name) == 0) {
22 return (char*) atts[i];
30 static void appendChild(osrfXMLGatewayParser* p, jsonObject* obj) {
35 if(p->objStack->size == 0)
38 jsonObject* parent = OSRF_LIST_GET_INDEX(p->objStack, p->objStack->size - 1);
40 if(parent->type == JSON_ARRAY) {
41 jsonObjectPush(parent, obj);
43 char* key = osrfListPop(p->keyStack);
44 jsonObjectSetKey(parent, key, obj);
45 free(key); /* the list is not setup for auto-freeing */
51 static void startElementHandler(
52 void *parser, const xmlChar *name, const xmlChar **atts) {
54 osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
57 char* hint = getXMLAttr(atts, "class_hint");
59 if(!strcmp((char*) name, "null")) {
60 appendChild(p, jsonNewObject(NULL));
64 if(!strcmp((char*) name, "string")) {
69 if(!strcmp((char*) name, "element")) {
70 osrfListPush(p->keyStack, strdup(getXMLAttr(atts, "key")));
74 if(!strcmp((char*) name, "object")) {
75 obj = jsonNewObject(NULL);
76 jsonObjectSetClass(obj, hint); /* OK if hint is NULL */
77 obj->type = JSON_HASH;
79 osrfListPush(p->objStack, obj);
83 if(!strcmp((char*) name, "array")) {
84 obj = jsonNewObject(NULL);
85 jsonObjectSetClass(obj, hint); /* OK if hint is NULL */
86 obj->type = JSON_ARRAY;
88 osrfListPush(p->objStack, obj);
93 if(!strcmp((char*) name, "number")) {
98 if(!strcmp((char*) name, "boolean")) {
99 obj = jsonNewObject(NULL);
100 obj->type = JSON_BOOL;
101 char* val = getXMLAttr(atts, "value");
102 if(val && !strcmp(val, "true"))
109 static void endElementHandler( void *parser, const xmlChar *name) {
110 if(!strcmp((char*) name, "array") || !strcmp((char*) name, "object")) {
111 osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
112 osrfListPop(p->objStack);
116 static void characterHandler(void *parser, const xmlChar *ch, int len) {
119 strncpy(data, (char*) ch, len);
121 osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
124 appendChild(p, jsonNewObject(data));
130 appendChild(p, jsonNewNumberObject(atof(data)));
136 static void parseWarningHandler(void *parser, const char* msg, ...) {
137 VA_LIST_TO_STRING(msg);
138 fprintf(stderr, "Parser warning %s\n", VA_BUF);
142 static void parseErrorHandler(void *parser, const char* msg, ...) {
144 VA_LIST_TO_STRING(msg);
145 fprintf(stderr, "Parser error %s\n", VA_BUF);
148 osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
150 /* keyStack as strdup'ed strings. The list may
151 * not be empty, so tell it to free the items
152 * when it's freed (from the main routine)
154 osrfListSetDefaultFree(p->keyStack);
155 jsonObjectFree(p->obj);
164 static xmlSAXHandler SAXHandlerStruct = {
165 NULL, /* internalSubset */
166 NULL, /* isStandalone */
167 NULL, /* hasInternalSubset */
168 NULL, /* hasExternalSubset */
169 NULL, /* resolveEntity */
170 NULL, /* getEntity */
171 NULL, /* entityDecl */
172 NULL, /* notationDecl */
173 NULL, /* attributeDecl */
174 NULL, /* elementDecl */
175 NULL, /* unparsedEntityDecl */
176 NULL, /* setDocumentLocator */
177 NULL, /* startDocument */
178 NULL, /* endDocument */
179 startElementHandler, /* startElement */
180 endElementHandler, /* endElement */
181 NULL, /* reference */
182 characterHandler, /* characters */
183 NULL, /* ignorableWhitespace */
184 NULL, /* processingInstruction */
186 parseWarningHandler, /* xmlParserWarning */
187 parseErrorHandler, /* xmlParserError */
188 NULL, /* xmlParserFatalError : unused */
189 NULL, /* getParameterEntity */
190 NULL, /* cdataBlock; */
191 NULL, /* externalSubset; */
194 NULL, /* startElementNs */
195 NULL, /* endElementNs */
196 NULL /* xmlStructuredErrorFunc */
199 static const xmlSAXHandlerPtr SAXHandler = &SAXHandlerStruct;
201 jsonObject* jsonXMLToJSONObject(const char* xml) {
203 osrfXMLGatewayParser parser;
205 /* don't define freeItem, since objects will be cleaned by freeing the parent */
206 parser.objStack = osrfNewList();
207 /* don't define freeItem, since the list eill end up empty if there are no errors*/
208 parser.keyStack = osrfNewList();
213 xmlParserCtxtPtr ctxt = xmlCreatePushParserCtxt(SAXHandler, &parser, "", 0, NULL);
214 xmlParseChunk(ctxt, xml, strlen(xml), 1);
216 osrfListFree(parser.objStack);
217 osrfListFree(parser.keyStack);
218 xmlFreeParserCtxt(ctxt);
219 xmlCleanupCharEncodingHandlers();
231 static char* _escape_xml (const char*);
232 static int _recurse_jsonObjectToXML(const jsonObject*, growing_buffer*);
234 char* jsonObjectToXML(const jsonObject* obj) {
236 growing_buffer * res_xml;
238 res_xml = buffer_init(1024);
241 return strdup("<null/>");
243 _recurse_jsonObjectToXML( obj, res_xml );
244 return buffer_release(res_xml);
248 int _recurse_jsonObjectToXML(const jsonObject* obj, growing_buffer* res_xml) {
253 hint = strdup(obj->classname);
255 if(obj->type == JSON_NULL) {
258 buffer_fadd(res_xml, "<null class_hint=\"%s\"/>",hint);
260 buffer_add(res_xml, "<null/>");
262 } else if(obj->type == JSON_BOOL) {
264 const char* bool_val;
271 buffer_fadd(res_xml, "<boolean value=\"%s\" class_hint=\"%s\"/>", bool_val, hint);
273 buffer_fadd(res_xml, "<boolean value=\"%s\"/>", bool_val);
275 } else if (obj->type == JSON_STRING) {
277 char * t = _escape_xml(jsonObjectGetString(obj));
278 buffer_fadd(res_xml,"<string class_hint=\"%s\">%s</string>", hint, t);
281 char * t = _escape_xml(jsonObjectGetString(obj));
282 buffer_fadd(res_xml,"<string>%s</string>", t);
286 } else if(obj->type == JSON_NUMBER) {
287 double x = jsonObjectGetNumber(obj);
290 buffer_fadd(res_xml,"<number class_hint=\"%s\">%d</number>", hint, (int)x);
292 buffer_fadd(res_xml,"<number class_hint=\"%s\">%lf</number>", hint, x);
295 buffer_fadd(res_xml,"<number>%d</number>", (int)x);
297 buffer_fadd(res_xml,"<number>%lf</number>", x);
300 } else if (obj->type == JSON_ARRAY) {
303 buffer_fadd(res_xml,"<array class_hint=\"%s\">", hint);
305 buffer_add(res_xml,"<array>");
308 for ( i = 0; i!= obj->size; i++ )
309 _recurse_jsonObjectToXML(jsonObjectGetIndex(obj,i), res_xml);
311 buffer_add(res_xml,"</array>");
313 } else if (obj->type == JSON_HASH) {
316 buffer_fadd(res_xml,"<object class_hint=\"%s\">", hint);
318 buffer_add(res_xml,"<object>");
320 jsonIterator* itr = jsonNewIterator(obj);
321 const jsonObject* tmp;
322 while( (tmp = jsonIteratorNext(itr)) ) {
323 buffer_fadd(res_xml,"<element key=\"%s\">",itr->key);
324 _recurse_jsonObjectToXML(tmp, res_xml);
325 buffer_add(res_xml,"</element>");
327 jsonIteratorFree(itr);
329 buffer_add(res_xml,"</object>");
338 char* _escape_xml (const char* text) {
339 growing_buffer* b = buffer_init(256);
340 int len = strlen(text);
342 for (i = 0; i < len; i++) {
344 buffer_add(b,"&");
345 else if (text[i] == '<')
346 buffer_add(b,"<");
347 else if (text[i] == '>')
348 buffer_add(b,">");
350 buffer_add_char(b,text[i]);
352 return buffer_release(b);