Annotation of XML/xinclude.c, revision 1.5

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) {
1.5     ! veillard  373:        xmlGenericError(xmlGenericErrorContext,
        !           374:                "XInclude: fragment identifier forbidden for text: %s\n",
        !           375:                uri->fragment);
1.2       veillard  376:        xmlFreeURI(uri);
                    377:        return;
                    378:     }
                    379:     URL = xmlSaveUri(uri);
                    380:     xmlFreeURI(uri);
                    381:     if (URL == NULL) {
                    382:        xmlGenericError(xmlGenericErrorContext,
                    383:                    "XInclude: invalid value URI %s\n", url);
                    384:        return;
                    385:     }
                    386: 
                    387:     /*
                    388:      * Handling of references to the local document are done
                    389:      * directly through ctxt->doc.
                    390:      */
                    391:     if (URL[0] == 0) {
                    392:        xmlGenericError(xmlGenericErrorContext,
                    393:                "XInclude: text serialization of document not available\n");
                    394:        xmlFree(URL);
                    395:        return;
                    396:     }
                    397: 
                    398:     /*
                    399:      * Prevent reloading twice the document.
                    400:      */
                    401:     for (i = 0; i < ctxt->txtNr; i++) {
                    402:        if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
                    403:            node = xmlCopyNode(ctxt->txtTab[i], 1);
                    404:            goto loaded;
                    405:        }
                    406:     }
                    407:     /*
                    408:      * Load it.
                    409:      * Issue 62: how to detect the encoding
                    410:      */
                    411:     buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
                    412:     if (buf == NULL) {
                    413:        xmlGenericError(xmlGenericErrorContext,
                    414:                    "XInclude: could not load %s\n", URL);
                    415:        xmlFree(URL);
                    416:        return;
                    417:     }
                    418:     node = xmlNewText(NULL);
                    419: 
                    420:     /*
                    421:      * Scan all chars from the resource and add the to the node
                    422:      */
                    423:     while (xmlParserInputBufferRead(buf, 128) > 0) {
                    424:        int len;
                    425:        const xmlChar *content;
                    426: 
                    427:        content = xmlBufferContent(buf->buffer);
                    428:        len = xmlBufferLength(buf->buffer);
                    429:        for (i = 0;i < len; i++) {
                    430:            /*
                    431:             * TODO: if the encoding issue is solved, scan UTF8 chars instead
                    432:             */
                    433:            if (!IS_CHAR(content[i])) {
                    434:                xmlGenericError(xmlGenericErrorContext,
                    435:                    "XInclude: %s contains invalid char %d\n", URL, content[i]);
                    436:            } else {
                    437:                xmlNodeAddContentLen(node, &content[i], 1);
                    438:            }
                    439:        }
                    440:        xmlBufferShrink(buf->buffer, len);
                    441:     }
                    442:     xmlFreeParserInputBuffer(buf);
                    443:     xmlXIncludeAddTxt(ctxt, node, URL);
                    444: 
                    445: loaded:
                    446:     /*
                    447:      * Add the element as the replacement copy.
                    448:      */
                    449:     ctxt->repTab[nr] = node;
                    450:     xmlFree(URL);
                    451: }
                    452: 
                    453: /************************************************************************
                    454:  *                                                                     *
                    455:  *                     XInclude Processing                             *
                    456:  *                                                                     *
                    457:  ************************************************************************/
                    458: 
1.1       veillard  459: /**
                    460:  * xmlXIncludePreProcessNode:
                    461:  * @ctxt: an XInclude context
                    462:  * @node: an XInclude node
                    463:  *
                    464:  * Implement the infoset replacement lookup on the XML element @node
                    465:  *
                    466:  * Returns the result list or NULL in case of error
                    467:  */
                    468: xmlNodePtr
                    469: xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
                    470:     xmlXIncludeAddNode(ctxt, node);
                    471:     return(0);
                    472: }
                    473: 
                    474: /**
                    475:  * xmlXIncludeLoadNode:
                    476:  * @ctxt: an XInclude context
                    477:  * @nr: the node number
                    478:  *
                    479:  * Find and load the infoset replacement for the given node.
                    480:  *
                    481:  * Returns 0 if substition succeeded, -1 if some processing failed
                    482:  */
                    483: int
