Annotation of rpm2html/rdf_api.c, revision 1.19

1.1       veillard    1: /*
                      2:  * rdf_api.h : implementation of methods to read and write RDF schemas
1.6       veillard    3:  *
                      4:  * See Copyright for the status of this software.
                      5:  *
1.19    ! daniel      6:  * $Id: rdf_api.c,v 1.18 1999/08/08 18:29:42 daniel Exp $
1.1       veillard    7:  */
                      8: 
1.17      daniel      9: #include "config.h"
1.1       veillard   10: #include <stdio.h>
                     11: #include <string.h>
                     12: #include <errno.h>
1.15      daniel     13: #include <memory.h>
1.1       veillard   14: #include "rpmdata.h"
                     15: #include "rdf_api.h"
1.16      daniel     16: #include "rpm2html.h"
1.1       veillard   17: 
                     18: /*
                     19:  * Reading an RDF schema stored in a file, this just build the
                     20:  * document tree, and check that it's an RDF:RDf element.
                     21:  */
                     22: rdfSchema rdfRead(const char *filename) {
                     23:     xmlDocPtr res;
                     24:    
                     25:     res = xmlParseFile(filename);
                     26:     if (res == NULL) return(NULL);
                     27:     if (res->root == NULL) {
                     28:        fprintf(stderr, "rdfRead %s: tree is empty\n", filename);
                     29:         xmlFreeDoc(res);
                     30:        return(NULL);
                     31:     }
                     32:     if (strcmp(res->root->name, "RDF")) {
                     33:        fprintf(stderr, "rdfRead %s: not an RDF file\n", filename);
                     34:         xmlFreeDoc(res);
                     35:        return(NULL);
                     36:     }
                     37:     return((rdfSchema) res);
                     38: }
                     39: 
                     40: /*
                     41:  * Writing an RDF schema to a file, this just save the
                     42:  * document tree as an XML document.
                     43:  */
                     44: void rdfWrite(rdfSchema rdf, const char *filename) {
                     45:     FILE *output;
                     46:     
                     47:     output = fopen(filename, "w");
                     48:     if (output == NULL) {
                     49:         fprintf(stderr, "rdfWrite : couldn't save to file %s: %s\n",
                     50:                filename, strerror(errno));
                     51:         return;
                     52:     }
                     53:     xmlDocDump(output, (xmlDocPtr) rdf);
                     54:     fclose(output);
                     55: }
                     56: 
                     57: /*
1.4       veillard   58:  * Writing an RDF schema to a memory buffer, this just save the
                     59:  * document tree as an XML document.
                     60:  */
                     61: void rdfWriteMemory(rdfSchema rdf, char **buffer, int *size) {
                     62:     xmlDocDumpMemory((xmlDocPtr) rdf, (CHAR **) buffer, size);
                     63: }
                     64: 
                     65: /*
1.2       veillard   66:  * Creating an RDF schema tree in memory.
1.1       veillard   67:  */
                     68: rdfSchema rdfNewSchema() {
                     69:     xmlDocPtr res;
1.8       daniel     70:     xmlNsPtr rdf;
1.1       veillard   71:    
                     72:     res = xmlNewDoc("1.0");
1.19    ! daniel     73:     res->root = xmlNewDocNode(res, NULL, "RDF", NULL);
        !            74:     rdf = xmlNewNs(res->root, "http://www.w3.org/TR/WD-rdf-syntax#", "RDF");
        !            75:     xmlSetNs(res->root, rdf);
1.1       veillard   76: 
                     77:     return((rdfSchema) res);
                     78: }
                     79: 
                     80: /*
                     81:  * Adding a new namespace to an RDF schema.
                     82:  */
