/* * rdf_api.h : implementation of methods to read and write RDF schemas */ #include #include #include #include #include "rpmdata.h" #include "rdf_api.h" /* * Reading an RDF schema stored in a file, this just build the * document tree, and check that it's an RDF:RDf element. */ rdfSchema rdfRead(const char *filename) { xmlDocPtr res; res = xmlParseFile(filename); if (res == NULL) return(NULL); if (res->root == NULL) { fprintf(stderr, "rdfRead %s: tree is empty\n", filename); xmlFreeDoc(res); return(NULL); } if (strcmp(res->root->name, "RDF")) { fprintf(stderr, "rdfRead %s: not an RDF file\n", filename); xmlFreeDoc(res); return(NULL); } return((rdfSchema) res); } /* * Writing an RDF schema to a file, this just save the * document tree as an XML document. */ void rdfWrite(rdfSchema rdf, const char *filename) { FILE *output; output = fopen(filename, "w"); if (output == NULL) { fprintf(stderr, "rdfWrite : couldn't save to file %s: %s\n", filename, strerror(errno)); return; } xmlDocDump(output, (xmlDocPtr) rdf); fclose(output); } /* * Creating an RDF schema in memory. */ rdfSchema rdfNewSchema() { xmlDocPtr res; xmlDtdPtr rdf; res = xmlNewDoc("1.0"); rdf = xmlNewDtd(res, "http://www.w3.org/TR/WD-rdf-syntax#", "RDF"); res->root = xmlNewNode(rdf, strdup("RDF"), NULL); return((rdfSchema) res); } /* * Adding a new namespace to an RDF schema. */ rdfNamespace rdfNewNamespace(rdfSchema rdf, const char *url, const char *ns) { xmlDtdPtr dtd; dtd = xmlNewDtd(rdf, url, ns); return((rdfNamespace) dtd); } /* * Get a namespace associated to an RDF schema. */ rdfNamespace rdfGetNamespace(rdfSchema rdf, const char *href) { xmlDtdPtr dtd; dtd = rdf->dtds; while (dtd != NULL) { if (!strcmp(dtd->href, href)) return((rdfNamespace) dtd); dtd = dtd->next; } return(NULL); } /* * Get the RDF namespace associated to an RDF schema. */ rdfNamespace rdfGetRdfNamespace(rdfSchema rdf) { xmlDtdPtr dtd; dtd = rdf->dtds; while (dtd != NULL) { if (!strcmp(dtd->href, "http://www.w3.org/TR/WD-rdf-syntax#")) return((rdfNamespace) dtd); dtd = dtd->next; } /* create it ! */ return(rdfNewNamespace(rdf, "http://www.w3.org/TR/WD-rdf-syntax#", "RDF")); } /* * Destroying an RDF schema in memory. */ void rdfDestroySchema(rdfSchema rdf) { xmlFreeDoc((xmlDocPtr) rdf); } /** ** An RDF schema is a collection of RDF descriptions. ** The following are used to browse the list. **/ /* First item */ rdfDescription rdfFirstDescription(rdfSchema schema) { xmlNodePtr tree; rdfNamespace rdfNs; rdfNs = rdfGetRdfNamespace(schema); tree = schema->root; if (tree == NULL) return(NULL); tree = tree->childs; while (tree != NULL) { if ((tree->dtd == rdfNs) && (!strcmp(tree->name, "Description"))) return(tree); tree = tree->next; } return(NULL); } /* Iteration : next item */ rdfDescription rdfNextDescription(rdfDescription desc) { rdfNamespace rdfNs; if (desc == NULL) return(NULL); rdfNs = desc->dtd; desc = desc->next; while (desc != NULL) { if ((desc->dtd == rdfNs) && (!strcmp(desc->name, "Description"))) return(desc); desc = desc->next; } return(NULL); } /* * Add an RDF description to an RDF schema, it just link it * the top level node of the description and requires further * action to fill it with the pertinent informations. */ rdfDescription rdfAddDescription(rdfSchema schema, const char *id, const char *href) { xmlNodePtr tree; tree = xmlNewChild(schema->root, NULL, strdup("Description"), NULL); if (id != NULL) { xmlNewProp(tree, "ID", id); } if (href != NULL) { rdfNamespace dtd; char *buf; dtd = rdfGetRdfNamespace(schema); buf = (char *) malloc(strlen(dtd->AS) + 10); sprintf(buf, "%s:HREF", dtd->AS); xmlNewProp(tree, buf, href); free(buf); } return((rdfDescription) tree); } /** ** Routines to read/write final values. **/ /* * browse the various property pertaining to this description, * and return the value which can be either a text (RDF_LEAF) * or an rdfElement (RDF_BAG, RDF_SEQ, RDF_ALT, RDF_DESC). * Having both reflect an invalid RDF document (while valid from * XML point of view). * This routine tries to ajust in case a request is done with or * or without a ns present or not on the node, and if the names * matches. * e.g. a request for Name may return BIB:Name * or a request for BIB:Name may return Name * if the exact match is not found. * * Return -1 if not found * 0 if a single value is found * RDF_xxx if a node is found. */ int rdfGetValue(rdfDescription desc, const char *property, rdfNamespace ns, char **value, rdfElement *elem){ rdfElement list = desc->childs; rdfElement best = NULL; int approx = 0; if (value != NULL) *value = NULL; if (elem != NULL) *elem = NULL; while (list != NULL) { if ((list->dtd == ns) && (!strcmp(list->name, property))) { /* * Found a perfect match, return it ! */ if ((list->content != NULL) && (list->childs != NULL)) { fprintf(stderr, "RDF Schema invalid, node %s has content and child(s)\n", list->name); } if (value != NULL) *value = list->content; if (elem != NULL) *elem = list->childs; if (!strcmp(list->name, "Bag")) return(RDF_BAG); if (!strcmp(list->name, "Seq")) return(RDF_SEQ); if (!strcmp(list->name, "Alt")) return(RDF_ALT); if (!strcmp(list->name, "Description")) return(RDF_DESC); return(0); } else if (((list->dtd == NULL) || (ns == NULL)) && (!strcmp(list->name, property))) { /* * If more than one "best" match exists, ignore them ! */ if (approx) { best = NULL; } else { best = list; approx = 1; } } list = list->next; } if (best != NULL) { if ((best->content != NULL) && (best->childs != NULL)) { fprintf(stderr, "RDF Schema invalid, node %s has content and child(s)\n", best->name); } if (value != NULL) *value = best->content; if (elem != NULL) *elem = best->childs; if (!strcmp(best->name, "Bag")) return(RDF_BAG); if (!strcmp(best->name, "Seq")) return(RDF_SEQ); if (!strcmp(best->name, "Alt")) return(RDF_ALT); if (!strcmp(best->name, "Description")) return(RDF_DESC); return(0); } return(-1); } /* * browse the various property pertaining to this description, * update the value if found on a text mode, otherwise append * a new property at the end of the list. * Note that contrary to GetValue, the check is absolute ! */ void rdfSetValue(rdfDescription desc, const char *property, rdfNamespace ns, const char *value) { rdfElement list = desc->childs; /* * Search the property. */ while (list != NULL) { if ((list->dtd == ns) && (!strcmp(list->name, property))) { /* * Property was found, update it ! */ if ((list->content != NULL) && (list->childs != NULL)) { fprintf(stderr, "RDF Schema invalid, node %s has content and child(s)\n", list->name); } if (list->content != NULL) free(list->content); if (list->childs == NULL) { list->content = strdup(value); } return; } list = list->next; } /* * Create a new property. */ xmlNewChild(desc, ns, strdup(property), value); } /* * browse the various property pertaining to this description, * and if found remove and destroy the subtree. */ void rdfRemoveProperty(rdfDescription desc, const char *property, rdfNamespace ns) { rdfElement list = desc->childs; rdfElement prev = NULL; /* * Search the property. */ while (list != NULL) { if ((list->dtd == ns) && (!strcmp(list->name, property))) { /* * Property was found, delete it ! */ if (prev == NULL) desc->childs = list->next; else prev->next = list->next; list->next = NULL; xmlFreeNode(list); return; } prev = list; list = list->next; } } /** ** Routines to read/write bags **/ /* * Add or update a bag. */ void rdfBagAddValue(rdfBag bag, const char *property, rdfNamespace ns, const char *value, rdfElement *elem) { } /* * Remove an entry in a bag. */ void rdfBagDeleteValue(rdfBag bag, const char *property, rdfNamespace ns) { } /** ** Routines to walk bags and sequences. **/ rdfElement rdfFirstChild(rdfElement bag) { return(bag->childs); } rdfElement rdfNextElem(rdfElement desc) { return(desc->next); } /** ** Direct access to Element values. **/ int rdfElemGetType(rdfElement elem) { if (!strcmp(elem->name, "Bag")) return(RDF_BAG); if (!strcmp(elem->name, "Seq")) return(RDF_SEQ); if (!strcmp(elem->name, "Alt")) return(RDF_ALT); if (!strcmp(elem->name, "Description")) return(RDF_DESC); return(0); } char *rdfElemGetValue(rdfElement elem) { return(elem->content); } char *rdfElemGetPropertyName(rdfElement elem) { return(elem->name); } void rdfElemSetValue(rdfElement elem, const char *value) { if (elem->childs != NULL) { fprintf(stderr, "rdfElemSetValue : elem %s has childs\n", elem->name); return; } if (elem->content != NULL) free(elem->content); elem->content = strdup(value); } /************************************************************************ * * * Debug * * * ************************************************************************/ #ifdef DEBUG_RDF int main(void) { rdfSchema rdf; rdfNamespace rpm; xmlNodePtr desc; char *value; /* * build a fake RDF document */ rdf = rdfNewSchema(); rpm = rdfNewNamespace(rdf, "http://www.rpm.org/", "RPM"); desc = rdfAddDescription(rdf, NULL, "ftp://ftp.redhat.com/pub/contrib/i386/rpm2html-0.90-1.i386.rpm"); rdfSetValue(desc, "Name", rpm, "rpm2html"); rdfSetValue(desc, "Version", rpm, "0.90"); rdfSetValue(desc, "Release", rpm, "1"); /* * Save it. */ rdfWrite(rdf, "test.rdf"); rdfDestroySchema(rdf); /* * Read it. */ rdf = rdfRead("test.rdf"); /* * print it. */ rpm = rdfGetNamespace(rdf, "http://www.rpm.org/"); if (rpm == NULL) fprintf(stderr, "RPM namespace not found !\n"); desc = rdfFirstDescription(rdf); rdfGetValue(desc, "Name", rpm, &value, NULL); printf("Name : %s\n", value); rdfGetValue(desc, "Name", NULL, &value, NULL); printf("Name : %s\n", value); printf("\n---\n"); xmlDocDump(stdout, rdf); /* * free it. */ rdfDestroySchema(rdf); return(0); } #endif