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