1.8       daniel     83: rdfNamespace rdfNewNamespace(rdfSchema rdf, const char *url,
                     84:                              const char *namespace) {
1.19    ! daniel     85:     xmlNodePtr root;
        !            86:     xmlNsPtr ns = NULL;
1.1       veillard   87:    
1.19    ! daniel     88:     root = xmlDocGetRootElement(rdf);
        !            89:     if (root != NULL)
        !            90:        ns = xmlNewNs(root, url, namespace);
1.1       veillard   91: 
1.8       daniel     92:     return((rdfNamespace) ns);
1.1       veillard   93: }
                     94: 
                     95: /*
                     96:  * Get a namespace associated to an RDF schema.
1.9       daniel     97:  * Should be stored either as an old NS on the document or as local
                     98:  * namespace stored on the root element.
1.1       veillard   99:  */
                    100: rdfNamespace rdfGetNamespace(rdfSchema rdf, const char *href) {
1.9       daniel    101:     return((rdfNamespace) xmlSearchNsByHref(rdf, rdf->root, href));
1.1       veillard  102: }
                    103: 
                    104: /*
                    105:  * Get the RDF namespace associated to an RDF schema.
                    106:  */
                    107: rdfNamespace rdfGetRdfNamespace(rdfSchema rdf) {
1.9       daniel    108:     rdfNamespace ns;
1.1       veillard  109:    
1.9       daniel    110:     ns = rdfGetNamespace(rdf, "http://www.w3.org/TR/WD-rdf-syntax#");
                    111:     if (ns != NULL)
                    112:         return((rdfNamespace) ns);
1.1       veillard  113:     /* create it ! */
                    114:     return(rdfNewNamespace(rdf, "http://www.w3.org/TR/WD-rdf-syntax#", "RDF"));
                    115: }
                    116: 
                    117: 
                    118: /*
                    119:  * Destroying an RDF schema in memory.
                    120:  */
                    121: void rdfDestroySchema(rdfSchema rdf) {
                    122:     xmlFreeDoc((xmlDocPtr) rdf);
                    123: }
                    124: 
                    125: /**
                    126:  ** An RDF schema is a collection of RDF descriptions.
                    127:  ** The following are used to browse the list.
                    128:  **/
                    129: 
                    130: /* First item */
                    131: rdfDescription rdfFirstDescription(rdfSchema schema) {
                    132:     xmlNodePtr tree;
                    133:     rdfNamespace rdfNs;
                    134: 
                    135:     rdfNs = rdfGetRdfNamespace(schema);
                    136:     tree = schema->root;
                    137:     if (tree == NULL) return(NULL);
                    138:     tree = tree->childs;
                    139:     while (tree != NULL) {
1.8       daniel    140:         if ((tree->ns == rdfNs) && (!strcmp(tree->name, "Description")))
1.1       veillard  141:            return(tree);
                    142:        tree = tree->next;
                    143:     }
                    144:     return(NULL);
                    145: }
                    146: 
                    147: /* Iteration : next item */
                    148: rdfDescription rdfNextDescription(rdfDescription desc) {
                    149:     rdfNamespace rdfNs;
                    150: 
                    151:     if (desc == NULL) return(NULL);
1.8       daniel    152:     rdfNs = desc->ns;
1.1       veillard  153:     desc = desc->next;
                    154:     while (desc != NULL) {
1.8       daniel    155:         if ((desc->ns == rdfNs) && (!strcmp(desc->name, "Description")))
1.1       veillard  156:            return(desc);
                    157:        desc = desc->next;
                    158:     }
                    159:     return(NULL);
                    160: }
                    161: 
                    162: /*
                    163:  * Add an RDF description to an RDF schema, it just link it
                    164:  * the top level node of the description and requires further
                    165:  * action to fill it with the pertinent informations.
                    166:  */
                    167: rdfDescription rdfAddDescription(rdfSchema schema, const char *id,
1.7       veillard  168:                                  const char *about) {
1.1       veillard  169:     xmlNodePtr tree;
                    170: 
1.10      daniel    171:     tree = xmlNewChild(schema->root, NULL, "Description", NULL);
1.1       veillard  172:     if (id != NULL) {
                    173:         xmlNewProp(tree, "ID", id);
                    174:     }
1.7       veillard  175:     if (about != NULL) {
                    176:         if (oldXMLWDcompatibility) {
1.8       daniel    177:            rdfNamespace ns;
1.7       veillard  178:            char *buf;
                    179: 
1.8       daniel    180:            ns = rdfGetRdfNamespace(schema);
1.15      daniel    181:            buf = (char *) debugMalloc(strlen(ns->prefix) + 10);
1.8       daniel    182:            sprintf(buf, "%s:HREF", ns->prefix);
1.7       veillard  183:            xmlNewProp(tree, buf, about); 
1.15      daniel    184:            debugFree(buf);
1.7       veillard  185:         } else {
                    186:            xmlNewProp(tree, "about", about); 
                    187:        }
1.1       veillard  188:     }
                    189:     return((rdfDescription) tree);
                    190: }
                    191: 
