added basic xpath support to JSON
authorerickson <erickson@9efc2488-bf62-4759-914b-345cdb29e865>
Thu, 25 Aug 2005 03:27:36 +0000 (03:27 +0000)
committererickson <erickson@9efc2488-bf62-4759-914b-345cdb29e865>
Thu, 25 Aug 2005 03:27:36 +0000 (03:27 +0000)
added some utility functions

git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@501 9efc2488-bf62-4759-914b-345cdb29e865

src/objson/json_parser.c
src/objson/json_parser.h
src/objson/object.c
src/objson/object.h
src/utils/utils.c
src/utils/utils.h

index a3e4692..9f3221d 100644 (file)
@@ -722,3 +722,14 @@ int json_handle_error(char* string, unsigned long* index, char* err_msg) {
 }
 
 
+object* json_parse_file(char* filename) {
+       if(!filename) return NULL;
+       char* data = file_to_string(filename);
+       object* o = json_parse_string(data);
+       free(data);
+       return o;
+}
+
+
+
+
index 5fb7d6b..a2a6ec6 100644 (file)
@@ -33,6 +33,7 @@ GNU General Public License for more details.
  */
 object* json_parse_string(char* string);
 
+object* json_parse_file(char* filename);
 
 
 
index ff41eaa..cea3d87 100644 (file)
@@ -639,3 +639,112 @@ int object_iterator_has_next(object_iterator* itr) {
 }
 
 
+object* object_find_path(object* obj, char* format, ...) {
+       if(!obj || !format || strlen(format) < 1) return NULL;  
+
+       /* build the string from the variable args */
+       long len = 0;
+       va_list args, a_copy;
+
+       va_copy(a_copy, args);
+
+       va_start(args, format);
+       len = va_list_size(format, args);
+       char buf[len];
+       bzero(buf, len);
+
+       va_start(a_copy, format);
+       vsnprintf(buf, len - 1, format, a_copy);
+       va_end(a_copy);
+       /* -------------------------------------------- */
+
+
+       /* tmp storage for strtok_r */
+       char tokbuf[len];               
+       bzero(tokbuf, len);
+
+       char* token = NULL;
+       char* t = buf;
+       char* tt = tokbuf;
+
+       char* pathcopy = strdup(buf);
+
+       /* grab the root of the path */
+       token = strtok_r(t, "/", &tt);
+       t = NULL;
+       if(!token) return NULL;
+
+       /* special case where path starts with //  (start anywhere) */
+       if(strlen(pathcopy) > 2 && pathcopy[0] == '/' && pathcopy[1] == '/') {
+               object* it = _object_find_path_recurse(obj, token, pathcopy + 1);
+               free(pathcopy);
+               return it;
+       }
+
+       free(pathcopy);
+
+       do { 
+               obj = obj->get_key(obj, token);
+       } while( (token = strtok_r(NULL, "/", &tt)) && obj);
+
+       return object_clone(obj);
+}
+
+
+
+object* _object_find_path_recurse(object* obj, char* root, char* path) {
+
+       if(!obj || ! root) return NULL;
+       object* arr = __object_find_path_recurse(obj, root);
+       object* newarr = json_parse_string("[]");
+
+       int i;
+
+       /* path is just /root or /root/ */
+       if( strlen(root) + 2 >= strlen(path) ) {
+               return arr;
+       } else {
+
+               for( i = 0; i < arr->size; i++ ) {
+                       /*
+                       fprintf(stderr, "Searching root %s and path %s and size %ld\n", root, path + strlen(root) + 1, arr->size);
+                       */
+                       object* a = arr->get_index(arr, i);
+                       object* thing = object_find_path(a , path + strlen(root) + 1); 
+                       if(thing) newarr->push(newarr, thing);
+               }
+       }
+       
+       free_object(arr);
+       return newarr;
+}
+
+object* __object_find_path_recurse(object* obj, char* root) {
+
+       object* arr = json_parse_string("[]");
+       if(!obj) return arr;
+       object* o = obj->get_key(obj, root);
+       if(o) arr->push(arr, object_clone(o));
+
+       object_node* tmp = NULL;
+       object* childarr;
+       object_iterator* itr = new_iterator(obj);
+
+       while( (tmp = itr->next(itr)) ) {
+               childarr = __object_find_path_recurse(tmp->item, root);
+               if(childarr && childarr->size > 0) {
+                       int i;
+                       for( i = 0; i!= childarr->size; i++ ) {
+                               arr->push(arr, object_clone(childarr->get_index(childarr, i)));
+                       }
+               }
+
+               free_object(childarr);
+       }
+
+       free_iterator(itr);
+
+       return arr;
+}
+
+
index f9925c2..8209de1 100644 (file)
@@ -219,4 +219,19 @@ char* json_string_format(char* json);
 object* object_clone(object* o);
 
 
