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"))
110 static void endElementHandler( void *parser, const xmlChar *name) {
111 if(!strcmp((char*) name, "array") || !strcmp((char*) name, "object")) {
112 osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
113 osrfListPop(p->objStack);
117 static void characterHandler(void *parser, const xmlChar *ch, int len) {
120 strncpy(data, (char*) ch, len);
122 osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
125 appendChild(p, jsonNewObject(data));
131 appendChild(p, jsonNewNumberObject(atof(data)));
137 static void parseWarningHandler(void *parser, const char* msg, ...) {
138 VA_LIST_TO_STRING(msg);
139 fprintf(stderr, "Parser warning %s\n", VA_BUF);
143 static void parseErrorHandler(void *parser, const char* msg, ...) {
145 VA_LIST_TO_STRING(msg);
146 fprintf(stderr, "Parser error %s\n", VA_BUF);
149 osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
151 /* keyStack as strdup'ed strings. The list may
152 * not be empty, so tell it to free the items
153 * when it's freed (from the main routine)
155 osrfListSetDefaultFree(p->keyStack);
156 jsonObjectFree(p->obj);
165 static xmlSAXHandler SAXHandlerStruct = {
166 NULL, /* internalSubset */
167 NULL, /* isStandalone */
168 NULL, /* hasInternalSubset */
169 NULL, /* hasExternalSubset */
170 NULL, /* resolveEntity */
171 NULL, /* getEntity */
172 NULL, /* entityDecl */
173 NULL, /* notationDecl */
174 NULL, /* attributeDecl */
175 NULL, /* elementDecl */
176 NULL, /* unparsedEntityDecl */
177 NULL, /* setDocumentLocator */
178 NULL, /* startDocument */
179 NULL, /* endDocument */
180 startElementHandler, /* startElement */
181 endElementHandler, /* endElement */
182 NULL, /* reference */
183 characterHandler, /* characters */
184 NULL, /* ignorableWhitespace */
185 NULL, /* processingInstruction */
187 parseWarningHandler, /* xmlParserWarning */
188 parseErrorHandler, /* xmlParserError */
189 NULL, /* xmlParserFatalError : unused */
190 NULL, /* getParameterEntity */
191 NULL, /* cdataBlock; */
192 NULL, /* externalSubset; */
195 NULL, /* startElementNs */
196 NULL, /* endElementNs */
197 NULL /* xmlStructuredErrorFunc */
200 static const xmlSAXHandlerPtr SAXHandler = &SAXHandlerStruct;
202 jsonObject* jsonXMLToJSONObject(const char* xml) {
204 osrfXMLGatewayParser parser;
206 /* don't define freeItem, since objects will be cleaned by freeing the parent */
207 parser.objStack = osrfNewList();
208 /* don't define freeItem, since the list eill end up empty if there are no errors*/
209 parser.keyStack = osrfNewList();
214 xmlParserCtxtPtr ctxt = xmlCreatePushParserCtxt(SAXHandler, &parser, "", 0, NULL);
215 xmlParseChunk(ctxt, xml, strlen(xml), 1);
217 osrfListFree(parser.objStack);
218 osrfListFree(parser.keyStack);
219 xmlFreeParserCtxt(ctxt);
220 xmlCleanupCharEncodingHandlers();
232 static char* _escape_xml (const char*);
233 static int _recurse_jsonObjectToXML(const jsonObject*, growing_buffer*);
235 char* jsonObjectToXML(const jsonObject* obj) {
238 return strdup("<null/>");
240 growing_buffer * res_xml = buffer_init(1024);
242 _recurse_jsonObjectToXML( obj, res_xml );
243 return buffer_release(res_xml);
247 int _recurse_jsonObjectToXML(const jsonObject* obj, growing_buffer* res_xml) {
252 hint = strdup(obj->classname);
254 if(obj->type == JSON_NULL) {
257 buffer_fadd(res_xml, "<null class_hint=\"%s\"/>",hint);
259 buffer_add(res_xml, "<null/>");
261 } else if(obj->type == JSON_BOOL) {
263 const char* bool_val;
270 buffer_fadd(res_xml, "<boolean value=\"%s\" class_hint=\"%s\"/>", bool_val, hint);
272 buffer_fadd(res_xml, "<boolean value=\"%s\"/>", bool_val);
274 } else if (obj->type == JSON_STRING) {
276 char * t = _escape_xml(jsonObjectGetString(obj));
277 buffer_fadd(res_xml,"<string class_hint=\"%s\">%s</string>", hint, t);
280 char * t = _escape_xml(jsonObjectGetString(obj));
281 buffer_fadd(res_xml,"<string>%s</string>", t);
285 } else if(obj->type == JSON_NUMBER) {
286 double x = jsonObjectGetNumber(obj);
289 buffer_fadd(res_xml,"<number class_hint=\"%s\">%d</number>", hint, (int)x);
291 buffer_fadd(res_xml,"<number class_hint=\"%s\">%lf</number>", hint, x);
294 buffer_fadd(res_xml,"<number>%d</number>", (int)x);
296 buffer_fadd(res_xml,"<number>%lf</number>", x);
299 } else if (obj->type == JSON_ARRAY) {
302 buffer_fadd(res_xml,"<array class_hint=\"%s\">", hint);
304 buffer_add(res_xml,"<array>");
307 for ( i = 0; i!= obj->size; i++ )
308 _recurse_jsonObjectToXML(jsonObjectGetIndex(obj,i), res_xml);
310 buffer_add(res_xml,"</array>");
312 } else if (obj->type == JSON_HASH) {
315 buffer_fadd(res_xml,"<object class_hint=\"%s\">", hint);
317 buffer_add(res_xml,"<object>");
319 jsonIterator* itr = jsonNewIterator(obj);
320 const jsonObject* tmp;
321 while( (tmp = jsonIteratorNext(itr)) ) {
322 buffer_fadd(res_xml,"<element key=\"%s\">",itr->key);
323 _recurse_jsonObjectToXML(tmp, res_xml);
324 buffer_add(res_xml,"</element>");
326 jsonIteratorFree(itr);
328 buffer_add(res_xml,"</object>");
337 static char* _escape_xml (const char* text) {
338 growing_buffer* b = buffer_init(256);
339 int len = strlen(text);
341 for (i = 0; i < len; i++) {
343 buffer_add(b,"&");
344 else if (text[i] == '<')
345 buffer_add(b,"<");
346 else if (text[i] == '>')
347 buffer_add(b,">");
349 buffer_add_char(b,text[i]);
351 return buffer_release(b);