Annotation of XML/xinclude.c, revision 1.4

1.1       veillard    1: /*
                      2:  * xinclude.c : Code to implement XInclude processing
                      3:  *
                      4:  * World Wide Web Consortium Working Draft 26 October 2000
                      5:  * http://www.w3.org/TR/2000/WD-xinclude-20001026
                      6:  *
                      7:  * See Copyright for the status of this software.
                      8:  *
                      9:  * Daniel.Veillard@w3.org
                     10:  */
                     11: 
                     12: /*
1.4     ! veillard   13:  * TODO: compute XPointers nodesets
1.1       veillard   14:  */
                     15: 
                     16: #ifdef WIN32
                     17: #include "win32config.h"
                     18: #else
                     19: #include "config.h"
                     20: #endif
                     21: 
                     22: #include <stdio.h>
                     23: #include <string.h>
                     24: #include <libxml/xmlmemory.h>
                     25: #include <libxml/tree.h>
                     26: #include <libxml/parser.h>
                     27: #include <libxml/uri.h>
                     28: #include <libxml/xpointer.h>
1.2       veillard   29: #include <libxml/parserInternals.h>
1.1       veillard   30: #ifdef LIBXML_DEBUG_ENABLED
                     31: #include <libxml/debugXML.h>
                     32: #endif
                     33: #include <libxml/xmlerror.h>
                     34: 
                     35: #ifdef LIBXML_XINCLUDE_ENABLED
                     36: #include <libxml/xinclude.h>
                     37: 
                     38: #define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/1999/XML/xinclude"
                     39: #define XINCLUDE_NODE (const xmlChar *) "include"
                     40: #define XINCLUDE_HREF (const xmlChar *) "href"
                     41: #define XINCLUDE_PARSE (const xmlChar *) "parse"
1.2       veillard   42: #define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
                     43: #define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
1.1       veillard   44: 
1.4     ! veillard   45: /* #define DEBUG_XINCLUDE  */
1.1       veillard   46: 
1.2       veillard   47: /************************************************************************
                     48:  *                                                                     *
                     49:  *                     XInclude contexts handling                      *
                     50:  *                                                                     *
                     51:  ************************************************************************/
                     52: 
1.1       veillard   53: /*
                     54:  * An XInclude context
                     55:  */
                     56: typedef xmlChar *URL;
                     57: typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
                     58: typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
                     59: struct _xmlXIncludeCtxt {
                     60:     xmlDocPtr             doc; /* the source document */
                     61:     int                 incNr; /* number of includes */
                     62:     int                incMax; /* size of includes tab */
                     63:     xmlNodePtr        *incTab; /* array of include nodes */
                     64:     xmlNodePtr        *repTab; /* array of replacement node lists */
1.2       veillard   65:     int                 docNr; /* number of parsed documents */
                     66:     int                docMax; /* size of parsed documents tab */
                     67:     xmlDocPtr         *docTab; /* array of parsed documents */
                     68:     URL               *urlTab; /* array of parsed documents URLs */
                     69:     int                 txtNr; /* number of unparsed documents */
                     70:     int                txtMax; /* size of unparsed documents tab */
                     71:     xmlNodePtr        *txtTab; /* array of unparsed text nodes */
                     72:     URL            *txturlTab; /* array of unparsed txtuments URLs */
1.1       veillard   73: };
                     74: 
                     75: /**
                     76:  * xmlXIncludeAddNode:
                     77:  * @ctxt:  the XInclude context
                     78:  * @node:  the new node
                     79:  * 
                     80:  * Add a new node to process to an XInclude context
                     81:  */
                     82: void
                     83: xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
                     84:     if (ctxt->incMax == 0) {
                     85:        ctxt->incMax = 4;
                     86:         ctxt->incTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
                     87:                                          sizeof(ctxt->incTab[0]));
                     88:         if (ctxt->incTab == NULL) {
                     89:            xmlGenericError(xmlGenericErrorContext,
                     90:                    "malloc failed !\n");
                     91:            return;
                     92:        }
                     93:         ctxt->repTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
                     94:                                          sizeof(ctxt->repTab[0]));
                     95:         if (ctxt->repTab == NULL) {
                     96:            xmlGenericError(xmlGenericErrorContext,
                     97:                    "malloc failed !\n");
                     98:            return;
                     99:        }
                    100:     }
                    101:     if (ctxt->incNr >= ctxt->incMax) {
                    102:        ctxt->incMax *= 2;
                    103:         ctxt->incTab = (xmlNodePtr *) xmlRealloc(ctxt->incTab,
                    104:                     ctxt->incMax * sizeof(ctxt->incTab[0]));
                    105:         if (ctxt->incTab == NULL) {
                    106:            xmlGenericError(xmlGenericErrorContext,
                    107:                    "realloc failed !\n");
                    108:            return;
                    109:        }
                    110:         ctxt->repTab = (xmlNodePtr *) xmlRealloc(ctxt->repTab,
                    111:                     ctxt->incMax * sizeof(ctxt->repTab[0]));
                    112:         if (ctxt->repTab == NULL) {
                    113:            xmlGenericError(xmlGenericErrorContext,
                    114:                    "realloc failed !\n");
                    115:            return;
                    116:        }
                    117:     }
                    118:     ctxt->incTab[ctxt->incNr] = node;
