/* * rdf_api.h : implementation of methods to read and write RDF schemas * * See Copyright for the status of this software. * * $Id: rdf_api.c,v 1.20 2000/02/15 17:26:54 daniel Exp $ */ #include "config.h" #include #include #include #include #include "rpmdata.h" #include "rdf_api.h" #include "rpm2html.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); } /* * Writing an RDF schema to a memory buffer, this just save the * document tree as an XML document. */ void rdfWriteMemory(rdfSchema rdf, char **buffer, int *size) { xmlDocDumpMemory((xmlDocPtr) rdf, (CHAR **) buffer, size); } /* * Creating an RDF schema tree in memory. */ rdfSchema rdfNewSchema() { xmlDocPtr res; xmlNsPtr rdf; res = xmlNewDoc("1.0"); res->root = xmlNewDocNode(res, NULL, "RDF", NULL); rdf = xmlNewNs(res->root, "http://www.w3.org/TR/WD-rdf-syntax#", "RDF"); xmlSetNs(res->root, rdf); return((rdfSchema) res); } /* * Adding a new namespace to an RDF schema. */ rdfNamespace rdfNewNamespace(rdfSchema rdf, const char *url, const char *namespace) { xmlNodePtr root; xmlNsPtr ns = NULL; root = xmlDocGetRootElement(rdf); if (root != NULL) ns = xmlNewNs(root, url, namespace); return((rdfNamespace) ns); } /* * Get a namespace associated with an RDF schema. * Should be stored either as an old NS on the document or as local * namespace stored on the root element. */ rdfNamespace rdfGetNamespace(rdfSchema rdf, const char *href) { return((rdfNamespace) xmlSearchNsByHref(rdf, rdf->root, href)); } /* * Get the RDF namespace associated with an RDF schema. */ rdfNamespace rdfGetRdfNamespace(rdfSchema rdf) { rdfNamespace ns; ns = rdfGetNamespace(rdf, "http://www.w3.org/TR/WD-rdf-syntax#"); if (ns != NULL) return((rdfNamespace) ns); /* 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->ns == 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->ns; desc = desc->next; while (desc != NULL) { if ((desc->ns == 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 *about) { xmlNodePtr tree; tree = xmlNewChild(schema->root, NULL, "Description", NULL); if (id != NULL) { xmlNewProp(tree, "ID", id); } if (about != NULL) { if (oldXMLWDcompatibility) { rdfNamespace ns; char *buf; ns = rdfGetRdfNamespace(schema); buf = (char *) debugMalloc(strlen(ns->prefix) + 10); sprintf(buf, "%s:HREF", ns->prefix); xmlNewProp(tree, buf, about); debugFree(buf); } else { xmlNewProp(tree, "about", about); } } return((rdfDescription) tree); } /* * Read the attributes of a Description node. */ char *rdfGetDescriptionId(rdfSchema schema, rdfDescription desc) { char *res; res = (char *) xmlGetProp(desc, "ID"); return(res); } char *rdfGetDescriptionAbout(rdfSchema schema, rdfDescription desc) { char *res; rdfNamespace ns; char *buf; res = (char *) xmlGetProp(desc, "about"); if (res != NULL) return(res); /* * Maintain compatibility with old "RDF:HREF" */ res = (char *) xmlGetProp(desc, "HREF"); if (res != NULL) return(res); ns = rdfGetRdfNamespace(schema); buf = (char *) debugMalloc(strlen(ns->prefix) + 10); sprintf(buf, "%s:HREF", ns->prefix); res = (char *) xmlGetProp(desc, buf); debugFree(buf); return(res); } /* * Read any resource associated with an element. */ char *rdfGetElementResource(rdfSchema schema, rdfElement elem) { char *res; res = (char *) xmlGetProp(elem, "resource"); return(res); } void rdfSetElementResource(rdfSchema schema, rdfElement elem, const char *URI) { xmlSetProp(elem, "resource", URI); } /** ** 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->ns == 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) { if (list->content != NULL) *value = xmlStrdup(list->content); else *value = xmlNodeListGetString(desc->doc, list->childs, 1); } 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->ns == 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) { if (best->content != NULL) *value = xmlStrdup(best->content); else *value = xmlNodeListGetString(desc->doc, best->childs, 1); } 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; char *str; /* * Search the property. */ while (list != NULL) { if ((list->ns == 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) debugFree(list->content); if (list->childs != NULL) xmlFreeNodeList(list->childs); str = xmlEncodeEntitiesReentrant(desc->doc, value); list->childs = xmlStringGetNodeList(desc->doc, value); if (str != NULL) free(str); return; } list = list->next; } /* * Create a new property. */ str = xmlEncodeEntitiesReentrant(desc->doc, value); xmlNewChild(desc, ns, property, str); if (str != NULL) free(str); } /* * 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->ns == 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 **/ /* * Create a new Bag. */ rdfBag rdfBagCreate(rdfSchema schema, rdfDescription desc, const char *property, rdfNamespace ns) { rdfElement cur; rdfNamespace rdf; rdf = rdfGetRdfNamespace(schema); cur = xmlNewChild(desc, ns, property, NULL); cur = xmlNewChild(cur, rdf, "Bag", NULL); return(cur); } /* * Add an element to a bag. */ rdfElement rdfBagAddValue(rdfBag bag, const char *property, rdfNamespace ns, const char *value, rdfElement elem) { rdfElement cur; if (value != NULL) cur = xmlNewChild(bag, ns, property, (char *) value); else { cur = xmlNewDocNode(bag->doc, ns, property, NULL); if (elem != NULL) xmlAddChild(cur, elem); xmlAddChild(bag, cur); } return(cur); } /** ** 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) { if (elem->content != NULL) return(debugStrdup(elem->content)); else return(xmlNodeListGetString(elem->doc, elem->childs, 1)); } char *rdfElemGetPropertyName(rdfElement elem) { return(debugStrdup(elem->name)); } rdfNamespace rdfElemGetNamespace(rdfElement elem) { return(elem->ns); } void rdfElemSetValue(rdfElement elem, const char *value) { char *str; if (elem->childs != NULL) { fprintf(stderr, "rdfElemSetValue : elem %s has childs\n", elem->name); return; } if (elem->content != NULL) debugFree(elem->content); if (elem->childs != NULL) xmlFreeNodeList(elem->childs); str = xmlEncodeEntitiesReentrant(elem->doc, value); elem->childs = xmlStringGetNodeList(elem->doc, str); if (str != NULL) free(str); } /************************************************************************ * * * Debug * * * ************************************************************************/ #ifdef DEBUG_RDF int main(void) { rdfSchema rdf; rdfNamespace rpm; rdfDescription desc; rdfBag bag; 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, "Description", rpm, ""); rdfSetValue(desc, "Name", rpm, "rpm2html"); rdfSetValue(desc, "Version", rpm, "0.90"); rdfSetValue(desc, "Release", rpm, "1"); bag = rdfBagCreate(rdf, desc, "Provides", rpm); rdfBagAddValue(bag, "Resource", rpm, "rpm2html", NULL); bag = rdfBagCreate(rdf, desc, "Requires", rpm); rdfBagAddValue(bag, "Resource", rpm, "libz.so.1", NULL); rdfBagAddValue(bag, "Resource", rpm, "libdb.so.2", NULL); rdfBagAddValue(bag, "Resource", rpm, "libc.so.6", NULL); rdfBagAddValue(bag, "Resource", rpm, "ld-linux.so.2", NULL); /* * 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); debugFree(value); rdfGetValue(desc, "Name", NULL, &value, NULL); printf("Name : %s\n", value); debugFree(value); printf("\n---\n"); xmlDocDump(stdout, rdf); /* * free it. */ rdfDestroySchema(rdf); return(0); } #endif