1/*
2 * gjobread.c : a small test program for gnome jobs XML format
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel.Veillard@w3.org
7 */
8
9#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12
13/*
14 * This example should compile and run indifferently with libxml-1.8.8 +
15 * and libxml2-2.1.0 +
16 * Check the COMPAT comments below
17 */
18
19/*
20 * COMPAT using xml-config --cflags to get the include path this will
21 * work with both
22 */
23#include <libxml/xmlmemory.h>
24#include <libxml/parser.h>
25
26#define DEBUG(x) printf(x)
27
28/*
29 * A person record
30 * an xmlChar * is really an UTF8 encoded char string (0 terminated)
31 */
32typedef struct person {
33    xmlChar *name;
34    xmlChar *email;
35    xmlChar *company;
36    xmlChar *organisation;
37    xmlChar *smail;
38    xmlChar *webPage;
39    xmlChar *phone;
40} person, *personPtr;
41
42/*
43 * And the code needed to parse it
44 */
45static personPtr
46parsePerson(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) {
47    personPtr ret = NULL;
48
49DEBUG("parsePerson\n");
50    /*
51     * allocate the struct
52     */
53    ret = (personPtr) malloc(sizeof(person));
54    if (ret == NULL) {
55        fprintf(stderr,"out of memory\n");
56	return(NULL);
57    }
58    memset(ret, 0, sizeof(person));
59
60    /* We don't care what the top level element name is */
61    /* COMPAT xmlChildrenNode is a macro unifying libxml1 and libxml2 names */
62    cur = cur->xmlChildrenNode;
63    while (cur != NULL) {
64        if ((!xmlStrcmp(cur->name, (const xmlChar *)"Person")) &&
65	    (cur->ns == ns))
66	    ret->name = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
67        if ((!xmlStrcmp(cur->name, (const xmlChar *)"Email")) &&
68	    (cur->ns == ns))
69	    ret->email = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
70	cur = cur->next;
71    }
72
73    return(ret);
74}
75
76/*
77 * and to print it
78 */
79static void
80printPerson(personPtr cur) {
81    if (cur == NULL) return;
82    printf("------ Person\n");
83    if (cur->name) printf("	name: %s\n", cur->name);
84    if (cur->email) printf("	email: %s\n", cur->email);
85    if (cur->company) printf("	company: %s\n", cur->company);
86    if (cur->organisation) printf("	organisation: %s\n", cur->organisation);
87    if (cur->smail) printf("	smail: %s\n", cur->smail);
88    if (cur->webPage) printf("	Web: %s\n", cur->webPage);
89    if (cur->phone) printf("	phone: %s\n", cur->phone);
90    printf("------\n");
91}
92
93/*
94 * a Description for a Job
95 */
96typedef struct job {
97    xmlChar *projectID;
98    xmlChar *application;
99    xmlChar *category;
100    personPtr contact;
101    int nbDevelopers;
102    personPtr developers[100]; /* using dynamic alloc is left as an exercise */
103} job, *jobPtr;
104
105/*
106 * And the code needed to parse it
107 */
108static jobPtr
109parseJob(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) {
110    jobPtr ret = NULL;
111
112DEBUG("parseJob\n");
113    /*
114     * allocate the struct
115     */
116    ret = (jobPtr) malloc(sizeof(job));
117    if (ret == NULL) {
118        fprintf(stderr,"out of memory\n");
119	return(NULL);
120    }
121    memset(ret, 0, sizeof(job));
122
123    /* We don't care what the top level element name is */
124    cur = cur->xmlChildrenNode;
125    while (cur != NULL) {
126
127        if ((!xmlStrcmp(cur->name, (const xmlChar *) "Project")) &&
128	    (cur->ns == ns)) {
129	    ret->projectID = xmlGetProp(cur, (const xmlChar *) "ID");
130	    if (ret->projectID == NULL) {
131		fprintf(stderr, "Project has no ID\n");
132	    }
133	}
134        if ((!xmlStrcmp(cur->name, (const xmlChar *) "Application")) &&
135            (cur->ns == ns))
136	    ret->application =
137		xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
138        if ((!xmlStrcmp(cur->name, (const xmlChar *) "Category")) &&
139	    (cur->ns == ns))
140	    ret->category =
141		xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
142        if ((!xmlStrcmp(cur->name, (const xmlChar *) "Contact")) &&
143	    (cur->ns == ns))
144	    ret->contact = parsePerson(doc, ns, cur);
145	cur = cur->next;
146    }
147
148    return(ret);
149}
150
151/*
152 * and to print it
153 */
154static void
155printJob(jobPtr cur) {
156    int i;
157
158    if (cur == NULL) return;
159    printf("=======  Job\n");
160    if (cur->projectID != NULL) printf("projectID: %s\n", cur->projectID);
161    if (cur->application != NULL) printf("application: %s\n", cur->application);
162    if (cur->category != NULL) printf("category: %s\n", cur->category);
163    if (cur->contact != NULL) printPerson(cur->contact);
164    printf("%d developers\n", cur->nbDevelopers);
165
166    for (i = 0;i < cur->nbDevelopers;i++) printPerson(cur->developers[i]);
167    printf("======= \n");
168}
169
170/*
171 * A pool of Gnome Jobs
172 */
173typedef struct gjob {
174    int nbJobs;
175    jobPtr jobs[500]; /* using dynamic alloc is left as an exercise */
176} gJob, *gJobPtr;
177
178
179static gJobPtr
180parseGjobFile(char *filename ATTRIBUTE_UNUSED) {
181    xmlDocPtr doc;
182    gJobPtr ret;
183    jobPtr curjob;
184    xmlNsPtr ns;
185    xmlNodePtr cur;
186
187#ifdef LIBXML_SAX1_ENABLED
188    /*
189     * build an XML tree from a the file;
190     */
191    doc = xmlParseFile(filename);
192    if (doc == NULL) return(NULL);
193#else
194    /*
195     * the library has been compiled without some of the old interfaces
196     */
197    return(NULL);
198#endif /* LIBXML_SAX1_ENABLED */
199
200    /*
201     * Check the document is of the right kind
202     */
203
204    cur = xmlDocGetRootElement(doc);
205    if (cur == NULL) {
206        fprintf(stderr,"empty document\n");
207	xmlFreeDoc(doc);
208	return(NULL);
209    }
210    ns = xmlSearchNsByHref(doc, cur,
211	    (const xmlChar *) "http://www.gnome.org/some-location");
212    if (ns == NULL) {
213        fprintf(stderr,
214	        "document of the wrong type, GJob Namespace not found\n");
215	xmlFreeDoc(doc);
216	return(NULL);
217    }
218    if (xmlStrcmp(cur->name, (const xmlChar *) "Helping")) {
219        fprintf(stderr,"document of the wrong type, root node != Helping");
220	xmlFreeDoc(doc);
221	return(NULL);
222    }
223
224    /*
225     * Allocate the structure to be returned.
226     */
227    ret = (gJobPtr) malloc(sizeof(gJob));
228    if (ret == NULL) {
229        fprintf(stderr,"out of memory\n");
230	xmlFreeDoc(doc);
231	return(NULL);
232    }
233    memset(ret, 0, sizeof(gJob));
234
235    /*
236     * Now, walk the tree.
237     */
238    /* First level we expect just Jobs */
239    cur = cur->xmlChildrenNode;
240    while ( cur && xmlIsBlankNode ( cur ) ) {
241	cur = cur -> next;
242    }
243    if ( cur == 0 ) {
244	xmlFreeDoc(doc);
245	free(ret);
246	return ( NULL );
247    }
248    if ((xmlStrcmp(cur->name, (const xmlChar *) "Jobs")) || (cur->ns != ns)) {
249        fprintf(stderr,"document of the wrong type, was '%s', Jobs expected",
250		cur->name);
251	fprintf(stderr,"xmlDocDump follows\n");
252#ifdef LIBXML_OUTPUT_ENABLED
253	xmlDocDump ( stderr, doc );
254	fprintf(stderr,"xmlDocDump finished\n");
255#endif /* LIBXML_OUTPUT_ENABLED */
256	xmlFreeDoc(doc);
257	free(ret);
258	return(NULL);
259    }
260
261    /* Second level is a list of Job, but be laxist */
262    cur = cur->xmlChildrenNode;
263    while (cur != NULL) {
264        if ((!xmlStrcmp(cur->name, (const xmlChar *) "Job")) &&
265	    (cur->ns == ns)) {
266	    curjob = parseJob(doc, ns, cur);
267	    if (curjob != NULL)
268	        ret->jobs[ret->nbJobs++] = curjob;
269            if (ret->nbJobs >= 500) break;
270	}
271	cur = cur->next;
272    }
273
274    return(ret);
275}
276
277static void
278handleGjob(gJobPtr cur) {
279    int i;
280
281    /*
282     * Do whatever you want and free the structure.
283     */
284    printf("%d Jobs registered\n", cur->nbJobs);
285    for (i = 0; i < cur->nbJobs; i++) printJob(cur->jobs[i]);
286}
287
288int main(int argc, char **argv) {
289    int i;
290    gJobPtr cur;
291
292    /* COMPAT: Do not genrate nodes for formatting spaces */
293    LIBXML_TEST_VERSION
294    xmlKeepBlanksDefault(0);
295
296    for (i = 1; i < argc ; i++) {
297	cur = parseGjobFile(argv[i]);
298	if ( cur )
299	  handleGjob(cur);
300	else
301	  fprintf( stderr, "Error parsing file '%s'\n", argv[i]);
302
303    }
304
305    /* Clean up everything else before quitting. */
306    xmlCleanupParser();
307
308    return(0);
309}
310