1.3       veillard  119:     ctxt->repTab[ctxt->incNr] = NULL;
1.1       veillard  120:     ctxt->incNr++;
                    121: }
                    122: 
                    123: /**
                    124:  * xmlXIncludeAddDoc:
                    125:  * @ctxt:  the XInclude context
                    126:  * @doc:  the new document
                    127:  * @url:  the associated URL
                    128:  * 
                    129:  * Add a new document to the list
                    130:  */
                    131: void
                    132: xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const URL url) {
                    133:     if (ctxt->docMax == 0) {
                    134:        ctxt->docMax = 4;
                    135:         ctxt->docTab = (xmlDocPtr *) xmlMalloc(ctxt->docMax *
                    136:                                          sizeof(ctxt->docTab[0]));
                    137:         if (ctxt->docTab == NULL) {
                    138:            xmlGenericError(xmlGenericErrorContext,
                    139:                    "malloc failed !\n");
                    140:            return;
                    141:        }
                    142:         ctxt->urlTab = (URL *) xmlMalloc(ctxt->docMax *
                    143:                                          sizeof(ctxt->urlTab[0]));
                    144:         if (ctxt->urlTab == NULL) {
                    145:            xmlGenericError(xmlGenericErrorContext,
                    146:                    "malloc failed !\n");
                    147:            return;
                    148:        }
                    149:     }
                    150:     if (ctxt->docNr >= ctxt->docMax) {
                    151:        ctxt->docMax *= 2;
                    152:         ctxt->docTab = (xmlDocPtr *) xmlRealloc(ctxt->docTab,
                    153:                     ctxt->docMax * sizeof(ctxt->docTab[0]));
                    154:         if (ctxt->docTab == NULL) {
                    155:            xmlGenericError(xmlGenericErrorContext,
                    156:                    "realloc failed !\n");
                    157:            return;
                    158:        }
                    159:         ctxt->urlTab = (URL *) xmlRealloc(ctxt->urlTab,
                    160:                     ctxt->docMax * sizeof(ctxt->urlTab[0]));
                    161:         if (ctxt->urlTab == NULL) {
                    162:            xmlGenericError(xmlGenericErrorContext,
                    163:                    "realloc failed !\n");
                    164:            return;
                    165:        }
                    166:     }
                    167:     ctxt->docTab[ctxt->docNr] = doc;
                    168:     ctxt->urlTab[ctxt->docNr] = xmlStrdup(url);
                    169:     ctxt->docNr++;
                    170: }
                    171: 
                    172: /**
1.2       veillard  173:  * xmlXIncludeAddTxt:
                    174:  * @ctxt:  the XInclude context
                    175:  * @txt:  the new text node
                    176:  * @url:  the associated URL
                    177:  * 
                    178:  * Add a new txtument to the list
                    179:  */
                    180: void
                    181: xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const URL url) {
                    182:     if (ctxt->txtMax == 0) {
                    183:        ctxt->txtMax = 4;
                    184:         ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
                    185:                                          sizeof(ctxt->txtTab[0]));
                    186:         if (ctxt->txtTab == NULL) {
                    187:            xmlGenericError(xmlGenericErrorContext,
                    188:                    "malloc failed !\n");
                    189:            return;
                    190:        }
                    191:         ctxt->txturlTab = (URL *) xmlMalloc(ctxt->txtMax *
                    192:                                          sizeof(ctxt->txturlTab[0]));
                    193:         if (ctxt->txturlTab == NULL) {
                    194:            xmlGenericError(xmlGenericErrorContext,
                    195:                    "malloc failed !\n");
                    196:            return;
                    197:        }
                    198:     }
                    199:     if (ctxt->txtNr >= ctxt->txtMax) {
                    200:        ctxt->txtMax *= 2;
                    201:         ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
                    202:                     ctxt->txtMax * sizeof(ctxt->txtTab[0]));
                    203:         if (ctxt->txtTab == NULL) {
                    204:            xmlGenericError(xmlGenericErrorContext,
                    205:                    "realloc failed !\n");
                    206:            return;
                    207:        }
                    208:         ctxt->txturlTab = (URL *) xmlRealloc(ctxt->txturlTab,
                    209:                     ctxt->txtMax * sizeof(ctxt->urlTab[0]));
                    210:         if (ctxt->txturlTab == NULL) {
                    211:            xmlGenericError(xmlGenericErrorContext,
                    212:                    "realloc failed !\n");
                    213:            return;
                    214:        }
                    215:     }
                    216:     ctxt->txtTab[ctxt->txtNr] = txt;
                    217:     ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
                    218:     ctxt->txtNr++;
                    219: }
                    220: 
                    221: /**
1.1       veillard  222:  * xmlXIncludeNewContext:
                    223:  * @doc:  an XML Document
                    224:  *
                    225:  * Creates a new XInclude context
                    226:  *
                    227:  * Returns the new set
                    228:  */
                    229: xmlXIncludeCtxtPtr
                    230: xmlXIncludeNewContext(xmlDocPtr doc) {
                    231:     xmlXIncludeCtxtPtr ret;
                    232: 
                    233:     if (doc == NULL)
                    234:        return(NULL);
                    235:     ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
                    236:     if (ret == NULL)
                    237:        return(NULL);
                    238:     memset(ret, 0, sizeof(xmlXIncludeCtxt));
                    239:     ret->doc = doc;
                    240:     ret->incNr = 0;
                    241:     ret->incMax = 0;
                    242:     ret->incTab = NULL;
                    243:     ret->repTab = NULL;
                    244:     ret->docNr = 0;
                    245:     ret->docMax = 0;
                    246:     ret->docTab = NULL;
                    247:     ret->urlTab = NULL;
                    248:     return(ret);
                    249: }
                    250: 
                    251: /**
                    252:  * xmlXIncludeFreeContext:
                    253:  * @ctxt: the XInclude context
                    254:  *
                    255:  * Free an XInclude context
                    256:  */
                    257: void
                    258: xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
                    259:     if (ctxt == NULL)
                    260:        return;
                    261:     if (ctxt->incTab != NULL)
                    262:        xmlFree(ctxt->incTab);
                    263:     if (ctxt->repTab != NULL)
                    264:        xmlFree(ctxt->repTab);
                    265:     memset(ctxt, 0xeb, sizeof(xmlXIncludeCtxt));
                    266:     xmlFree(ctxt);
                    267: }
                    268: 