1.5       veillard  192: /*
                    193:  * Read the attributes of a Description node.
                    194:  */
                    195: char *rdfGetDescriptionId(rdfSchema schema, rdfDescription desc) {
                    196:     char *res;
                    197: 
                    198:     res = (char *) xmlGetProp(desc, "ID");
                    199:     return(res);
                    200: }
                    201: 
1.7       veillard  202: char *rdfGetDescriptionAbout(rdfSchema schema, rdfDescription desc) {
1.5       veillard  203:     char *res;
1.8       daniel    204:     rdfNamespace ns;
1.5       veillard  205:     char *buf;
                    206: 
1.7       veillard  207:     res = (char *) xmlGetProp(desc, "about");
                    208:     if (res != NULL) return(res);
                    209: 
                    210:     /*
                    211:      * Maintain compatibility with old "RDF:HREF"
                    212:      */
1.8       daniel    213:     res = (char *) xmlGetProp(desc, "HREF");
                    214:     if (res != NULL) return(res);
                    215:     ns = rdfGetRdfNamespace(schema);
1.15      daniel    216:     buf = (char *) debugMalloc(strlen(ns->prefix) + 10);
1.8       daniel    217:     sprintf(buf, "%s:HREF", ns->prefix);
1.5       veillard  218:     res = (char *) xmlGetProp(desc, buf);
1.15      daniel    219:     debugFree(buf);
1.5       veillard  220:     return(res);
                    221: }
                    222: 
1.7       veillard  223: /*
                    224:  * Read any resource associated to an element.
                    225:  */
                    226: char *rdfGetElementResource(rdfSchema schema, rdfElement elem) {
                    227:     char *res;
                    228: 
                    229:     res = (char *) xmlGetProp(elem, "resource");
                    230:     return(res);
                    231: }
                    232: 
                    233: void rdfSetElementResource(rdfSchema schema, rdfElement elem, const char *URI) {
                    234:     xmlSetProp(elem, "resource", URI);
                    235: }
                    236: 
