Annotation of XML/xinclude.c, revision 1.8

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

Webmaster