Annotation of XML/xinclude.c, revision 1.6

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;
1.6     ! veillard  288:     xmlChar *fragment = NULL;
1.2       veillard  289:     int i;
                    290:     /*
                    291:      * Check the URL and remove any fragment identifier
                    292:      */
                    293:     uri = xmlParseURI((const char *)url);
                    294:     if (uri == NULL) {
                    295:        xmlGenericError(xmlGenericErrorContext,
                    296:                    "XInclude: invalid value URI %s\n", url);
                    297:        return;
                    298:     }
                    299:     if (uri->fragment != NULL) {
1.6     ! veillard  300:        fragment = (xmlChar *) uri->fragment;
        !           301:        uri->fragment = NULL;
1.2       veillard  302:     }
                    303:     URL = xmlSaveUri(uri);
                    304:     xmlFreeURI(uri);
                    305:     if (URL == NULL) {
                    306:        xmlGenericError(xmlGenericErrorContext,
                    307:                    "XInclude: invalid value URI %s\n", url);
1.6     ! veillard  308:        if (fragment != NULL)
        !           309:            xmlFree(fragment);
1.2       veillard  310:        return;
                    311:     }
                    312: 
                    313:     /*
                    314:      * Handling of references to the local document are done
                    315:      * directly through ctxt->doc.
                    316:      */
1.6     ! veillard  317:     if ((URL[0] == 0) || (URL[0] == '#')) {
        !           318:        doc = NULL;
        !           319:         goto loaded;
1.2       veillard  320:     }
                    321: 
                    322:     /*
                    323:      * Prevent reloading twice the document.
                    324:      */
                    325:     for (i = 0; i < ctxt->docNr; i++) {
                    326:        if (xmlStrEqual(URL, ctxt->urlTab[i])) {
                    327:            doc = ctxt->docTab[i];
                    328:            goto loaded;
                    329:        }
                    330:     }
                    331:     /*
                    332:      * Load it.
                    333:      */
                    334:     doc = xmlParseFile((const char *)URL);
                    335:     if (doc == NULL) {
                    336:        xmlGenericError(xmlGenericErrorContext,
                    337:                    "XInclude: could not load %s\n", URL);
                    338:        xmlFree(URL);
1.6     ! veillard  339:        if (fragment != NULL)
        !           340:            xmlFree(fragment);
1.2       veillard  341:        return;
                    342:     }
                    343:     xmlXIncludeAddDoc(ctxt, doc, URL);
                    344: 
                    345: loaded:
1.6     ! veillard  346:     if (fragment == NULL) {
        !           347:        /*
        !           348:         * Add the top children list as the replacement copy.
        !           349:         * ISSUE: seems we should scrap DTD info from the copied list.
        !           350:         */
        !           351:        if (doc == NULL)
        !           352:            ctxt->repTab[nr] = xmlCopyNodeList(ctxt->doc->children);
        !           353:        else
        !           354:            ctxt->repTab[nr] = xmlCopyNodeList(doc->children);
        !           355:     } else {
        !           356:        /*
        !           357:         * Computes the XPointer expression and make a copy used
        !           358:         * as the replacement copy.
        !           359:         */
        !           360:        xmlXPathObjectPtr xptr;
        !           361:        xmlXPathContextPtr xptrctxt;
        !           362: 
        !           363:        if (doc == NULL) {
        !           364:            xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr], NULL);
        !           365:        } else {
        !           366:            xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
        !           367:        }
        !           368:        if (xptrctxt == NULL) {
        !           369:            xmlGenericError(xmlGenericErrorContext,
        !           370:                        "XInclude: could create XPointer context\n");
        !           371:            xmlFree(URL);
        !           372:            xmlFree(fragment);
        !           373:            return;
        !           374:        }
        !           375:        xptr = xmlXPtrEval(fragment, xptrctxt);
        !           376:        if (xptr == NULL) {
        !           377:            xmlGenericError(xmlGenericErrorContext,
        !           378:                        "XInclude: XPointer evaluation failed: #%s\n",
        !           379:                        fragment);
        !           380:            xmlFree(URL);
        !           381:            xmlFree(fragment);
        !           382:            return;
        !           383:        }
        !           384:        ctxt->repTab[nr] = xmlXPtrBuildNodeList(xptr);
        !           385:        xmlXPathFreeObject(xptr);
        !           386:        xmlXPathFreeContext(xptrctxt);
        !           387:        xmlFree(fragment);
        !           388:     }
