Annotation of rpm2html/rdf_api.c, revision 1.8
1.1 veillard 1: /*
2: * rdf_api.h : implementation of methods to read and write RDF schemas
1.6 veillard 3: *
4: * See Copyright for the status of this software.
5: *
1.8 ! daniel 6: * $Id: rdf_api.c,v 1.3 1998/08/06 04:18:12 daniel Exp $
1.1 veillard 7: */
8:
9: #include <stdio.h>
10: #include <string.h>
11: #include <malloc.h>
12: #include <errno.h>
13: #include "rpmdata.h"
14: #include "rdf_api.h"
15:
16: /*
17: * Reading an RDF schema stored in a file, this just build the
18: * document tree, and check that it's an RDF:RDf element.
19: */
20: rdfSchema rdfRead(const char *filename) {
21: xmlDocPtr res;
22:
23: res = xmlParseFile(filename);
24: if (res == NULL) return(NULL);
25: if (res->root == NULL) {
26: fprintf(stderr, "rdfRead %s: tree is empty\n", filename);
27: xmlFreeDoc(res);
28: return(NULL);
29: }
30: if (strcmp(res->root->name, "RDF")) {
31: fprintf(stderr, "rdfRead %s: not an RDF file\n", filename);
32: xmlFreeDoc(res);
33: return(NULL);
34: }
35: return((rdfSchema) res);
36: }
37:
38: /*
39: * Writing an RDF schema to a file, this just save the
40: * document tree as an XML document.
41: */
42: void rdfWrite(rdfSchema rdf, const char *filename) {
43: FILE *output;
44:
45: output = fopen(filename, "w");
46: if (output == NULL) {
47: fprintf(stderr, "rdfWrite : couldn't save to file %s: %s\n",
48: filename, strerror(errno));
49: return;
50: }
51: xmlDocDump(output, (xmlDocPtr) rdf);
52: fclose(output);
53: }
54:
55: /*
1.4 veillard 56: * Writing an RDF schema to a memory buffer, this just save the
57: * document tree as an XML document.
58: */
59: void rdfWriteMemory(rdfSchema rdf, char **buffer, int *size) {
60: xmlDocDumpMemory((xmlDocPtr) rdf, (CHAR **) buffer, size);
61: }
62:
63: /*
1.2 veillard 64: * Creating an RDF schema tree in memory.
1.1 veillard 65: */
66: rdfSchema rdfNewSchema() {
67: xmlDocPtr res;
1.8 ! daniel 68: xmlNsPtr rdf;
1.1 veillard 69:
70: res = xmlNewDoc("1.0");
1.8 ! daniel 71: rdf = xmlNewNs(res, "http://www.w3.org/TR/WD-rdf-syntax#", "RDF");
1.1 veillard 72: res->root = xmlNewNode(rdf, strdup("RDF"), NULL);
73:
74: return((rdfSchema) res);
75: }
76:
77: /*
78: * Adding a new namespace to an RDF schema.
79: */
1.8 ! daniel 80: rdfNamespace rdfNewNamespace(rdfSchema rdf, const char *url,
! 81: const char *namespace) {
! 82: xmlNsPtr ns;
1.1 veillard 83:
1.8 ! daniel 84: ns = xmlNewNs(rdf, url, namespace);
1.1 veillard 85:
1.8 ! daniel 86: return((rdfNamespace) ns);
1.1 veillard 87: }
88:
89: /*
90: * Get a namespace associated to an RDF schema.
91: */
92: rdfNamespace rdfGetNamespace(rdfSchema rdf, const char *href) {
1.8 ! daniel 93: xmlNsPtr ns;
1.1 veillard 94:
1.8 ! daniel 95: ns = rdf->nss;
! 96: while (ns != NULL) {
! 97: if (!strcmp(ns->href, href))
! 98: return((rdfNamespace) ns);
! 99: ns = ns->next;
1.1 veillard 100: }
101: return(NULL);
102: }
103:
104: /*
105: * Get the RDF namespace associated to an RDF schema.
106: */
107: rdfNamespace rdfGetRdfNamespace(rdfSchema rdf) {
1.8 ! daniel 108: xmlNsPtr ns;
1.1 veillard 109:
1.8 ! daniel 110: ns = rdf->nss;
! 111: while (ns != NULL) {
! 112: if (!strcmp(ns->href, "http://www.w3.org/TR/WD-rdf-syntax#"))
! 113: return((rdfNamespace) ns);
! 114: ns = ns->next;
1.1 veillard 115: }
116: /* create it ! */
117: return(rdfNewNamespace(rdf, "http://www.w3.org/TR/WD-rdf-syntax#", "RDF"));
118: }
119:
120:
121: /*
122: * Destroying an RDF schema in memory.
123: */
124: void rdfDestroySchema(rdfSchema rdf) {
125: xmlFreeDoc((xmlDocPtr) rdf);
126: }
127:
128: /**
129: ** An RDF schema is a collection of RDF descriptions.
130: ** The following are used to browse the list.
131: **/
132:
133: /* First item */
134: rdfDescription rdfFirstDescription(rdfSchema schema) {
135: xmlNodePtr tree;
136: rdfNamespace rdfNs;
137:
138: rdfNs = rdfGetRdfNamespace(schema);
139: tree = schema->root;
140: if (tree == NULL) return(NULL);
141: tree = tree->childs;
142: while (tree != NULL) {
1.8 ! daniel 143: if ((tree->ns == rdfNs) && (!strcmp(tree->name, "Description")))
1.1 veillard 144: return(tree);
145: tree = tree->next;
146: }
147: return(NULL);
148: }
149:
150: /* Iteration : next item */
151: rdfDescription rdfNextDescription(rdfDescription desc) {
152: rdfNamespace rdfNs;
153:
154: if (desc == NULL) return(NULL);
1.8 ! daniel 155: rdfNs = desc->ns;
1.1 veillard 156: desc = desc->next;
157: while (desc != NULL) {
1.8 ! daniel 158: if ((desc->ns == rdfNs) && (!strcmp(desc->name, "Description")))
1.1 veillard 159: return(desc);
160: desc = desc->next;
161: }
162: return(NULL);
163: }
164:
165: /*
166: * Add an RDF description to an RDF schema, it just link it
167: * the top level node of the description and requires further
168: * action to fill it with the pertinent informations.
169: */
170: rdfDescription rdfAddDescription(rdfSchema schema, const char *id,
1.7 veillard 171: const char *about) {
1.1 veillard 172: xmlNodePtr tree;
173:
174: tree = xmlNewChild(schema->root, NULL, strdup("Description"), NULL);
175: if (id != NULL) {
176: xmlNewProp(tree, "ID", id);
177: }
1.7 veillard 178: if (about != NULL) {
179: if (oldXMLWDcompatibility) {
1.8 ! daniel 180: rdfNamespace ns;
1.7 veillard 181: char *buf;
182:
1.8 ! daniel 183: ns = rdfGetRdfNamespace(schema);
! 184: buf = (char *) malloc(strlen(ns->prefix) + 10);
! 185: sprintf(buf, "%s:HREF", ns->prefix);
1.7 veillard 186: xmlNewProp(tree, buf, about);
187: free(buf);
188: } else {
189: xmlNewProp(tree, "about", about);
190: }
1.1 veillard 191: }
192: return((rdfDescription) tree);
193: }
194:
1.5 veillard 195: /*
196: * Read the attributes of a Description node.
197: */
198: char *rdfGetDescriptionId(rdfSchema schema, rdfDescription desc) {
199: char *res;
200:
201: res = (char *) xmlGetProp(desc, "ID");
202: return(res);
203: }
204:
1.7 veillard 205: char *rdfGetDescriptionAbout(rdfSchema schema, rdfDescription desc) {
1.5 veillard 206: char *res;
1.8 ! daniel 207: rdfNamespace ns;
1.5 veillard 208: char *buf;
209:
1.7 veillard 210: res = (char *) xmlGetProp(desc, "about");
211: if (res != NULL) return(res);
212:
213: /*
214: * Maintain compatibility with old "RDF:HREF"
215: */
1.8 ! daniel 216: res = (char *) xmlGetProp(desc, "HREF");
! 217: if (res != NULL) return(res);
! 218: ns = rdfGetRdfNamespace(schema);
! 219: buf = (char *) malloc(strlen(ns->prefix) + 10);
! 220: sprintf(buf, "%s:HREF", ns->prefix);
1.5 veillard 221: res = (char *) xmlGetProp(desc, buf);
222: free(buf);
223: return(res);
224: }
225:
1.7 veillard 226: /*
227: * Read any resource associated to an element.
228: */
229: char *rdfGetElementResource(rdfSchema schema, rdfElement elem) {
230: char *res;
231:
232: res = (char *) xmlGetProp(elem, "resource");
233: return(res);
234: }
235:
236: void rdfSetElementResource(rdfSchema schema, rdfElement elem, const char *URI) {
237: xmlSetProp(elem, "resource", URI);
238: }
239:
1.1 veillard 240: /**
241: ** Routines to read/write final values.
242: **/
243:
244: /*
245: * browse the various property pertaining to this description,
246: * and return the value which can be either a text (RDF_LEAF)
247: * or an rdfElement (RDF_BAG, RDF_SEQ, RDF_ALT, RDF_DESC).
248: * Having both reflect an invalid RDF document (while valid from
249: * XML point of view).
250: * This routine tries to ajust in case a request is done with or
251: * or without a ns present or not on the node, and if the names
252: * matches.
253: * e.g. a request for Name may return BIB:Name
254: * or a request for BIB:Name may return Name
255: * if the exact match is not found.
256: *
257: * Return -1 if not found
258: * 0 if a single value is found
259: * RDF_xxx if a node is found.
260: */
261: int rdfGetValue(rdfDescription desc, const char *property,
262: rdfNamespace ns, char **value, rdfElement *elem){
263: rdfElement list = desc->childs;
264: rdfElement best = NULL;
265: int approx = 0;
266:
267: if (value != NULL) *value = NULL;
268: if (elem != NULL) *elem = NULL;
269:
270: while (list != NULL) {
1.8 ! daniel 271: if ((list->ns == ns) && (!strcmp(list->name, property))) {
1.1 veillard 272: /*
273: * Found a perfect match, return it !
274: */
275: if ((list->content != NULL) && (list->childs != NULL)) {
276: fprintf(stderr,
277: "RDF Schema invalid, node %s has content and child(s)\n",
278: list->name);
279: }
280: if (value != NULL) *value = list->content;
281: if (elem != NULL) *elem = list->childs;
282: if (!strcmp(list->name, "Bag")) return(RDF_BAG);
283: if (!strcmp(list->name, "Seq")) return(RDF_SEQ);
284: if (!strcmp(list->name, "Alt")) return(RDF_ALT);
285: if (!strcmp(list->name, "Description")) return(RDF_DESC);
286: return(0);
287: }
1.8 ! daniel 288: else if (((list->ns == NULL) || (ns == NULL)) &&
1.1 veillard 289: (!strcmp(list->name, property))) {
290: /*
291: * If more than one "best" match exists, ignore them !
292: */
293: if (approx) {
294: best = NULL;
295: } else {
296: best = list;
297: approx = 1;
298: }
299: }
300: list = list->next;
301: }
302: if (best != NULL) {
303: if ((best->content != NULL) && (best->childs != NULL)) {
304: fprintf(stderr,
305: "RDF Schema invalid, node %s has content and child(s)\n",
306: best->name);
307: }
308: if (value != NULL) *value = best->content;
309: if (elem != NULL) *elem = best->childs;
310: if (!strcmp(best->name, "Bag")) return(RDF_BAG);
311: if (!strcmp(best->name, "Seq")) return(RDF_SEQ);
312: if (!strcmp(best->name, "Alt")) return(RDF_ALT);
313: if (!strcmp(best->name, "Description")) return(RDF_DESC);
314: return(0);
315: }
316: return(-1);
317: }
318:
319: /*
320: * browse the various property pertaining to this description,
321: * update the value if found on a text mode, otherwise append
322: * a new property at the end of the list.
323: * Note that contrary to GetValue, the check is absolute !
324: */
325: void rdfSetValue(rdfDescription desc, const char *property,
326: rdfNamespace ns, const char *value) {
327: rdfElement list = desc->childs;
328:
329: /*
330: * Search the property.
331: */
332: while (list != NULL) {
1.8 ! daniel 333: if ((list->ns == ns) && (!strcmp(list->name, property))) {
1.1 veillard 334: /*
335: * Property was found, update it !
336: */
337: if ((list->content != NULL) && (list->childs != NULL)) {
338: fprintf(stderr,
339: "RDF Schema invalid, node %s has content and child(s)\n",
340: list->name);
341: }
342: if (list->content != NULL) free(list->content);
343: if (list->childs == NULL) {
344: list->content = strdup(value);
345: }
346: return;
347: }
348: list = list->next;
349: }
350:
351: /*
352: * Create a new property.
353: */
1.4 veillard 354: xmlNewChild(desc, ns, strdup(property), (char *) value);
1.1 veillard 355: }
356:
357: /*
358: * browse the various property pertaining to this description,
359: * and if found remove and destroy the subtree.
360: */
361: void rdfRemoveProperty(rdfDescription desc, const char *property,
362: rdfNamespace ns) {
363: rdfElement list = desc->childs;
364: rdfElement prev = NULL;
365:
366: /*
367: * Search the property.
368: */
369: while (list != NULL) {
1.8 ! daniel 370: if ((list->ns == ns) && (!strcmp(list->name, property))) {
1.1 veillard 371: /*
372: * Property was found, delete it !
373: */
374: if (prev == NULL)
375: desc->childs = list->next;
376: else
377: prev->next = list->next;
378: list->next = NULL;
379:
380: xmlFreeNode(list);
381: return;
382: }
383: prev = list;
384: list = list->next;
385: }
386: }
387:
388: /**
389: ** Routines to read/write bags
390: **/
391:
392: /*
1.2 veillard 393: * Create a new Bag.
1.1 veillard 394: */
1.2 veillard 395: rdfBag rdfBagCreate(rdfSchema schema, rdfDescription desc,
396: const char *property, rdfNamespace ns) {
397: rdfElement cur;
398: rdfNamespace rdf;
399:
400: rdf = rdfGetRdfNamespace(schema);
1.3 veillard 401: cur = xmlNewChild(desc, ns, strdup(property), NULL);
1.2 veillard 402: cur = xmlNewChild(cur, rdf, strdup("Bag"), NULL);
403: return(cur);
1.1 veillard 404: }
405:
406: /*
1.2 veillard 407: * Add an element to a bag.
1.1 veillard 408: */
1.2 veillard 409: rdfElement rdfBagAddValue(rdfBag bag, const char *property,
1.4 veillard 410: rdfNamespace ns, const char *value, rdfElement elem) {
1.2 veillard 411: rdfElement cur;
412:
413: if (value != NULL)
1.4 veillard 414: cur = xmlNewChild(bag, ns, strdup(property), (char *) value);
1.2 veillard 415: else {
416: cur = xmlNewNode(ns, strdup(property), NULL);
1.7 veillard 417: if (elem != NULL)
418: xmlAddChild(cur, elem);
1.2 veillard 419: xmlAddChild(bag, cur);
420: }
421: return(cur);
1.1 veillard 422: }
423:
424: /**
425: ** Routines to walk bags and sequences.
426: **/
427: rdfElement rdfFirstChild(rdfElement bag) {
428: return(bag->childs);
429: }
430: rdfElement rdfNextElem(rdfElement desc) {
431: return(desc->next);
432: }
433:
434: /**
435: ** Direct access to Element values.
436: **/
437: int rdfElemGetType(rdfElement elem) {
438: if (!strcmp(elem->name, "Bag")) return(RDF_BAG);
439: if (!strcmp(elem->name, "Seq")) return(RDF_SEQ);
440: if (!strcmp(elem->name, "Alt")) return(RDF_ALT);
441: if (!strcmp(elem->name, "Description")) return(RDF_DESC);
442: return(0);
443: }
444:
445: char *rdfElemGetValue(rdfElement elem) {
446: return(elem->content);
447: }
1.4 veillard 448: const char *rdfElemGetPropertyName(rdfElement elem) {
1.1 veillard 449: return(elem->name);
1.3 veillard 450: }
451: rdfNamespace rdfElemGetNamespace(rdfElement elem) {
1.8 ! daniel 452: return(elem->ns);
1.1 veillard 453: }
454: void rdfElemSetValue(rdfElement elem, const char *value) {
455: if (elem->childs != NULL) {
456: fprintf(stderr, "rdfElemSetValue : elem %s has childs\n", elem->name);
457: return;
458: }
459: if (elem->content != NULL) free(elem->content);
460: elem->content = strdup(value);
461: }
462:
463: /************************************************************************
464: * *
465: * Debug *
466: * *
467: ************************************************************************/
468:
469: #ifdef DEBUG_RDF
470: int main(void) {
471: rdfSchema rdf;
472: rdfNamespace rpm;
1.2 veillard 473: rdfDescription desc;
474: rdfBag bag;
1.1 veillard 475:
476: char *value;
477:
478: /*
479: * build a fake RDF document
480: */
481: rdf = rdfNewSchema();
482: rpm = rdfNewNamespace(rdf, "http://www.rpm.org/", "RPM");
483: desc = rdfAddDescription(rdf, NULL,
484: "ftp://ftp.redhat.com/pub/contrib/i386/rpm2html-0.90-1.i386.rpm");
485: rdfSetValue(desc, "Name", rpm, "rpm2html");
486: rdfSetValue(desc, "Version", rpm, "0.90");
487: rdfSetValue(desc, "Release", rpm, "1");
1.2 veillard 488: bag = rdfBagCreate(rdf, desc, "Provides", rpm);
489: rdfBagAddValue(bag, "Resource", rpm, "rpm2html", NULL);
490: bag = rdfBagCreate(rdf, desc, "Requires", rpm);
491: rdfBagAddValue(bag, "Resource", rpm, "libz.so.1", NULL);
492: rdfBagAddValue(bag, "Resource", rpm, "libdb.so.2", NULL);
493: rdfBagAddValue(bag, "Resource", rpm, "libc.so.6", NULL);
494: rdfBagAddValue(bag, "Resource", rpm, "ld-linux.so.2", NULL);
1.1 veillard 495:
496: /*
497: * Save it.
498: */
499: rdfWrite(rdf, "test.rdf");
500: rdfDestroySchema(rdf);
501:
502: /*
503: * Read it.
504: */
505: rdf = rdfRead("test.rdf");
506:
507: /*
508: * print it.
509: */
510: rpm = rdfGetNamespace(rdf, "http://www.rpm.org/");
511: if (rpm == NULL) fprintf(stderr, "RPM namespace not found !\n");
512: desc = rdfFirstDescription(rdf);
513: rdfGetValue(desc, "Name", rpm, &value, NULL);
514: printf("Name : %s\n", value);
515: rdfGetValue(desc, "Name", NULL, &value, NULL);
516: printf("Name : %s\n", value);
517: printf("\n---\n");
518: xmlDocDump(stdout, rdf);
519:
520: /*
521: * free it.
522: */
523: rdfDestroySchema(rdf);
524: return(0);
525: }
526: #endif
Webmaster