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