1.2       veillard  389:     xmlFree(URL);
                    390: }
                    391: 
                    392: /**
                    393:  * xmlXIncludeLoadTxt:
                    394:  * @ctxt:  the XInclude context
                    395:  * @url:  the associated URL
                    396:  * @nr:  the xinclude node number
                    397:  * 
                    398:  * Load the content, and store the result in the XInclude context
                    399:  */
                    400: void
                    401: xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
                    402:     xmlParserInputBufferPtr buf;
                    403:     xmlNodePtr node;
                    404:     xmlURIPtr uri;
                    405:     xmlChar *URL;
                    406:     int i;
                    407:     /*
                    408:      * Check the URL and remove any fragment identifier
                    409:      */
                    410:     uri = xmlParseURI((const char *)url);
                    411:     if (uri == NULL) {
                    412:        xmlGenericError(xmlGenericErrorContext,
                    413:                    "XInclude: invalid value URI %s\n", url);
                    414:        return;
                    415:     }
                    416:     if (uri->fragment != NULL) {
1.5       veillard  417:        xmlGenericError(xmlGenericErrorContext,
                    418:                "XInclude: fragment identifier forbidden for text: %s\n",
                    419:                uri->fragment);
1.2       veillard  420:        xmlFreeURI(uri);
                    421:        return;
                    422:     }
                    423:     URL = xmlSaveUri(uri);
                    424:     xmlFreeURI(uri);
                    425:     if (URL == NULL) {
                    426:        xmlGenericError(xmlGenericErrorContext,
                    427:                    "XInclude: invalid value URI %s\n", url);
                    428:        return;
                    429:     }
                    430: 
                    431:     /*
                    432:      * Handling of references to the local document are done
                    433:      * directly through ctxt->doc.
                    434:      */
                    435:     if (URL[0] == 0) {
                    436:        xmlGenericError(xmlGenericErrorContext,
                    437:                "XInclude: text serialization of document not available\n");
                    438:        xmlFree(URL);
                    439:        return;
                    440:     }
                    441: 
                    442:     /*
                    443:      * Prevent reloading twice the document.
                    444:      */
                    445:     for (i = 0; i < ctxt->txtNr; i++) {
                    446:        if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
                    447:            node = xmlCopyNode(ctxt->txtTab[i], 1);
                    448:            goto loaded;
                    449:        }
                    450:     }
                    451:     /*
                    452:      * Load it.
                    453:      * Issue 62: how to detect the encoding
                    454:      */
                    455:     buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
                    456:     if (buf == NULL) {
                    457:        xmlGenericError(xmlGenericErrorContext,
                    458:                    "XInclude: could not load %s\n", URL);
                    459:        xmlFree(URL);
                    460:        return;
                    461:     }
                    462:     node = xmlNewText(NULL);
                    463: 
                    464:     /*
                    465:      * Scan all chars from the resource and add the to the node
                    466:      */
                    467:     while (xmlParserInputBufferRead(buf, 128) > 0) {
                    468:        int len;
                    469:        const xmlChar *content;
                    470: 
                    471:        content = xmlBufferContent(buf->buffer);
                    472:        len = xmlBufferLength(buf->buffer);
                    473:        for (i = 0;i < len; i++) {
                    474:            /*
                    475:             * TODO: if the encoding issue is solved, scan UTF8 chars instead
                    476:             */
                    477:            if (!IS_CHAR(content[i])) {
                    478:                xmlGenericError(xmlGenericErrorContext,
                    479:                    "XInclude: %s contains invalid char %d\n", URL, content[i]);
                    480:            } else {
                    481:                xmlNodeAddContentLen(node, &content[i], 1);
                    482:            }
                    483:        }
                    484:        xmlBufferShrink(buf->buffer, len);
                    485:     }
                    486:     xmlFreeParserInputBuffer(buf);
                    487:     xmlXIncludeAddTxt(ctxt, node, URL);
                    488: 
                    489: loaded:
                    490:     /*
                    491:      * Add the element as the replacement copy.
                    492:      */
                    493:     ctxt->repTab[nr] = node;
                    494:     xmlFree(URL);
                    495: }
                    496: 
                    497: /************************************************************************
                    498:  *                                                                     *
                    499:  *                     XInclude Processing                             *
                    500:  *                                                                     *
                    501:  ************************************************************************/
                    502: 
1.1       veillard  503: /**
                    504:  * xmlXIncludePreProcessNode:
                    505:  * @ctxt: an XInclude context
                    506:  * @node: an XInclude node
                    507:  *
                    508:  * Implement the infoset replacement lookup on the XML element @node
                    509:  *
                    510:  * Returns the result list or NULL in case of error
                    511:  */
                    512: xmlNodePtr
                    513: xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
                    514:     xmlXIncludeAddNode(ctxt, node);
                    515:     return(0);
                    516: }
                    517: 
                    518: /**
                    519:  * xmlXIncludeLoadNode:
                    520:  * @ctxt: an XInclude context
                    521:  * @nr: the node number
                    522:  *
                    523:  * Find and load the infoset replacement for the given node.
                    524:  *
                    525:  * Returns 0 if substition succeeded, -1 if some processing failed
                    526:  */
                    527: int
