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