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) {
237 return strdup("<null/>");
239 growing_buffer * res_xml = buffer_init(1024);
241 _recurse_jsonObjectToXML( obj, res_xml );
242 return buffer_release(res_xml);
246 int _recurse_jsonObjectToXML(const jsonObject* obj, growing_buffer* res_xml) {
251 hint = strdup(obj->classname);
253 if(obj->type == JSON_NULL) {
256 buffer_fadd(res_xml, "<null class_hint=\"%s\"/>",hint);
258 buffer_add(res_xml, "<null/>");
260 } else if(obj->type == JSON_BOOL) {
262 const char* bool_val;
269 buffer_fadd(res_xml, "<boolean value=\"%s\" class_hint=\"%s\"/>", bool_val, hint);
271 buffer_fadd(res_xml, "<boolean value=\"%s\"/>", bool_val);
273 } else if (obj->type == JSON_STRING) {
275 char * t = _escape_xml(jsonObjectGetString(obj));
276 buffer_fadd(res_xml,"<string class_hint=\"%s\">%s</string>", hint, t);
279 char * t = _escape_xml(jsonObjectGetString(obj));
280 buffer_fadd(res_xml,"<string>%s</string>", t);
284 } else if(obj->type == JSON_NUMBER) {
285 double x = jsonObjectGetNumber(obj);
288 buffer_fadd(res_xml,"<number class_hint=\"%s\">%d</number>", hint, (int)x);
290 buffer_fadd(res_xml,"<number class_hint=\"%s\">%lf</number>", hint, x);
293 buffer_fadd(res_xml,"<number>%d</number>", (int)x);
295 buffer_fadd(res_xml,"<number>%lf</number>", x);
298 } else if (obj->type == JSON_ARRAY) {
301 buffer_fadd(res_xml,"<array class_hint=\"%s\">", hint);
303 buffer_add(res_xml,"<array>");
306 for ( i = 0; i!= obj->size; i++ )
307 _recurse_jsonObjectToXML(jsonObjectGetIndex(obj,i), res_xml);
309 buffer_add(res_xml,"</array>");
311 } else if (obj->type == JSON_HASH) {
314 buffer_fadd(res_xml,"<object class_hint=\"%s\">", hint);
316 buffer_add(res_xml,"<object>");
318 jsonIterator* itr = jsonNewIterator(obj);
319 const jsonObject* tmp;
320 while( (tmp = jsonIteratorNext(itr)) ) {
321 buffer_fadd(res_xml,"<element key=\"%s\">",itr->key);
322 _recurse_jsonObjectToXML(tmp, res_xml);
323 buffer_add(res_xml,"</element>");
325 jsonIteratorFree(itr);
327 buffer_add(res_xml,"</object>");
336 static char* _escape_xml (const char* text) {
337 growing_buffer* b = buffer_init(256);
338 int len = strlen(text);
340 for (i = 0; i < len; i++) {
342 buffer_add(b,"&");
343 else if (text[i] == '<')
344 buffer_add(b,"<");
345 else if (text[i] == '>')
346 buffer_add(b,">");
348 buffer_add_char(b,text[i]);
350 return buffer_release(b);