1.2       veillard  528: xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1.1       veillard  529:     xmlNodePtr cur;
                    530:     xmlChar *href;
                    531:     xmlChar *parse;
                    532:     xmlChar *base;
                    533:     xmlChar *URI;
                    534:     int xml = 1; /* default Issue 64 */
                    535: 
                    536:     if (ctxt == NULL)
                    537:        return(-1);
                    538:     if ((nr < 0) || (nr >= ctxt->incNr))
                    539:        return(-1);
                    540:     cur = ctxt->incTab[nr];
                    541:     if (cur == NULL)
                    542:        return(-1);
                    543: 
                    544: #ifdef DEBUG_XINCLUDE
                    545:     xmlDebugDumpNode(stdout, cur, 0);
                    546: #endif
                    547:     /*
1.2       veillard  548:      * read the attributes
1.1       veillard  549:      */
                    550:     href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
                    551:     if (href == NULL) {
1.2       veillard  552:        href = xmlGetProp(cur, XINCLUDE_HREF);
                    553:        if (href == NULL) {
                    554:            xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
                    555:            return(-1);
                    556:        }
                    557:     }
                    558:     parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
                    559:     if (parse == NULL) {
                    560:        parse = xmlGetProp(cur, XINCLUDE_PARSE);
                    561:     }
                    562:     if (parse != NULL) {
                    563:        if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
                    564:            xml = 1;
                    565:        else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
                    566:            xml = 0;
                    567:        else {
                    568:            xmlGenericError(xmlGenericErrorContext,
                    569:                    "XInclude: invalid value %s for %s\n",
                    570:                            parse, XINCLUDE_PARSE);
                    571:            if (href != NULL)
                    572:                xmlFree(href);
                    573:            if (parse != NULL)
                    574:                xmlFree(parse);
                    575:            return(-1);
                    576:        }
                    577:     }
                    578: 
                    579:     /*
                    580:      * compute the URI
                    581:      */
                    582:     base = xmlNodeGetBase(ctxt->doc, cur);
                    583:     URI = xmlBuildURI(href, base);
                    584:     if (URI == NULL) {
                    585:        xmlChar *escbase;
                    586:        xmlChar *eschref;
                    587:        /*
                    588:         * Some escapeing may be needed
                    589:         */
                    590:        escbase = xmlURIEscape(base);
                    591:        eschref = xmlURIEscape(href);
                    592:        URI = xmlBuildURI(eschref, escbase);
                    593:        if (escbase != NULL)
                    594:            xmlFree(escbase);
                    595:        if (eschref != NULL)
                    596:            xmlFree(eschref);
                    597:     }
                    598:     if (URI == NULL) {
                    599:        xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
                    600:        if (parse != NULL)
                    601:            xmlFree(parse);
                    602:        if (href != NULL)
                    603:            xmlFree(href);
                    604:        if (base != NULL)
                    605:            xmlFree(base);
                    606:        return(-1);
                    607:     }
                    608: #ifdef DEBUG_XINCLUDE
                    609:     xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
                    610:            xml ? "xml": "text");
                    611:     xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
                    612: #endif
                    613: 
                    614:     /*
                    615:      * Cleanup
                    616:      */
                    617:     if (xml) {
                    618:        xmlXIncludeLoadDoc(ctxt, URI, nr);
                    619:        /* xmlXIncludeGetFragment(ctxt, cur, URI); */
                    620:     } else {
                    621:        xmlXIncludeLoadTxt(ctxt, URI, nr);
                    622:     }
                    623: 
                    624:     /*
                    625:      * Cleanup
                    626:      */
                    627:     if (URI != NULL)
                    628:        xmlFree(URI);
                    629:     if (parse != NULL)
                    630:        xmlFree(parse);
                    631:     if (href != NULL)
                    632:        xmlFree(href);
                    633:     if (base != NULL)
                    634:        xmlFree(base);
                    635:     return(0);
                    636: }
                    637: 
                    638: /**
                    639:  * xmlXIncludeIncludeNode:
                    640:  * @ctxt: an XInclude context
                    641:  * @nr: the node number
                    642:  *
                    643:  * Inplement the infoset replacement for the given node
                    644:  *
                    645:  * Returns 0 if substition succeeded, -1 if some processing failed
                    646:  */
                    647: int
                    648: xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
                    649:     xmlNodePtr cur, end, list;
                    650: 
                    651:     if (ctxt == NULL)
                    652:        return(-1);
                    653:     if ((nr < 0) || (nr >= ctxt->incNr))
                    654:        return(-1);
                    655:     cur = ctxt->incTab[nr];
                    656:     if (cur == NULL)
                    657:        return(-1);
                    658: 
                    659:     /*
                    660:      * Change the current node as an XInclude start one, and add an
                    661:      * entity end one
                    662:      */
                    663:     cur->type = XML_XINCLUDE_START;
                    664:     end = xmlNewNode(cur->ns, cur->name);
                    665:     if (end == NULL) {
                    666:        xmlGenericError(xmlGenericErrorContext, 
                    667:                "XInclude: failed to build node\n");
1.1       veillard  668:        return(-1);
                    669:     }