1.2       veillard  269: /************************************************************************
                    270:  *                                                                     *
                    271:  *                     XInclude I/O handling                           *
                    272:  *                                                                     *
                    273:  ************************************************************************/
                    274: 
                    275: /**
                    276:  * xmlXIncludeLoadDoc:
                    277:  * @ctxt:  the XInclude context
                    278:  * @url:  the associated URL
                    279:  * @nr:  the xinclude node number
                    280:  * 
                    281:  * Load the document, and store the result in the XInclude context
                    282:  */
                    283: void
                    284: xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
                    285:     xmlDocPtr doc;
                    286:     xmlURIPtr uri;
                    287:     xmlChar *URL;
                    288:     int i;
                    289:     /*
                    290:      * Check the URL and remove any fragment identifier
                    291:      */
                    292:     uri = xmlParseURI((const char *)url);
                    293:     if (uri == NULL) {
                    294:        xmlGenericError(xmlGenericErrorContext,
                    295:                    "XInclude: invalid value URI %s\n", url);
                    296:        return;
                    297:     }
                    298:     if (uri->fragment != NULL) {
                    299:        xmlFree(uri->fragment);
                    300:        uri->fragment = NULL; /* TODO: kkep it for later processing */
                    301:     }
                    302:     URL = xmlSaveUri(uri);
                    303:     xmlFreeURI(uri);
                    304:     if (URL == NULL) {
                    305:        xmlGenericError(xmlGenericErrorContext,
                    306:                    "XInclude: invalid value URI %s\n", url);
                    307:        return;
                    308:     }
                    309: 
                    310:     /*
                    311:      * Handling of references to the local document are done
                    312:      * directly through ctxt->doc.
                    313:      */
                    314:     if (URL[0] == 0) {
                    315:        xmlFree(URL);
                    316:        return;
                    317:     }
                    318: 
                    319:     /*
                    320:      * Prevent reloading twice the document.
                    321:      */
                    322:     for (i = 0; i < ctxt->docNr; i++) {
                    323:        if (xmlStrEqual(URL, ctxt->urlTab[i])) {
                    324:            doc = ctxt->docTab[i];
                    325:            goto loaded;
                    326:        }
                    327:     }
                    328:     /*
                    329:      * Load it.
                    330:      */
                    331:     doc = xmlParseFile((const char *)URL);
                    332:     if (doc == NULL) {
                    333:        xmlGenericError(xmlGenericErrorContext,
                    334:                    "XInclude: could not load %s\n", URL);
                    335:        xmlFree(URL);
                    336:        return;
                    337:     }
                    338:     xmlXIncludeAddDoc(ctxt, doc, URL);
                    339: 
                    340: loaded:
                    341:     /*
                    342:      * Add the top children list as the replacement copy.
                    343:      */
                    344:     ctxt->repTab[nr] = xmlCopyNodeList(doc->children);
                    345:     xmlFree(URL);
                    346: }
                    347: 
                    348: /**
                    349:  * xmlXIncludeLoadTxt:
                    350:  * @ctxt:  the XInclude context
                    351:  * @url:  the associated URL
                    352:  * @nr:  the xinclude node number
                    353:  * 
                    354:  * Load the content, and store the result in the XInclude context
                    355:  */
                    356: void
                    357: xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
                    358:     xmlParserInputBufferPtr buf;
                    359:     xmlNodePtr node;
                    360:     xmlURIPtr uri;
                    361:     xmlChar *URL;
                    362:     int i;
                    363:     /*
                    364:      * Check the URL and remove any fragment identifier
                    365:      */
                    366:     uri = xmlParseURI((const char *)url);
                    367:     if (uri == NULL) {
                    368:        xmlGenericError(xmlGenericErrorContext,
                    369:                    "XInclude: invalid value URI %s\n", url);
                    370:        return;
                    371:     }
                    372:     if (uri->fragment != NULL) {
                    373:        xmlFreeURI(uri);
                    374:        xmlGenericError(xmlGenericErrorContext,
                    375:                    "XInclude: fragment identifier forbidden for text\n");
                    376:        return;
                    377:     }
                    378:     URL = xmlSaveUri(uri);
                    379:     xmlFreeURI(uri);
                    380:     if (URL == NULL) {
                    381:        xmlGenericError(xmlGenericErrorContext,
                    382:                    "XInclude: invalid value URI %s\n", url);
                    383:        return;
                    384:     }
                    385: 
                    386:     /*
                    387:      * Handling of references to the local document are done
                    388:      * directly through ctxt->doc.
                    389:      */
                    390:     if (URL[0] == 0) {
                    391:        xmlGenericError(xmlGenericErrorContext,
                    392:                "XInclude: text serialization of document not available\n");
                    393:        xmlFree(URL);
                    394:        return;
                    395:     }
                    396: 
                    397:     /*
                    398:      * Prevent reloading twice the document.
                    399:      */
                    400:     for (i = 0; i < ctxt->txtNr; i++) {
                    401:        if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
                    402:            node = xmlCopyNode(ctxt->txtTab[i], 1);
                    403:            goto loaded;
                    404:        }
                    405:     }
                    406:     /*
                    407:      * Load it.
                    408:      * Issue 62: how to detect the encoding
                    409:      */
                    410:     buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
                    411:     if (buf == NULL) {
                    412:        xmlGenericError(xmlGenericErrorContext,
                    413:                    "XInclude: could not load %s\n", URL);
                    414:        xmlFree(URL);
                    415:        return;
                    416:     }
                    417:     node = xmlNewText(NULL);
                    418: 
                    419:     /*
                    420:      * Scan all chars from the resource and add the to the node
                    421:      */
                    422:     while (xmlParserInputBufferRead(buf, 128) > 0) {
                    423:        int len;
                    424:        const xmlChar *content;
                    425: 
                    426:        content = xmlBufferContent(buf->buffer);
                    427:        len = xmlBufferLength(buf->buffer);
                    428:        for (i = 0;i < len; i++) {
                    429:            /*
                    430:             * TODO: if the encoding issue is solved, scan UTF8 chars instead
                    431:             */
                    432:            if (!IS_CHAR(content[i])) {
                    433:                xmlGenericError(xmlGenericErrorContext,
                    434:                    "XInclude: %s contains invalid char %d\n", URL, content[i]);
                    435:            } else {
                    436:                xmlNodeAddContentLen(node, &content[i], 1);
                    437:            }
                    438:        }
                    439:        xmlBufferShrink(buf->buffer, len);
                    440:     }
                    441:     xmlFreeParserInputBuffer(buf);
                    442:     xmlXIncludeAddTxt(ctxt, node, URL);
                    443: 
                    444: loaded:
                    445:     /*
                    446:      * Add the element as the replacement copy.
                    447:      */
                    448:     ctxt->repTab[nr] = node;
                    449:     xmlFree(URL);
                    450: }
                    451: 
                    452: /************************************************************************
                    453:  *                                                                     *
                    454:  *                     XInclude Processing                             *
                    455:  *                                                                     *
                    456:  ************************************************************************/
                    457: 