1.1       veillard  237: /**
                    238:  ** Routines to read/write final values.
                    239:  **/
                    240: 
                    241: /*
                    242:  * browse the various property pertaining to this description,
                    243:  * and return the value which can be either a text (RDF_LEAF)
                    244:  * or an rdfElement (RDF_BAG, RDF_SEQ, RDF_ALT, RDF_DESC).
                    245:  * Having both reflect an invalid RDF document (while valid from
                    246:  * XML point of view).
                    247:  * This routine tries to ajust in case a request is done with or
                    248:  * or without a ns present or not on the node, and if the names
                    249:  * matches.
                    250:  *  e.g. a request for Name may return BIB:Name
                    251:  *    or a request for BIB:Name may return Name
                    252:  * if the exact match is not found.
                    253:  * 
                    254:  * Return -1 if not found
                    255:  *         0 if a single value is found
                    256:  *   RDF_xxx if a node is found.
                    257:  */
                    258: int rdfGetValue(rdfDescription desc, const char *property, 
                    259:                 rdfNamespace ns, char **value, rdfElement *elem){
                    260:     rdfElement list = desc->childs;
                    261:     rdfElement best = NULL;
                    262:     int approx = 0;
                    263: 
                    264:     if (value != NULL) *value = NULL;
                    265:     if (elem != NULL) *elem = NULL;
                    266: 
                    267:     while (list != NULL) {
1.8       daniel    268:         if ((list->ns == ns) && (!strcmp(list->name, property))) {
1.1       veillard  269:            /*
                    270:             * Found a perfect match, return it !
                    271:             */
                    272:            if ((list->content != NULL) && (list->childs != NULL)) {
                    273:                fprintf(stderr, 
                    274:                    "RDF Schema invalid, node %s has content and child(s)\n",
                    275:                        list->name);
                    276:            }
1.11      daniel    277:            if (value != NULL) {
                    278:                if (list->content != NULL)
                    279:                    *value = xmlStrdup(list->content);
                    280:                 else
                    281:                    *value = xmlNodeListGetString(desc->doc, list->childs, 1);
                    282:             }
1.1       veillard  283:            if (elem != NULL) *elem = list->childs;
                    284:            if (!strcmp(list->name, "Bag")) return(RDF_BAG);
                    285:            if (!strcmp(list->name, "Seq")) return(RDF_SEQ);
                    286:            if (!strcmp(list->name, "Alt")) return(RDF_ALT);
                    287:            if (!strcmp(list->name, "Description")) return(RDF_DESC);
                    288:            return(0);
                    289:        }
1.8       daniel    290:        else if (((list->ns == NULL) || (ns == NULL)) &&
1.1       veillard  291:                 (!strcmp(list->name, property))) {
                    292:            /*
                    293:             * If more than one "best" match exists, ignore them !
                    294:             */
                    295:            if (approx) {
                    296:                best = NULL;
                    297:            } else {
                    298:                 best = list;
                    299:                approx = 1;
                    300:             }
                    301:         }
                    302:        list = list->next;
                    303:     }
                    304:     if (best != NULL) {
                    305:        if ((best->content != NULL) && (best->childs != NULL)) {
                    306:            fprintf(stderr, 
                    307:                    "RDF Schema invalid, node %s has content and child(s)\n",
                    308:                    best->name);
                    309:        }
1.11      daniel    310:        if (value != NULL) {
                    311:            if (best->content != NULL)
                    312:                *value = xmlStrdup(best->content);
                    313:            else
                    314:                *value = xmlNodeListGetString(desc->doc, best->childs, 1);
                    315:        }
1.1       veillard  316:        if (elem != NULL) *elem = best->childs;
                    317:        if (!strcmp(best->name, "Bag")) return(RDF_BAG);
                    318:        if (!strcmp(best->name, "Seq")) return(RDF_SEQ);
                    319:        if (!strcmp(best->name, "Alt")) return(RDF_ALT);
                    320:        if (!strcmp(best->name, "Description")) return(RDF_DESC);
                    321:        return(0);
                    322:     }
                    323:     return(-1);
                    324: }
                    325: 
                    326: /*
                    327:  * browse the various property pertaining to this description,
                    328:  * update the value if found on a text mode, otherwise append
                    329:  * a new property at the end of the list.
                    330:  * Note that contrary to GetValue, the check is absolute !
                    331:  */
                    332: void rdfSetValue(rdfDescription desc, const char *property,
                    333:                  rdfNamespace ns, const char *value) {
                    334:     rdfElement list = desc->childs;
1.18      daniel    335:     char *str;
1.1       veillard  336: 
                    337:     /*
                    338:      * Search the property.
                    339:      */
                    340:     while (list != NULL) {
1.8       daniel    341:         if ((list->ns == ns) && (!strcmp(list->name, property))) {
1.1       veillard  342:            /*
                    343:             * Property was found, update it !
                    344:             */
                    345:            if ((list->content != NULL) && (list->childs != NULL)) {
                    346:                fprintf(stderr, 
                    347:                    "RDF Schema invalid, node %s has content and child(s)\n",
                    348:                        list->name);
                    349:            }
1.15      daniel    350:            if (list->content != NULL) debugFree(list->content);
1.11      daniel    351:            if (list->childs != NULL) xmlFreeNodeList(list->childs);
1.18      daniel    352:            str = xmlEncodeEntitiesReentrant(desc->doc, value);
                    353:            list->childs = xmlStringGetNodeList(desc->doc, value);
                    354:            if (str != NULL)
                    355:                free(str);
1.1       veillard  356:            return;
                    357:        }
                    358:        list = list->next;
                    359:     }
                    360: 
                    361:     /*
                    362:      * Create a new property.
                    363:      */
1.18      daniel    364:     str = xmlEncodeEntitiesReentrant(desc->doc, value);
                    365:     xmlNewChild(desc, ns, property, str);
                    366:     if (str != NULL)
                    367:        free(str);
1.1       veillard  368: }
                    369: 
                    370: /*
                    371:  * browse the various property pertaining to this description,
                    372:  * and if found remove and destroy the subtree.
                    373:  */
                    374: void rdfRemoveProperty(rdfDescription desc, const char *property,
                    375:                        rdfNamespace ns) {
                    376:     rdfElement list = desc->childs;
                    377:     rdfElement prev = NULL;
                    378: 
                    379:     /*
                    380:      * Search the property.
                    381:      */
                    382:     while (list != NULL) {
1.8       daniel    383:         if ((list->ns == ns) && (!strcmp(list->name, property))) {
1.1       veillard  384:            /*
                    385:             * Property was found, delete it !
                    386:             */
                    387:            if (prev == NULL)
                    388:                desc->childs = list->next;
                    389:            else
                    390:                prev->next = list->next;
                    391:            list->next = NULL;
                    392:            
                    393:            xmlFreeNode(list);
                    394:            return;
                    395:        }
                    396:        prev = list;
                    397:        list = list->next;
                    398:     }
                    399: }
                    400: 
                    401: /**
                    402:  ** Routines to read/write bags
                    403:  **/
                    404: 
                    405: /*
1.2       veillard  406:  * Create a new Bag.
1.1       veillard  407:  */
1.2       veillard  408: rdfBag rdfBagCreate(rdfSchema schema, rdfDescription desc,
                    409:                     const char *property, rdfNamespace ns) {
                    410:     rdfElement cur;
                    411:     rdfNamespace rdf;
                    412: 
                    413:     rdf = rdfGetRdfNamespace(schema);
1.10      daniel    414:     cur = xmlNewChild(desc, ns, property, NULL);
                    415:     cur = xmlNewChild(cur, rdf, "Bag", NULL);
1.2       veillard  416:     return(cur);
1.1       veillard  417: }
                    418: 
                    419: /*
1.2       veillard  420:  * Add an element to a bag.
1.1       veillard  421:  */
1.2       veillard  422: rdfElement rdfBagAddValue(rdfBag bag, const char *property,
1.4       veillard  423:                     rdfNamespace ns, const char *value, rdfElement elem) {
1.2       veillard  424:     rdfElement cur;
                    425: 
                    426:     if (value != NULL)
1.10      daniel    427:         cur = xmlNewChild(bag, ns, property, (char *) value);
1.2       veillard  428:     else {
1.11      daniel    429:         cur = xmlNewDocNode(bag->doc, ns, property, NULL);
1.7       veillard  430:        if (elem != NULL)
                    431:            xmlAddChild(cur, elem);
1.2       veillard  432:        xmlAddChild(bag, cur);
                    433:     }
                    434:     return(cur);
1.1       veillard  435: }
                    436: 
                    437: /**
                    438:  ** Routines to walk bags and sequences.
                    439:  **/
                    440: rdfElement rdfFirstChild(rdfElement bag) {
                    441:     return(bag->childs);
                    442: }
                    443: rdfElement rdfNextElem(rdfElement desc) {
                    444:     return(desc->next);
                    445: }
                    446: 
                    447: /**
                    448:  ** Direct access to Element values.
                    449:  **/
                    450: int rdfElemGetType(rdfElement elem) {
                    451:     if (!strcmp(elem->name, "Bag")) return(RDF_BAG);
                    452:     if (!strcmp(elem->name, "Seq")) return(RDF_SEQ);
                    453:     if (!strcmp(elem->name, "Alt")) return(RDF_ALT);
                    454:     if (!strcmp(elem->name, "Description")) return(RDF_DESC);
                    455:     return(0);
                    456: }
                    457: 
                    458: char *rdfElemGetValue(rdfElement elem) {
1.12      daniel    459:     if (elem->content != NULL)
1.15      daniel    460:        return(debugStrdup(elem->content));
1.12      daniel    461:     else
                    462:         return(xmlNodeListGetString(elem->doc, elem->childs, 1));
1.1       veillard  463: }
1.14      daniel    464: char *rdfElemGetPropertyName(rdfElement elem) {
1.15      daniel    465:     return(debugStrdup(elem->name));
1.3       veillard  466: }
                    467: rdfNamespace rdfElemGetNamespace(rdfElement elem) {
1.8       daniel    468:     return(elem->ns);
1.1       veillard  469: }
                    470: void rdfElemSetValue(rdfElement elem, const char *value) {
1.18      daniel    471:     char *str;
1.1       veillard  472:     if (elem->childs != NULL) {
                    473:         fprintf(stderr, "rdfElemSetValue : elem %s has childs\n", elem->name);
                    474:        return;
                    475:     }
1.15      daniel    476:     if (elem->content != NULL) debugFree(elem->content);
1.12      daniel    477:     if (elem->childs != NULL) xmlFreeNodeList(elem->childs);
1.18      daniel    478:     str = xmlEncodeEntitiesReentrant(elem->doc, value);
                    479:     elem->childs = xmlStringGetNodeList(elem->doc, str);
                    480:     if (str != NULL)
                    481:        free(str);
1.1       veillard  482: }
                    483: 
                    484: /************************************************************************
                    485:  *                                                                     *
                    486:  *                             Debug                                   *
                    487:  *                                                                     *
                    488:  ************************************************************************/
                    489: 
                    490: #ifdef DEBUG_RDF
                    491: int main(void) {
                    492:     rdfSchema rdf;
                    493:     rdfNamespace rpm;
1.2       veillard  494:     rdfDescription desc;
                    495:     rdfBag bag;
1.1       veillard  496: 
                    497:     char *value;
                    498: 
                    499:     /*
                    500:      * build a fake RDF document
                    501:      */
                    502:     rdf = rdfNewSchema();
                    503:     rpm = rdfNewNamespace(rdf, "http://www.rpm.org/", "RPM");
                    504:     desc = rdfAddDescription(rdf, NULL,
                    505:            "ftp://ftp.redhat.com/pub/contrib/i386/rpm2html-0.90-1.i386.rpm");
1.12      daniel    506:     rdfSetValue(desc, "Description", rpm, "<shade/stick & close/destroy>");
1.1       veillard  507:     rdfSetValue(desc, "Name", rpm, "rpm2html");
                    508:     rdfSetValue(desc, "Version", rpm, "0.90");
                    509:     rdfSetValue(desc, "Release", rpm, "1");
1.2       veillard  510:     bag = rdfBagCreate(rdf, desc, "Provides", rpm);
                    511:     rdfBagAddValue(bag, "Resource", rpm, "rpm2html", NULL);
                    512:     bag = rdfBagCreate(rdf, desc, "Requires", rpm);
                    513:     rdfBagAddValue(bag, "Resource", rpm, "libz.so.1", NULL);
                    514:     rdfBagAddValue(bag, "Resource", rpm, "libdb.so.2", NULL);
                    515:     rdfBagAddValue(bag, "Resource", rpm, "libc.so.6", NULL);
                    516:     rdfBagAddValue(bag, "Resource", rpm, "ld-linux.so.2", NULL);
1.1       veillard  517: 
                    518:     /*
                    519:      * Save it.
                    520:      */
                    521:     rdfWrite(rdf, "test.rdf");
                    522:     rdfDestroySchema(rdf);
                    523: 
                    524:     /*
                    525:      * Read it.
                    526:      */
                    527:     rdf = rdfRead("test.rdf");
                    528: 
                    529:     /*
                    530:      * print it.
                    531:      */
                    532:     rpm = rdfGetNamespace(rdf, "http://www.rpm.org/");
                    533:     if (rpm == NULL) fprintf(stderr, "RPM namespace not found !\n");
                    534:     desc = rdfFirstDescription(rdf);
                    535:     rdfGetValue(desc, "Name", rpm, &value, NULL);
                    536:     printf("Name : %s\n", value);
1.15      daniel    537:     debugFree(value);
1.1       veillard  538:     rdfGetValue(desc, "Name", NULL, &value, NULL);
                    539:     printf("Name : %s\n", value);
1.15      daniel    540:     debugFree(value);
1.1       veillard  541:     printf("\n---\n");
                    542:     xmlDocDump(stdout, rdf);
                    543: 
                    544:     /*
                    545:      * free it.
                    546:      */
                    547:     rdfDestroySchema(rdf);
                    548:     return(0);
                    549: }
                    550: #endif

Webmaster