1.3       veillard  670:     end->type = XML_XINCLUDE_END;
                    671:     xmlAddNextSibling(cur, end);
1.2       veillard  672: 
                    673:     /*
                    674:      * Add the list of nodes
                    675:      */
                    676:     list = ctxt->repTab[nr];
                    677:     ctxt->repTab[nr] = NULL;
                    678:     while (list != NULL) {
                    679:        cur = list;
                    680:        list = list->next;
1.1       veillard  681: 
1.2       veillard  682:         xmlAddPrevSibling(end, cur);
1.1       veillard  683:     }
                    684:     return(0);
                    685: }
                    686: 
                    687: /**
                    688:  * xmlXIncludeTestNode:
                    689:  * @doc: an XML document
                    690:  * @node: an XInclude node
                    691:  *
                    692:  * test if the node is an XInclude node
                    693:  *
                    694:  * Returns 1 true, 0 otherwise
                    695:  */
                    696: int
                    697: xmlXIncludeTestNode(xmlDocPtr doc, xmlNodePtr node) {
                    698:     if (node == NULL)
                    699:        return(0);
                    700:     if (node->ns == NULL)
                    701:        return(0);
                    702:     if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
                    703:        (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
                    704:     return(0);
                    705: }
                    706: 
                    707: /**
                    708:  * xmlXIncludeProcess:
                    709:  * @doc: an XML document
                    710:  *
                    711:  * Implement the XInclude substitution on the XML document @doc
                    712:  *
                    713:  * Returns 0 if no substition were done, -1 if some processing failed
                    714:  *    or the number of substitutions done.
                    715:  */
                    716: int
                    717: xmlXIncludeProcess(xmlDocPtr doc) {
                    718:     xmlXIncludeCtxtPtr ctxt;
                    719:     xmlNodePtr cur;
                    720:     int ret = 0;
                    721:     int i;
                    722: 
                    723:     if (doc == NULL)
                    724:        return(-1);
                    725:     ctxt = xmlXIncludeNewContext(doc);
                    726:     if (ctxt == NULL)
                    727:        return(-1);
                    728: 
                    729:     /*
                    730:      * First phase: lookup the elements in the document
                    731:      */
                    732:     cur = xmlDocGetRootElement(doc);
                    733:     if (xmlXIncludeTestNode(doc, cur))
                    734:        xmlXIncludePreProcessNode(ctxt, cur);
                    735:     while (cur != NULL) {
1.3       veillard  736:        /* TODO: need to work on entities -> stack */
                    737:        if ((cur->children != NULL) &&
                    738:            (cur->children->type != XML_ENTITY_DECL)) {
                    739:            cur = cur->children;
                    740:            if (xmlXIncludeTestNode(doc, cur))
                    741:                xmlXIncludePreProcessNode(ctxt, cur);
1.1       veillard  742:        } else if (cur->next != NULL) {
                    743:            cur = cur->next;
                    744:            if (xmlXIncludeTestNode(doc, cur))
                    745:                xmlXIncludePreProcessNode(ctxt, cur);
                    746:        } else {
                    747:            do {
                    748:                cur = cur->parent;
                    749:                if (cur == NULL) break; /* do */
                    750:                if (cur->next != NULL) {
                    751:                    cur = cur->next;
                    752:                    if (xmlXIncludeTestNode(doc, cur))
                    753:                        xmlXIncludePreProcessNode(ctxt, cur);
                    754:                    break; /* do */
                    755:                }
                    756:            } while (cur != NULL);
                    757:        }
                    758:     }
                    759: 
                    760:     /*
                    761:      * Second Phase : collect the infosets fragments
                    762:      */
                    763:     for (i = 0;i < ctxt->incNr; i++) {
1.2       veillard  764:         xmlXIncludeLoadNode(ctxt, i);
1.1       veillard  765:     }
                    766: 
                    767:     /*
                    768:      * Third phase: extend the original document infoset.
                    769:      */
1.2       veillard  770:     for (i = 0;i < ctxt->incNr; i++) {
                    771:        xmlXIncludeIncludeNode(ctxt, i);
                    772:     }
1.1       veillard  773: 
                    774:     /*
                    775:      * Cleanup
                    776:      */
                    777:     xmlXIncludeFreeContext(ctxt);
                    778:     return(ret);
                    779: }
                    780: 
                    781: #else /* !LIBXML_XINCLUDE_ENABLED */
                    782: #endif

Webmaster