1.1       veillard  458: /**
                    459:  * xmlXIncludePreProcessNode:
                    460:  * @ctxt: an XInclude context
                    461:  * @node: an XInclude node
                    462:  *
                    463:  * Implement the infoset replacement lookup on the XML element @node
                    464:  *
                    465:  * Returns the result list or NULL in case of error
                    466:  */
                    467: xmlNodePtr
                    468: xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
                    469:     xmlXIncludeAddNode(ctxt, node);
                    470:     return(0);
                    471: }
                    472: 
                    473: /**
                    474:  * xmlXIncludeLoadNode:
                    475:  * @ctxt: an XInclude context
                    476:  * @nr: the node number
                    477:  *
                    478:  * Find and load the infoset replacement for the given node.
                    479:  *
                    480:  * Returns 0 if substition succeeded, -1 if some processing failed
                    481:  */
                    482: int
1.2       veillard  483: xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1.1       veillard  484:     xmlNodePtr cur;
                    485:     xmlChar *href;
                    486:     xmlChar *parse;
                    487:     xmlChar *base;
                    488:     xmlChar *URI;
                    489:     int xml = 1; /* default Issue 64 */
                    490: 
                    491:     if (ctxt == NULL)
                    492:        return(-1);
                    493:     if ((nr < 0) || (nr >= ctxt->incNr))
                    494:        return(-1);
                    495:     cur = ctxt->incTab[nr];
                    496:     if (cur == NULL)
                    497:        return(-1);
                    498: 
                    499: #ifdef DEBUG_XINCLUDE
                    500:     xmlDebugDumpNode(stdout, cur, 0);
                    501: #endif
                    502:     /*
1.2       veillard  503:      * read the attributes
1.1       veillard  504:      */
                    505:     href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
                    506:     if (href == NULL) {
1.2       veillard  507:        href = xmlGetProp(cur, XINCLUDE_HREF);
                    508:        if (href == NULL) {
                    509:            xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
                    510:            return(-1);
                    511:        }
                    512:     }
                    513:     parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
                    514:     if (parse == NULL) {
                    515:        parse = xmlGetProp(cur, XINCLUDE_PARSE);
                    516:     }
                    517:     if (parse != NULL) {
                    518:        if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
                    519:            xml = 1;
                    520:        else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
                    521:            xml = 0;
                    522:        else {
                    523:            xmlGenericError(xmlGenericErrorContext,
                    524:                    "XInclude: invalid value %s for %s\n",
                    525:                            parse, XINCLUDE_PARSE);
                    526:            if (href != NULL)
                    527:                xmlFree(href);
                    528:            if (parse != NULL)
                    529:                xmlFree(parse);
                    530:            return(-1);
                    531:        }
                    532:     }
                    533: 
                    534:     /*
                    535:      * compute the URI
                    536:      */
                    537:     base = xmlNodeGetBase(ctxt->doc, cur);
                    538:     URI = xmlBuildURI(href, base);
                    539:     if (URI == NULL) {
                    540:        xmlChar *escbase;
                    541:        xmlChar *eschref;
                    542:        /*
                    543:         * Some escapeing may be needed
                    544:         */
                    545:        escbase = xmlURIEscape(base);
                    546:        eschref = xmlURIEscape(href);
                    547:        URI = xmlBuildURI(eschref, escbase);
                    548:        if (escbase != NULL)
                    549:            xmlFree(escbase);
                    550:        if (eschref != NULL)
                    551:            xmlFree(eschref);
                    552:     }
                    553:     if (URI == NULL) {
                    554:        xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
                    555:        if (parse != NULL)
                    556:            xmlFree(parse);
                    557:        if (href != NULL)
                    558:            xmlFree(href);
                    559:        if (base != NULL)
                    560:            xmlFree(base);
                    561:        return(-1);
                    562:     }
                    563: #ifdef DEBUG_XINCLUDE
                    564:     xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
                    565:            xml ? "xml": "text");
                    566:     xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
                    567: #endif
                    568: 
                    569:     /*
                    570:      * Cleanup
                    571:      */
                    572:     if (xml) {
                    573:        xmlXIncludeLoadDoc(ctxt, URI, nr);
                    574:        /* xmlXIncludeGetFragment(ctxt, cur, URI); */
                    575:     } else {
                    576:        xmlXIncludeLoadTxt(ctxt, URI, nr);
                    577:     }
                    578: 
                    579:     /*
                    580:      * Cleanup
                    581:      */
                    582:     if (URI != NULL)
                    583:        xmlFree(URI);
                    584:     if (parse != NULL)
                    585:        xmlFree(parse);
                    586:     if (href != NULL)
                    587:        xmlFree(href);
                    588:     if (base != NULL)
                    589:        xmlFree(base);
                    590:     return(0);
                    591: }
                    592: 
                    593: /**
                    594:  * xmlXIncludeIncludeNode:
                    595:  * @ctxt: an XInclude context
                    596:  * @nr: the node number
                    597:  *
                    598:  * Inplement the infoset replacement for the given node
                    599:  *
                    600:  * Returns 0 if substition succeeded, -1 if some processing failed
                    601:  */
                    602: int
                    603: xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
                    604:     xmlNodePtr cur, end, list;
                    605: 
                    606:     if (ctxt == NULL)
                    607:        return(-1);
                    608:     if ((nr < 0) || (nr >= ctxt->incNr))
                    609:        return(-1);
                    610:     cur = ctxt->incTab[nr];
                    611:     if (cur == NULL)
                    612:        return(-1);
                    613: 
                    614:     /*
                    615:      * Change the current node as an XInclude start one, and add an
                    616:      * entity end one
                    617:      */
                    618:     cur->type = XML_XINCLUDE_START;
                    619:     end = xmlNewNode(cur->ns, cur->name);
                    620:     if (end == NULL) {
                    621:        xmlGenericError(xmlGenericErrorContext, 
                    622:                "XInclude: failed to build node\n");
1.1       veillard  623:        return(-1);
                    624:     }
