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