/*
* 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.13 1998/11/12 02:35:36 daniel Exp $
*/
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#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);
}
/*
* 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");
rdf = xmlNewGlobalNs(res, "http://www.w3.org/TR/WD-rdf-syntax#", "RDF");
res->root = xmlNewDocNode(res, rdf, "RDF", NULL);
return((rdfSchema) res);
}
/*
* Adding a new namespace to an RDF schema.
*/
rdfNamespace rdfNewNamespace(rdfSchema rdf, const char *url,
const char *namespace) {
xmlNsPtr ns;
ns = xmlNewGlobalNs(rdf, url, namespace);
return((rdfNamespace) ns);
}
/*
* Get a namespace associated to 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 to 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 *) malloc(strlen(ns->prefix) + 10);
sprintf(buf, "%s:HREF", ns->prefix);
xmlNewProp(tree, buf, about);
free(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 *) malloc(strlen(ns->prefix) + 10);
sprintf(buf, "%s:HREF", ns->prefix);
res = (char *) xmlGetProp(desc, buf);
free(buf);
return(res);
}
/*
* Read any resource associated to 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;
/*
* 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) free(list->content);
if (list->childs != NULL) xmlFreeNodeList(list->childs);
list->childs = xmlStringGetNodeList(desc->doc,
xmlEncodeEntities(desc->doc, value));
return;
}
list = list->next;
}
/*
* Create a new property.
*/
xmlNewChild(desc, ns, property, xmlEncodeEntities(desc->doc, 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->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(strdup(elem->content));
else
return(xmlNodeListGetString(elem->doc, elem->childs, 1));
}
const char *rdfElemGetPropertyName(rdfElement elem) {
return(strdup(elem->name));
}
rdfNamespace rdfElemGetNamespace(rdfElement elem) {
return(elem->ns);
}
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);
if (elem->childs != NULL) xmlFreeNodeList(elem->childs);
elem->childs = xmlStringGetNodeList(elem->doc,
xmlEncodeEntities(elem->doc, value));
}
/************************************************************************
* *
* 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, "<shade/stick & close/destroy>");
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);
free(value);
rdfGetValue(desc, "Name", NULL, &value, NULL);
printf("Name : %s\n", value);
free(value);
printf("\n---\n");
xmlDocDump(stdout, rdf);
/*
* free it.
*/
rdfDestroySchema(rdf);
return(0);
}
#endif
Webmaster