1.3       veillard  625:     end->type = XML_XINCLUDE_END;
                    626:     xmlAddNextSibling(cur, end);
1.2       veillard  627: 
                    628:     /*
                    629:      * Add the list of nodes
                    630:      */
                    631:     list = ctxt->repTab[nr];
                    632:     ctxt->repTab[nr] = NULL;
                    633:     while (list != NULL) {
                    634:        cur = list;
                    635:        list = list->next;
1.1       veillard  636: 
1.2       veillard  637:         xmlAddPrevSibling(end, cur);
1.1       veillard  638:     }
                    639:     return(0);
                    640: }
                    641: 
                    642: /**
                    643:  * xmlXIncludeTestNode:
                    644:  * @doc: an XML document
                    645:  * @node: an XInclude node
                    646:  *
                    647:  * test if the node is an XInclude node
                    648:  *
                    649:  * Returns 1 true, 0 otherwise
                    650:  */
                    651: int
                    652: xmlXIncludeTestNode(xmlDocPtr doc, xmlNodePtr node) {
                    653:     if (node == NULL)
                    654:        return(0);
                    655:     if (node->ns == NULL)
                    656:        return(0);
                    657:     if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
                    658:        (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
                    659:     return(0);
                    660: }
                    661: 
                    662: /**
                    663:  * xmlXIncludeProcess:
                    664:  * @doc: an XML document
                    665:  *
                    666:  * Implement the XInclude substitution on the XML document @doc
                    667:  *
                    668:  * Returns 0 if no substition were done, -1 if some processing failed
                    669:  *    or the number of substitutions done.
                    670:  */
                    671: int
                    672: xmlXIncludeProcess(xmlDocPtr doc) {
                    673:     xmlXIncludeCtxtPtr ctxt;
                    674:     xmlNodePtr cur;
                    675:     int ret = 0;
                    676:     int i;
                    677: 
                    678:     if (doc == NULL)
                    679:        return(-1);
                    680:     ctxt = xmlXIncludeNewContext(doc);
                    681:     if (ctxt == NULL)
                    682:        return(-1);
                    683: 
                    684:     /*
                    685:      * First phase: lookup the elements in the document
                    686:      */
                    687:     cur = xmlDocGetRootElement(doc);
                    688:     if (xmlXIncludeTestNode(doc, cur))
                    689:        xmlXIncludePreProcessNode(ctxt, cur);
                    690:     while (cur != NULL) {
1.3       veillard  691:        /* TODO: need to work on entities -> stack */
                    692:        if ((cur->children != NULL) &&
                    693:            (cur->children->type != XML_ENTITY_DECL)) {
                    694:            cur = cur->children;
                    695:            if (xmlXIncludeTestNode(doc, cur))
                    696:                xmlXIncludePreProcessNode(ctxt, cur);
1.1       veillard  697:        } else if (cur->next != NULL) {
                    698:            cur = cur->next;
                    699:            if (xmlXIncludeTestNode(doc, cur))
                    700:                xmlXIncludePreProcessNode(ctxt, cur);
                    701:        } else {
                    702:            do {
                    703:                cur = cur->parent;
                    704:                if (cur == NULL) break; /* do */
                    705:                if (cur->next != NULL) {
                    706:                    cur = cur->next;
                    707:                    if (xmlXIncludeTestNode(doc, cur))
                    708:                        xmlXIncludePreProcessNode(ctxt, cur);
                    709:                    break; /* do */
                    710:                }
                    711:            } while (cur != NULL);
                    712:        }
                    713:     }
                    714: 
                    715:     /*
                    716:      * Second Phase : collect the infosets fragments
                    717:      */
                    718:     for (i = 0;i < ctxt->incNr; i++) {
1.2       veillard  719:         xmlXIncludeLoadNode(ctxt, i);
1.1       veillard  720:     }
                    721: 
                    722:     /*
                    723:      * Third phase: extend the original document infoset.
                    724:      */
1.2       veillard  725:     for (i = 0;i < ctxt->incNr; i++) {
                    726:        xmlXIncludeIncludeNode(ctxt, i);
                    727:     }
1.1       veillard  728: 
                    729:     /*
                    730:      * Cleanup
                    731:      */
                    732:     xmlXIncludeFreeContext(ctxt);
                    733:     return(ret);
                    734: }
                    735: 
                    736: #else /* !LIBXML_XINCLUDE_ENABLED */
                    737: #endif

Webmaster