+/* provide an XPATH style path (e.g. /some/node/here) and this will 
+       return the object at that location if one exists.  Naturally,  
+       every element in the path must be a proper object ("hash" / {}).
+       Returns NULL if the specified node is not found 
+       Note also that the object returned is a clone and
+       must be freed by the caller
+*/
+object* object_find_path(object* obj, char* format, ...);
+
+
+/* returns an object array of matches */
+object* _object_find_path_recurse(object* obj, char* root, char* path);
+object* __object_find_path_recurse(object* obj, char* root);
+
+
 #endif
index 1d79de3..9c0a3c2 100644 (file)
@@ -83,16 +83,22 @@ int clr_fl( int fd, int flags ) {
        return 0;
 }
 
+long va_list_size(const char* format, va_list args) {
+       int len = 0;
+       len = vsnprintf(NULL, 0, format, args);
+       va_end(args);
+       len += 2;
+       return len;
+}
+
+
 // ---------------------------------------------------------------------------------
 // Flesh out a ubiqitous growing string buffer
 // ---------------------------------------------------------------------------------
 
 growing_buffer* buffer_init(int num_initial_bytes) {
 
-       if( num_initial_bytes > BUFFER_MAX_SIZE ) {
-               return NULL;
-       }
-
+       if( num_initial_bytes > BUFFER_MAX_SIZE ) return NULL;
 
        size_t len = sizeof(growing_buffer);
 
@@ -105,23 +111,19 @@ growing_buffer* buffer_init(int num_initial_bytes) {
        return gb;
 }
 
+
 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
 
        if(!gb || !format) return 0; 
 
-       int len = 0;
+       long len = 0;
        va_list args;
        va_list a_copy;
 
-       //char* f_copy = strdup(format);
-
        va_copy(a_copy, args);
 
        va_start(args, format);
-       len = vsnprintf(NULL, 0, format, args);
-       va_end(args);
-
-       len += 2;
+       len = va_list_size(format, args);
 
        char buf[len];
        memset(buf, 0, len);
@@ -130,8 +132,6 @@ int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
        vsnprintf(buf, len - 1, format, a_copy);
        va_end(a_copy);
 
-       //free(f_copy);
-
        return buffer_add(gb, buf);
 
 }
@@ -309,15 +309,16 @@ char* uescape( const char* string, int size, int full_escape ) {
 // A function to turn a process into a daemon and set it's process name in ps/top
 int daemonize() {
        int f = fork();
+
        if (f == -1) {
                perror("Failed to fork!");
                return -1;
-       } else if (f == 0) {
-               // We're in the child now...
+
+       } else if (f == 0) { // We're in the child now...
                setsid();
                return 0;
-       } else {
-               // We're in the parent...
+
+       } else { // We're in the parent...
                exit(0);
        }
 }
@@ -332,3 +333,29 @@ int stringisnum(char* s) {
 }
        
 
+
+char* file_to_string(char* filename) {
+
+       if(!filename) return NULL;
+
+       int len = 1024;
+       char buf[len];
+       bzero(buf, len);
+       growing_buffer* gb = buffer_init(len);
+
+       FILE* file = fopen(filename, "r");
+       if(!file) {
+               perror("Unable to open file in json_parse_file()");
+               return NULL;
+       }
+
+       while(fgets(buf, len - 1, file)) {
+               buffer_add(gb, buf);
+               bzero(buf, len);
+       }
+
+       char* data = buffer_data(gb);
+       buffer_free(gb);
+       return data;
+}
+
index 894faf3..af09795 100644 (file)
@@ -52,6 +52,11 @@ char* buffer_data( growing_buffer* gb);
 int buffer_free( growing_buffer* gb );
 int buffer_add_char(growing_buffer* gb, char c);
 
+/* returns the size needed to fill in the vsnprintf buffer.  
+       * ! this calls va_end on the va_list argument*
+       */
+long va_list_size(const char* format, va_list);
+
 
 /* string escape utility method.  escapes unicode embeded characters.
        escapes the usual \n, \t, etc. 
@@ -79,6 +84,11 @@ double get_timestamp_millis();
 /* returns true if the whole string is a number */
 int stringisnum(char* s);
 
+/* reads a file and returns the string version of the file
+       user is responsible for freeing the returned char*
+       */
+char* file_to_string(char* filename);
+