1.2       veillard  484: xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1.1       veillard  485:     xmlNodePtr cur;
                    486:     xmlChar *href;
                    487:     xmlChar *parse;
                    488:     xmlChar *base;
                    489:     xmlChar *URI;
                    490:     int xml = 1; /* default Issue 64 */
                    491: 
                    492:     if (ctxt == NULL)
                    493:        return(-1);
                    494:     if ((nr < 0) || (nr >= ctxt->incNr))
                    495:        return(-1);
                    496:     cur = ctxt->incTab[nr];
                    497:     if (cur == NULL)
                    498:        return(-1);
                    499: 
                    500: #ifdef DEBUG_XINCLUDE
                    501:     xmlDebugDumpNode(stdout, cur, 0);
                    502: #endif
                    503:     /*
1.2       veillard  504:      * read the attributes
1.1       veillard  505:      */
                    506:     href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
                    507:     if (href == NULL) {
1.2       veillard  508:        href = xmlGetProp(cur, XINCLUDE_HREF);
                    509:        if (href == NULL) {
                    510:            xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
                    511:            return(-1);
                    512:        }
                    513:     }
                    514:     parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
                    515:     if (parse == NULL) {
                    516:        parse = xmlGetProp(cur, XINCLUDE_PARSE);
                    517:     }
                    518:     if (parse != NULL) {
                    519:        if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
                    520:            xml = 1;
                    521:        else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
                    522:            xml = 0;
                    523:        else {
                    524:            xmlGenericError(xmlGenericErrorContext,
                    525:                    "XInclude: invalid value %s for %s\n",
                    526:                            parse, XINCLUDE_PARSE);
                    527:            if (href != NULL)
                    528:                xmlFree(href);
                    529:            if (parse != NULL)
                    530:                xmlFree(parse);
                    531:            return(-1);
                    532:        }
                    533:     }
                    534: 
                    535:     /*
                    536:      * compute the URI
                    537:      */
                    538:     base = xmlNodeGetBase(ctxt->doc, cur);
                    539:     URI = xmlBuildURI(href, base);
                    540:     if (URI == NULL) {
                    541:        xmlChar *escbase;
                    542:        xmlChar *eschref;
                    543:        /*
                    544:         * Some escapeing may be needed
                    545:         */
                    546:        escbase = xmlURIEscape(base);
                    547:        eschref = xmlURIEscape(href);
                    548:        URI = xmlBuildURI(eschref, escbase);
                    549:        if (escbase != NULL)
                    550:            xmlFree(escbase);
                    551:        if (eschref != NULL)
                    552:            xmlFree(eschref);
                    553:     }
                    554:     if (URI == NULL) {
                    555:        xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
                    556:        if (parse != NULL)
                    557:            xmlFree(parse);
                    558:        if (href != NULL)
                    559:            xmlFree(href);
                    560:        if (base != NULL)
                    561:            xmlFree(base);
                    562:        return(-1);
                    563:     }
                    564: #ifdef DEBUG_XINCLUDE
                    565:     xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
                    566:            xml ? "xml": "text");
                    567:     xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
                    568: #endif
                    569: 
                    570:     /*
                    571:      * Cleanup
                    572:      */
                    573:     if (xml) {
                    574:        xmlXIncludeLoadDoc(ctxt, URI, nr);
                    575:        /* xmlXIncludeGetFragment(ctxt, cur, URI); */
                    576:     } else {
                    577:        xmlXIncludeLoadTxt(ctxt, URI, nr);
                    578:     }
                    579: 
                    580:     /*
                    581:      * Cleanup
                    582:      */
                    583:     if (URI != NULL)
                    584:        xmlFree(URI);
                    585:     if (parse != NULL)
                    586:        xmlFree(parse);
                    587:     if (href != NULL)
                    588:        xmlFree(href);
                    589:     if (base != NULL)
                    590:        xmlFree(base);
                    591:     return(0);
                    592: }
                    593: 
                    594: /**
                    595:  * xmlXIncludeIncludeNode:
                    596:  * @ctxt: an XInclude context
                    597:  * @nr: the node number
                    598:  *
                    599:  * Inplement the infoset replacement for the given node
                    600:  *
                    601:  * Returns 0 if substition succeeded, -1 if some processing failed
                    602:  */
                    603: int
                    604: xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
                    605:     xmlNodePtr cur, end, list;
                    606: 
                    607:     if (ctxt == NULL)
                    608:        return(-1);
                    609:     if ((nr < 0) || (nr >= ctxt->incNr))
                    610:        return(-1);
                    611:     cur = ctxt->incTab[nr];
                    612:     if (cur == NULL)
                    613:        return(-1);
                    614: 
                    615:     /*
                    616:      * Change the current node as an XInclude start one, and add an
                    617:      * entity end one
                    618:      */
                    619:     cur->type = XML_XINCLUDE_START;
                    620:     end = xmlNewNode(cur->ns, cur->name);
                    621:     if (end == NULL) {
                    622:        xmlGenericError(xmlGenericErrorContext, 
                    623:                "XInclude: failed to build node\n");
1.1       veillard  624:        return(-1);
                    625:     }
