|  | /* | 
|  | * gjobread.c : a small test program for gnome jobs XML format | 
|  | * | 
|  | * See Copyright for the status of this software. | 
|  | * | 
|  | * Daniel.Veillard@w3.org | 
|  | */ | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  | #include <stdlib.h> | 
|  |  | 
|  | /* | 
|  | * This example should compile and run indifferently with libxml-1.8.8 + | 
|  | * and libxml2-2.1.0 + | 
|  | * Check the COMPAT comments below | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * COMPAT using xml-config --cflags to get the include path this will | 
|  | * work with both | 
|  | */ | 
|  | #include <libxml/xmlmemory.h> | 
|  | #include <libxml/parser.h> | 
|  |  | 
|  | #define DEBUG(x) printf(x) | 
|  |  | 
|  | /* | 
|  | * A person record | 
|  | * an xmlChar * is really an UTF8 encoded char string (0 terminated) | 
|  | */ | 
|  | typedef struct person { | 
|  | xmlChar *name; | 
|  | xmlChar *email; | 
|  | xmlChar *company; | 
|  | xmlChar *organisation; | 
|  | xmlChar *smail; | 
|  | xmlChar *webPage; | 
|  | xmlChar *phone; | 
|  | } person, *personPtr; | 
|  |  | 
|  | /* | 
|  | * And the code needed to parse it | 
|  | */ | 
|  | static personPtr | 
|  | parsePerson(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) { | 
|  | personPtr ret = NULL; | 
|  |  | 
|  | DEBUG("parsePerson\n"); | 
|  | /* | 
|  | * allocate the struct | 
|  | */ | 
|  | ret = (personPtr) malloc(sizeof(person)); | 
|  | if (ret == NULL) { | 
|  | fprintf(stderr,"out of memory\n"); | 
|  | return(NULL); | 
|  | } | 
|  | memset(ret, 0, sizeof(person)); | 
|  |  | 
|  | /* We don't care what the top level element name is */ | 
|  | /* COMPAT xmlChildrenNode is a macro unifying libxml1 and libxml2 names */ | 
|  | cur = cur->xmlChildrenNode; | 
|  | while (cur != NULL) { | 
|  | if ((!xmlStrcmp(cur->name, (const xmlChar *)"Person")) && | 
|  | (cur->ns == ns)) | 
|  | ret->name = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); | 
|  | if ((!xmlStrcmp(cur->name, (const xmlChar *)"Email")) && | 
|  | (cur->ns == ns)) | 
|  | ret->email = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); | 
|  | cur = cur->next; | 
|  | } | 
|  |  | 
|  | return(ret); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * and to print it | 
|  | */ | 
|  | static void | 
|  | printPerson(personPtr cur) { | 
|  | if (cur == NULL) return; | 
|  | printf("------ Person\n"); | 
|  | if (cur->name) printf("	name: %s\n", cur->name); | 
|  | if (cur->email) printf("	email: %s\n", cur->email); | 
|  | if (cur->company) printf("	company: %s\n", cur->company); | 
|  | if (cur->organisation) printf("	organisation: %s\n", cur->organisation); | 
|  | if (cur->smail) printf("	smail: %s\n", cur->smail); | 
|  | if (cur->webPage) printf("	Web: %s\n", cur->webPage); | 
|  | if (cur->phone) printf("	phone: %s\n", cur->phone); | 
|  | printf("------\n"); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * a Description for a Job | 
|  | */ | 
|  | typedef struct job { | 
|  | xmlChar *projectID; | 
|  | xmlChar *application; | 
|  | xmlChar *category; | 
|  | personPtr contact; | 
|  | int nbDevelopers; | 
|  | personPtr developers[100]; /* using dynamic alloc is left as an exercise */ | 
|  | } job, *jobPtr; | 
|  |  | 
|  | /* | 
|  | * And the code needed to parse it | 
|  | */ | 
|  | static jobPtr | 
|  | parseJob(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) { | 
|  | jobPtr ret = NULL; | 
|  |  | 
|  | DEBUG("parseJob\n"); | 
|  | /* | 
|  | * allocate the struct | 
|  | */ | 
|  | ret = (jobPtr) malloc(sizeof(job)); | 
|  | if (ret == NULL) { | 
|  | fprintf(stderr,"out of memory\n"); | 
|  | return(NULL); | 
|  | } | 
|  | memset(ret, 0, sizeof(job)); | 
|  |  | 
|  | /* We don't care what the top level element name is */ | 
|  | cur = cur->xmlChildrenNode; | 
|  | while (cur != NULL) { | 
|  |  | 
|  | if ((!xmlStrcmp(cur->name, (const xmlChar *) "Project")) && | 
|  | (cur->ns == ns)) { | 
|  | ret->projectID = xmlGetProp(cur, (const xmlChar *) "ID"); | 
|  | if (ret->projectID == NULL) { | 
|  | fprintf(stderr, "Project has no ID\n"); | 
|  | } | 
|  | } | 
|  | if ((!xmlStrcmp(cur->name, (const xmlChar *) "Application")) && | 
|  | (cur->ns == ns)) | 
|  | ret->application = | 
|  | xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); | 
|  | if ((!xmlStrcmp(cur->name, (const xmlChar *) "Category")) && | 
|  | (cur->ns == ns)) | 
|  | ret->category = | 
|  | xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); | 
|  | if ((!xmlStrcmp(cur->name, (const xmlChar *) "Contact")) && | 
|  | (cur->ns == ns)) | 
|  | ret->contact = parsePerson(doc, ns, cur); | 
|  | cur = cur->next; | 
|  | } | 
|  |  | 
|  | return(ret); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * and to print it | 
|  | */ | 
|  | static void | 
|  | printJob(jobPtr cur) { | 
|  | int i; | 
|  |  | 
|  | if (cur == NULL) return; | 
|  | printf("=======  Job\n"); | 
|  | if (cur->projectID != NULL) printf("projectID: %s\n", cur->projectID); | 
|  | if (cur->application != NULL) printf("application: %s\n", cur->application); | 
|  | if (cur->category != NULL) printf("category: %s\n", cur->category); | 
|  | if (cur->contact != NULL) printPerson(cur->contact); | 
|  | printf("%d developers\n", cur->nbDevelopers); | 
|  |  | 
|  | for (i = 0;i < cur->nbDevelopers;i++) printPerson(cur->developers[i]); | 
|  | printf("======= \n"); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * A pool of Gnome Jobs | 
|  | */ | 
|  | typedef struct gjob { | 
|  | int nbJobs; | 
|  | jobPtr jobs[500]; /* using dynamic alloc is left as an exercise */ | 
|  | } gJob, *gJobPtr; | 
|  |  | 
|  |  | 
|  | static gJobPtr | 
|  | parseGjobFile(char *filename) { | 
|  | xmlDocPtr doc; | 
|  | gJobPtr ret; | 
|  | jobPtr curjob; | 
|  | xmlNsPtr ns; | 
|  | xmlNodePtr cur; | 
|  |  | 
|  | #ifdef LIBXML_SAX1_ENABLED | 
|  | /* | 
|  | * build an XML tree from a the file; | 
|  | */ | 
|  | doc = xmlParseFile(filename); | 
|  | if (doc == NULL) return(NULL); | 
|  | #else | 
|  | /* | 
|  | * the library has been compiled without some of the old interfaces | 
|  | */ | 
|  | return(NULL); | 
|  | #endif /* LIBXML_SAX1_ENABLED */ | 
|  |  | 
|  | /* | 
|  | * Check the document is of the right kind | 
|  | */ | 
|  |  | 
|  | cur = xmlDocGetRootElement(doc); | 
|  | if (cur == NULL) { | 
|  | fprintf(stderr,"empty document\n"); | 
|  | xmlFreeDoc(doc); | 
|  | return(NULL); | 
|  | } | 
|  | ns = xmlSearchNsByHref(doc, cur, | 
|  | (const xmlChar *) "http://www.gnome.org/some-location"); | 
|  | if (ns == NULL) { | 
|  | fprintf(stderr, | 
|  | "document of the wrong type, GJob Namespace not found\n"); | 
|  | xmlFreeDoc(doc); | 
|  | return(NULL); | 
|  | } | 
|  | if (xmlStrcmp(cur->name, (const xmlChar *) "Helping")) { | 
|  | fprintf(stderr,"document of the wrong type, root node != Helping"); | 
|  | xmlFreeDoc(doc); | 
|  | return(NULL); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Allocate the structure to be returned. | 
|  | */ | 
|  | ret = (gJobPtr) malloc(sizeof(gJob)); | 
|  | if (ret == NULL) { | 
|  | fprintf(stderr,"out of memory\n"); | 
|  | xmlFreeDoc(doc); | 
|  | return(NULL); | 
|  | } | 
|  | memset(ret, 0, sizeof(gJob)); | 
|  |  | 
|  | /* | 
|  | * Now, walk the tree. | 
|  | */ | 
|  | /* First level we expect just Jobs */ | 
|  | cur = cur->xmlChildrenNode; | 
|  | while ( cur && xmlIsBlankNode ( cur ) ) { | 
|  | cur = cur -> next; | 
|  | } | 
|  | if ( cur == 0 ) { | 
|  | xmlFreeDoc(doc); | 
|  | free(ret); | 
|  | return ( NULL ); | 
|  | } | 
|  | if ((xmlStrcmp(cur->name, (const xmlChar *) "Jobs")) || (cur->ns != ns)) { | 
|  | fprintf(stderr,"document of the wrong type, was '%s', Jobs expected", | 
|  | cur->name); | 
|  | fprintf(stderr,"xmlDocDump follows\n"); | 
|  | #ifdef LIBXML_OUTPUT_ENABLED | 
|  | xmlDocDump ( stderr, doc ); | 
|  | fprintf(stderr,"xmlDocDump finished\n"); | 
|  | #endif /* LIBXML_OUTPUT_ENABLED */ | 
|  | xmlFreeDoc(doc); | 
|  | free(ret); | 
|  | return(NULL); | 
|  | } | 
|  |  | 
|  | /* Second level is a list of Job, but be laxist */ | 
|  | cur = cur->xmlChildrenNode; | 
|  | while (cur != NULL) { | 
|  | if ((!xmlStrcmp(cur->name, (const xmlChar *) "Job")) && | 
|  | (cur->ns == ns)) { | 
|  | curjob = parseJob(doc, ns, cur); | 
|  | if (curjob != NULL) | 
|  | ret->jobs[ret->nbJobs++] = curjob; | 
|  | if (ret->nbJobs >= 500) break; | 
|  | } | 
|  | cur = cur->next; | 
|  | } | 
|  |  | 
|  | return(ret); | 
|  | } | 
|  |  | 
|  | static void | 
|  | handleGjob(gJobPtr cur) { | 
|  | int i; | 
|  |  | 
|  | /* | 
|  | * Do whatever you want and free the structure. | 
|  | */ | 
|  | printf("%d Jobs registered\n", cur->nbJobs); | 
|  | for (i = 0; i < cur->nbJobs; i++) printJob(cur->jobs[i]); | 
|  | } | 
|  |  | 
|  | int main(int argc, char **argv) { | 
|  | int i; | 
|  | gJobPtr cur; | 
|  |  | 
|  | /* COMPAT: Do not genrate nodes for formatting spaces */ | 
|  | LIBXML_TEST_VERSION | 
|  | xmlKeepBlanksDefault(0); | 
|  |  | 
|  | for (i = 1; i < argc ; i++) { | 
|  | cur = parseGjobFile(argv[i]); | 
|  | if ( cur ) | 
|  | handleGjob(cur); | 
|  | else | 
|  | fprintf( stderr, "Error parsing file '%s'\n", argv[i]); | 
|  |  | 
|  | } | 
|  |  | 
|  | /* Clean up everything else before quitting. */ | 
|  | xmlCleanupParser(); | 
|  |  | 
|  | return(0); | 
|  | } |