1.3       veillard  626:     end->type = XML_XINCLUDE_END;
                    627:     xmlAddNextSibling(cur, end);
1.2       veillard  628: 
                    629:     /*
                    630:      * Add the list of nodes
                    631:      */
                    632:     list = ctxt->repTab[nr];
                    633:     ctxt->repTab[nr] = NULL;
                    634:     while (list != NULL) {
                    635:        cur = list;
                    636:        list = list->next;
1.1       veillard  637: 
1.2       veillard  638:         xmlAddPrevSibling(end, cur);
1.1       veillard  639:     }
                    640:     return(0);
                    641: }
                    642: 
                    643: /**
                    644:  * xmlXIncludeTestNode:
                    645:  * @doc: an XML document
                    646:  * @node: an XInclude node
                    647:  *
                    648:  * test if the node is an XInclude node
                    649:  *
                    650:  * Returns 1 true, 0 otherwise
                    651:  */
                    652: int
                    653: xmlXIncludeTestNode(xmlDocPtr doc, xmlNodePtr node) {
                    654:     if (node == NULL)
                    655:        return(0);
                    656:     if (node->ns == NULL)
                    657:        return(0);
                    658:     if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
                    659:        (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
                    660:     return(0);
                    661: }
                    662: 
                    663: /**
                    664:  * xmlXIncludeProcess:
                    665:  * @doc: an XML document
                    666:  *
                    667:  * Implement the XInclude substitution on the XML document @doc
                    668:  *
                    669:  * Returns 0 if no substition were done, -1 if some processing failed
                    670:  *    or the number of substitutions done.
                    671:  */
                    672: int
                    673: xmlXIncludeProcess(xmlDocPtr doc) {
                    674:     xmlXIncludeCtxtPtr ctxt;
                    675:     xmlNodePtr cur;
                    676:     int ret = 0;
                    677:     int i;
                    678: 
                    679:     if (doc == NULL)
                    680:        return(-1);
                    681:     ctxt = xmlXIncludeNewContext(doc);
                    682:     if (ctxt == NULL)
                    683:        return(-1);
                    684: 
                    685:     /*
                    686:      * First phase: lookup the elements in the document
                    687:      */
                    688:     cur = xmlDocGetRootElement(doc);
                    689:     if (xmlXIncludeTestNode(doc, cur))
                    690:        xmlXIncludePreProcessNode(ctxt, cur);
                    691:     while (cur != NULL) {
1.3       veillard  692:        /* TODO: need to work on entities -> stack */
                    693:        if ((cur->children != NULL) &&
                    694:            (cur->children->type != XML_ENTITY_DECL)) {
                    695:            cur = cur->children;
                    696:            if (xmlXIncludeTestNode(doc, cur))
                    697:                xmlXIncludePreProcessNode(ctxt, cur);
1.1       veillard  698:        } else if (cur->next != NULL) {
                    699:            cur = cur->next;
                    700:            if (xmlXIncludeTestNode(doc, cur))
                    701:                xmlXIncludePreProcessNode(ctxt, cur);
                    702:        } else {
                    703:            do {
                    704:                cur = cur->parent;
                    705:                if (cur == NULL) break; /* do */
                    706:                if (cur->next != NULL) {
                    707:                    cur = cur->next;
                    708:                    if (xmlXIncludeTestNode(doc, cur))
                    709:                        xmlXIncludePreProcessNode(ctxt, cur);
                    710:                    break; /* do */
                    711:                }
                    712:            } while (cur != NULL);
                    713:        }
                    714:     }
                    715: 
                    716:     /*
                    717:      * Second Phase : collect the infosets fragments
                    718:      */
                    719:     for (i = 0;i < ctxt->incNr; i++) {
1.2       veillard  720:         xmlXIncludeLoadNode(ctxt, i);
1.1       veillard  721:     }
                    722: 
                    723:     /*
                    724:      * Third phase: extend the original document infoset.
                    725:      */
1.2       veillard  726:     for (i = 0;i < ctxt->incNr; i++) {
                    727:        xmlXIncludeIncludeNode(ctxt, i);
                    728:     }
1.1       veillard  729: 
                    730:     /*
                    731:      * Cleanup
                    732:      */
                    733:     xmlXIncludeFreeContext(ctxt);
                    734:     return(ret);
                    735: }
                    736: 
                    737: #else /* !LIBXML_XINCLUDE_ENABLED */
                    738: #endif

Webmaster