blob: dfd90abdb6fb16fb30a44109fefe7b4a7f311c10 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xinclude.c : Code to implement XInclude processing
3 *
Daniel Veillardbbd22452001-05-23 12:02:27 +00004 * World Wide Web Consortium W3C Last Call Working Draft 16 May 2001
5 * http://www.w3.org/TR/2001/WD-xinclude-20010516/
Owen Taylor3473f882001-02-23 17:55:21 +00006 *
7 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 */
11
12/*
13 * TODO: compute XPointers nodesets
Daniel Veillardd16df9f2001-05-23 13:44:21 +000014 * TODO: add an node intermediate API and handle recursion at this level
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Bjorn Reese70a9da52001-04-21 16:57:29 +000017#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000018
Owen Taylor3473f882001-02-23 17:55:21 +000019#include <string.h>
20#include <libxml/xmlmemory.h>
21#include <libxml/tree.h>
22#include <libxml/parser.h>
23#include <libxml/uri.h>
24#include <libxml/xpointer.h>
25#include <libxml/parserInternals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000026#include <libxml/xmlerror.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000027#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000028
29#ifdef LIBXML_XINCLUDE_ENABLED
30#include <libxml/xinclude.h>
31
Daniel Veillardbbd22452001-05-23 12:02:27 +000032#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
Owen Taylor3473f882001-02-23 17:55:21 +000033#define XINCLUDE_NODE (const xmlChar *) "include"
34#define XINCLUDE_HREF (const xmlChar *) "href"
35#define XINCLUDE_PARSE (const xmlChar *) "parse"
36#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
37#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
38
39/* #define DEBUG_XINCLUDE */
Daniel Veillard017b1082001-06-21 11:20:21 +000040#ifdef DEBUG_XINCLUDE
41#ifdef LIBXML_DEBUG_ENABLED
42#include <libxml/debugXML.h>
43#endif
44#endif
Owen Taylor3473f882001-02-23 17:55:21 +000045
46/************************************************************************
47 * *
48 * XInclude contexts handling *
49 * *
50 ************************************************************************/
51
52/*
53 * An XInclude context
54 */
Daniel Veillardedac3c92001-02-26 01:36:19 +000055typedef xmlChar *xmlURL;
Owen Taylor3473f882001-02-23 17:55:21 +000056typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
57typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
58struct _xmlXIncludeCtxt {
59 xmlDocPtr doc; /* the source document */
60 int incNr; /* number of includes */
61 int incMax; /* size of includes tab */
62 xmlNodePtr *incTab; /* array of include nodes */
63 xmlNodePtr *repTab; /* array of replacement node lists */
64 int docNr; /* number of parsed documents */
65 int docMax; /* size of parsed documents tab */
66 xmlDocPtr *docTab; /* array of parsed documents */
Daniel Veillardedac3c92001-02-26 01:36:19 +000067 xmlURL *urlTab; /* array of parsed documents URLs */
Owen Taylor3473f882001-02-23 17:55:21 +000068 int txtNr; /* number of unparsed documents */
69 int txtMax; /* size of unparsed documents tab */
70 xmlNodePtr *txtTab; /* array of unparsed text nodes */
Daniel Veillardedac3c92001-02-26 01:36:19 +000071 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
Owen Taylor3473f882001-02-23 17:55:21 +000072};
73
Daniel Veillardd16df9f2001-05-23 13:44:21 +000074static int
75xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc);
Owen Taylor3473f882001-02-23 17:55:21 +000076
77/**
78 * xmlXIncludeNewContext:
79 * @doc: an XML Document
80 *
81 * Creates a new XInclude context
82 *
83 * Returns the new set
84 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000085static xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +000086xmlXIncludeNewContext(xmlDocPtr doc) {
87 xmlXIncludeCtxtPtr ret;
88
89 if (doc == NULL)
90 return(NULL);
91 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
92 if (ret == NULL)
93 return(NULL);
94 memset(ret, 0, sizeof(xmlXIncludeCtxt));
95 ret->doc = doc;
96 ret->incNr = 0;
97 ret->incMax = 0;
98 ret->incTab = NULL;
99 ret->repTab = NULL;
100 ret->docNr = 0;
101 ret->docMax = 0;
102 ret->docTab = NULL;
103 ret->urlTab = NULL;
104 return(ret);
105}
106
107/**
108 * xmlXIncludeFreeContext:
109 * @ctxt: the XInclude context
110 *
111 * Free an XInclude context
112 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000113static void
Owen Taylor3473f882001-02-23 17:55:21 +0000114xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
115 int i;
116
117 if (ctxt == NULL)
118 return;
119 for (i = 0;i < ctxt->docNr;i++) {
120 xmlFreeDoc(ctxt->docTab[i]);
121 if (ctxt->urlTab[i] != NULL)
122 xmlFree(ctxt->urlTab[i]);
123 }
124 for (i = 0;i < ctxt->txtNr;i++) {
125 if (ctxt->txturlTab[i] != NULL)
126 xmlFree(ctxt->txturlTab[i]);
127 }
128 if (ctxt->incTab != NULL)
129 xmlFree(ctxt->incTab);
130 if (ctxt->repTab != NULL)
131 xmlFree(ctxt->repTab);
132 if (ctxt->urlTab != NULL)
133 xmlFree(ctxt->urlTab);
134 if (ctxt->docTab != NULL)
135 xmlFree(ctxt->docTab);
136 if (ctxt->txtTab != NULL)
137 xmlFree(ctxt->txtTab);
138 if (ctxt->txturlTab != NULL)
139 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000140 xmlFree(ctxt);
141}
142
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000143/**
144 * xmlXIncludeAddNode:
145 * @ctxt: the XInclude context
146 * @node: the new node
147 *
148 * Add a new node to process to an XInclude context
149 */
150static void
151xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
152 if (ctxt->incMax == 0) {
153 ctxt->incMax = 4;
154 ctxt->incTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
155 sizeof(ctxt->incTab[0]));
156 if (ctxt->incTab == NULL) {
157 xmlGenericError(xmlGenericErrorContext,
158 "malloc failed !\n");
159 return;
160 }
161 ctxt->repTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
162 sizeof(ctxt->repTab[0]));
163 if (ctxt->repTab == NULL) {
164 xmlGenericError(xmlGenericErrorContext,
165 "malloc failed !\n");
166 return;
167 }
168 }
169 if (ctxt->incNr >= ctxt->incMax) {
170 ctxt->incMax *= 2;
171 ctxt->incTab = (xmlNodePtr *) xmlRealloc(ctxt->incTab,
172 ctxt->incMax * sizeof(ctxt->incTab[0]));
173 if (ctxt->incTab == NULL) {
174 xmlGenericError(xmlGenericErrorContext,
175 "realloc failed !\n");
176 return;
177 }
178 ctxt->repTab = (xmlNodePtr *) xmlRealloc(ctxt->repTab,
179 ctxt->incMax * sizeof(ctxt->repTab[0]));
180 if (ctxt->repTab == NULL) {
181 xmlGenericError(xmlGenericErrorContext,
182 "realloc failed !\n");
183 return;
184 }
185 }
186 ctxt->incTab[ctxt->incNr] = node;
187 ctxt->repTab[ctxt->incNr] = NULL;
188 ctxt->incNr++;
189}
190
191/**
192 * xmlXIncludeAddDoc:
193 * @ctxt: the XInclude context
194 * @doc: the new document
195 * @url: the associated URL
196 *
197 * Add a new document to the list. The XInclude recursive nature is handled
198 * at this point.
199 */
200static void
201xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const xmlURL url) {
202 xmlXIncludeCtxtPtr newctxt;
203 int i;
204
205 if (ctxt->docMax == 0) {
206 ctxt->docMax = 4;
207 ctxt->docTab = (xmlDocPtr *) xmlMalloc(ctxt->docMax *
208 sizeof(ctxt->docTab[0]));
209 if (ctxt->docTab == NULL) {
210 xmlGenericError(xmlGenericErrorContext,
211 "malloc failed !\n");
212 return;
213 }
214 ctxt->urlTab = (xmlURL *) xmlMalloc(ctxt->docMax *
215 sizeof(ctxt->urlTab[0]));
216 if (ctxt->urlTab == NULL) {
217 xmlGenericError(xmlGenericErrorContext,
218 "malloc failed !\n");
219 return;
220 }
221 }
222 if (ctxt->docNr >= ctxt->docMax) {
223 ctxt->docMax *= 2;
224 ctxt->docTab = (xmlDocPtr *) xmlRealloc(ctxt->docTab,
225 ctxt->docMax * sizeof(ctxt->docTab[0]));
226 if (ctxt->docTab == NULL) {
227 xmlGenericError(xmlGenericErrorContext,
228 "realloc failed !\n");
229 return;
230 }
231 ctxt->urlTab = (xmlURL *) xmlRealloc(ctxt->urlTab,
232 ctxt->docMax * sizeof(ctxt->urlTab[0]));
233 if (ctxt->urlTab == NULL) {
234 xmlGenericError(xmlGenericErrorContext,
235 "realloc failed !\n");
236 return;
237 }
238 }
239 ctxt->docTab[ctxt->docNr] = doc;
240 ctxt->urlTab[ctxt->docNr] = xmlStrdup(url);
241 ctxt->docNr++;
242
243 /*
244 * Handle recursion here.
245 */
246
247 newctxt = xmlXIncludeNewContext(doc);
248 if (newctxt != NULL) {
249 /*
250 * Copy the existing document set
251 */
252 newctxt->docMax = ctxt->docMax;
253 newctxt->docNr = ctxt->docNr;
254 newctxt->docTab = (xmlDocPtr *) xmlMalloc(newctxt->docMax *
255 sizeof(newctxt->docTab[0]));
256 if (newctxt->docTab == NULL) {
257 xmlGenericError(xmlGenericErrorContext,
258 "malloc failed !\n");
259 xmlFree(newctxt);
260 return;
261 }
262 newctxt->urlTab = (xmlURL *) xmlMalloc(newctxt->docMax *
263 sizeof(newctxt->urlTab[0]));
264 if (ctxt->urlTab == NULL) {
265 xmlGenericError(xmlGenericErrorContext,
266 "malloc failed !\n");
267 xmlFree(newctxt);
268 return;
269 }
270
271 for (i = 0;i < ctxt->docNr;i++) {
272 newctxt->docTab[i] = ctxt->docTab[i];
273 newctxt->urlTab[i] = ctxt->urlTab[i];
274 }
275 xmlXIncludeDoProcess(newctxt, doc);
276 for (i = 0;i < ctxt->docNr;i++) {
277 newctxt->docTab[i] = NULL;
278 newctxt->urlTab[i] = NULL;
279 }
280 xmlXIncludeFreeContext(newctxt);
281 }
282}
283
284/**
285 * xmlXIncludeAddTxt:
286 * @ctxt: the XInclude context
287 * @txt: the new text node
288 * @url: the associated URL
289 *
290 * Add a new txtument to the list
291 */
292static void
293xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
294 if (ctxt->txtMax == 0) {
295 ctxt->txtMax = 4;
296 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
297 sizeof(ctxt->txtTab[0]));
298 if (ctxt->txtTab == NULL) {
299 xmlGenericError(xmlGenericErrorContext,
300 "malloc failed !\n");
301 return;
302 }
303 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
304 sizeof(ctxt->txturlTab[0]));
305 if (ctxt->txturlTab == NULL) {
306 xmlGenericError(xmlGenericErrorContext,
307 "malloc failed !\n");
308 return;
309 }
310 }
311 if (ctxt->txtNr >= ctxt->txtMax) {
312 ctxt->txtMax *= 2;
313 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
314 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
315 if (ctxt->txtTab == NULL) {
316 xmlGenericError(xmlGenericErrorContext,
317 "realloc failed !\n");
318 return;
319 }
320 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
321 ctxt->txtMax * sizeof(ctxt->urlTab[0]));
322 if (ctxt->txturlTab == NULL) {
323 xmlGenericError(xmlGenericErrorContext,
324 "realloc failed !\n");
325 return;
326 }
327 }
328 ctxt->txtTab[ctxt->txtNr] = txt;
329 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
330 ctxt->txtNr++;
331}
332
Owen Taylor3473f882001-02-23 17:55:21 +0000333/************************************************************************
334 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000335 * Node copy with specific semantic *
336 * *
337 ************************************************************************/
338
339/**
340 * xmlXIncludeCopyNode:
341 * @ctxt: the XInclude context
342 * @target: the document target
343 * @source: the document source
344 * @elem: the element
345 *
346 * Make a copy of the node while preserving the XInclude semantic
347 * of the Infoset copy
348 */
349static xmlNodePtr
350xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
351 xmlDocPtr source, xmlNodePtr elem) {
352 xmlNodePtr result = NULL;
353
354 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
355 (elem == NULL))
356 return(NULL);
357 if (elem->type == XML_DTD_NODE)
358 return(NULL);
359 result = xmlDocCopyNode(elem, target, 1);
360 return(result);
361}
362
363/**
364 * xmlXIncludeCopyNodeList:
365 * @ctxt: the XInclude context
366 * @target: the document target
367 * @source: the document source
368 * @elem: the element list
369 *
370 * Make a copy of the node list while preserving the XInclude semantic
371 * of the Infoset copy
372 */
373static xmlNodePtr
374xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
375 xmlDocPtr source, xmlNodePtr elem) {
376 xmlNodePtr cur, res, result = NULL, last = NULL;
377
378 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
379 (elem == NULL))
380 return(NULL);
381 cur = elem;
382 while (cur != NULL) {
383 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
384 if (res != NULL) {
385 if (result == NULL) {
386 result = last = res;
387 } else {
388 last->next = res;
389 res->prev = last;
390 last = res;
391 }
392 }
393 cur = cur->next;
394 }
395 return(result);
396}
397
398/**
399 * xmlXInclueGetNthChild:
400 * @cur: the node
401 * @no: the child number
402 *
403 * Returns the @no'th element child of @cur or NULL
404 */
405static xmlNodePtr
406xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
407 int i;
408 if (cur == NULL)
409 return(cur);
410 cur = cur->children;
411 for (i = 0;i <= no;cur = cur->next) {
412 if (cur == NULL)
413 return(cur);
414 if ((cur->type == XML_ELEMENT_NODE) ||
415 (cur->type == XML_DOCUMENT_NODE) ||
416 (cur->type == XML_HTML_DOCUMENT_NODE)) {
417 i++;
418 if (i == no)
419 break;
420 }
421 }
422 return(cur);
423}
424
425xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
426
427/**
428 * xmlXIncludeCopyRange:
429 * @ctxt: the XInclude context
430 * @target: the document target
431 * @source: the document source
432 * @obj: the XPointer result from the evaluation.
433 *
434 * Build a node list tree copy of the XPointer result.
435 *
436 * Returns an xmlNodePtr list or NULL.
437 * the caller has to free the node tree.
438 */
439static xmlNodePtr
440xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
441 xmlDocPtr source, xmlXPathObjectPtr range) {
442 /* pointers to generated nodes */
443 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
444 /* pointers to traversal nodes */
445 xmlNodePtr start, cur, end;
446 int index1, index2;
447
448 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
449 (range == NULL))
450 return(NULL);
451 if (range->type != XPATH_RANGE)
452 return(NULL);
453 start = (xmlNodePtr) range->user;
454
455 if (start == NULL)
456 return(NULL);
457 end = range->user2;
458 if (end == NULL)
459 return(xmlDocCopyNode(start, target, 1));
460
461 cur = start;
462 index1 = range->index;
463 index2 = range->index2;
464 while (cur != NULL) {
465 if (cur == end) {
466 if (cur->type == XML_TEXT_NODE) {
467 const xmlChar *content = cur->content;
468 int len;
469
470 if (content == NULL) {
471 tmp = xmlNewTextLen(NULL, 0);
472 } else {
473 len = index2;
474 if ((cur == start) && (index1 > 1)) {
475 content += (index1 - 1);
476 len -= (index1 - 1);
477 index1 = 0;
478 } else {
479 len = index2;
480 }
481 tmp = xmlNewTextLen(content, len);
482 }
483 /* single sub text node selection */
484 if (list == NULL)
485 return(tmp);
486 /* prune and return full set */
487 if (last != NULL)
488 xmlAddNextSibling(last, tmp);
489 else
490 xmlAddChild(parent, tmp);
491 return(list);
492 } else {
493 tmp = xmlDocCopyNode(cur, target, 0);
494 if (list == NULL)
495 list = tmp;
496 else {
497 if (last != NULL)
498 xmlAddNextSibling(last, tmp);
499 else
500 xmlAddChild(parent, tmp);
501 }
502 last = NULL;
503 parent = tmp;
504
505 if (index2 > 1) {
506 end = xmlXIncludeGetNthChild(cur, index2 - 1);
507 index2 = 0;
508 }
509 if ((cur == start) && (index1 > 1)) {
510 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
511 index1 = 0;
512 } else {
513 cur = cur->children;
514 }
515 /*
516 * Now gather the remaining nodes from cur to end
517 */
518 continue; /* while */
519 }
520 } else if ((cur == start) &&
521 (list == NULL) /* looks superfluous but ... */ ) {
522 if ((cur->type == XML_TEXT_NODE) ||
523 (cur->type == XML_CDATA_SECTION_NODE)) {
524 const xmlChar *content = cur->content;
525
526 if (content == NULL) {
527 tmp = xmlNewTextLen(NULL, 0);
528 } else {
529 if (index1 > 1) {
530 content += (index1 - 1);
531 }
532 tmp = xmlNewText(content);
533 }
534 last = list = tmp;
535 } else {
536 if ((cur == start) && (index1 > 1)) {
537 tmp = xmlDocCopyNode(cur, target, 0);
538 list = tmp;
539 parent = tmp;
540 last = NULL;
541 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
542 index1 = 0;
543 /*
544 * Now gather the remaining nodes from cur to end
545 */
546 continue; /* while */
547 }
548 tmp = xmlDocCopyNode(cur, target, 1);
549 list = tmp;
550 parent = NULL;
551 last = tmp;
552 }
553 } else {
554 tmp = NULL;
555 switch (cur->type) {
556 case XML_DTD_NODE:
557 case XML_ELEMENT_DECL:
558 case XML_ATTRIBUTE_DECL:
559 case XML_ENTITY_NODE:
560 /* Do not copy DTD informations */
561 break;
562 case XML_ENTITY_DECL:
563 /* handle crossing entities -> stack needed */
564 break;
565 case XML_XINCLUDE_START:
566 case XML_XINCLUDE_END:
567 /* don't consider it part of the tree content */
568 break;
569 case XML_ATTRIBUTE_NODE:
570 /* Humm, should not happen ! */
571 break;
572 default:
573 tmp = xmlDocCopyNode(cur, target, 1);
574 break;
575 }
576 if (tmp != NULL) {
577 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
578 return(NULL);
579 }
580 if (last != NULL)
581 xmlAddNextSibling(last, tmp);
582 else {
583 xmlAddChild(parent, tmp);
584 last = tmp;
585 }
586 }
587 }
588 /*
589 * Skip to next node in document order
590 */
591 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
592 return(NULL);
593 }
594 cur = xmlXPtrAdvanceNode(cur);
595 }
596 return(list);
597}
598
599/**
600 * xmlXIncludeBuildNodeList:
601 * @ctxt: the XInclude context
602 * @target: the document target
603 * @source: the document source
604 * @obj: the XPointer result from the evaluation.
605 *
606 * Build a node list tree copy of the XPointer result.
607 * This will drop Attributes and Namespace declarations.
608 *
609 * Returns an xmlNodePtr list or NULL.
610 * the caller has to free the node tree.
611 */
612static xmlNodePtr
613xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
614 xmlDocPtr source, xmlXPathObjectPtr obj) {
615 xmlNodePtr list = NULL, last = NULL;
616 int i;
617
618 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
619 (obj == NULL))
620 return(NULL);
621 switch (obj->type) {
622 case XPATH_NODESET: {
623 xmlNodeSetPtr set = obj->nodesetval;
624 if (set == NULL)
625 return(NULL);
626 for (i = 0;i < set->nodeNr;i++) {
627 if (set->nodeTab[i] == NULL)
628 continue;
629 switch (set->nodeTab[i]->type) {
630 case XML_TEXT_NODE:
631 case XML_CDATA_SECTION_NODE:
632 case XML_ELEMENT_NODE:
633 case XML_ENTITY_REF_NODE:
634 case XML_ENTITY_NODE:
635 case XML_PI_NODE:
636 case XML_COMMENT_NODE:
637 case XML_DOCUMENT_NODE:
638 case XML_HTML_DOCUMENT_NODE:
639#ifdef LIBXML_DOCB_ENABLED
640 case XML_DOCB_DOCUMENT_NODE:
641#endif
642 case XML_XINCLUDE_START:
643 case XML_XINCLUDE_END:
644 break;
645 case XML_ATTRIBUTE_NODE:
646 case XML_NAMESPACE_DECL:
647 case XML_DOCUMENT_TYPE_NODE:
648 case XML_DOCUMENT_FRAG_NODE:
649 case XML_NOTATION_NODE:
650 case XML_DTD_NODE:
651 case XML_ELEMENT_DECL:
652 case XML_ATTRIBUTE_DECL:
653 case XML_ENTITY_DECL:
654 continue; /* for */
655 }
656 if (last == NULL)
657 list = last = xmlXIncludeCopyNode(ctxt, target, source,
658 set->nodeTab[i]);
659 else {
660 xmlAddNextSibling(last,
661 xmlXIncludeCopyNode(ctxt, target, source,
662 set->nodeTab[i]));
663 if (last->next != NULL)
664 last = last->next;
665 }
666 }
667 break;
668 }
669 case XPATH_LOCATIONSET: {
670 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
671 if (set == NULL)
672 return(NULL);
673 for (i = 0;i < set->locNr;i++) {
674 if (last == NULL)
675 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
676 set->locTab[i]);
677 else
678 xmlAddNextSibling(last,
679 xmlXIncludeCopyXPointer(ctxt, target, source,
680 set->locTab[i]));
681 if (last != NULL) {
682 while (last->next != NULL)
683 last = last->next;
684 }
685 }
686 break;
687 }
688 case XPATH_RANGE:
689 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
690 case XPATH_POINT:
691 /* points are ignored in XInclude */
692 break;
693 default:
694 break;
695 }
696 return(list);
697}
698/************************************************************************
699 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000700 * XInclude I/O handling *
701 * *
702 ************************************************************************/
703
704/**
705 * xmlXIncludeLoadDoc:
706 * @ctxt: the XInclude context
707 * @url: the associated URL
708 * @nr: the xinclude node number
709 *
710 * Load the document, and store the result in the XInclude context
711 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000712static void
Owen Taylor3473f882001-02-23 17:55:21 +0000713xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
714 xmlDocPtr doc;
715 xmlURIPtr uri;
716 xmlChar *URL;
717 xmlChar *fragment = NULL;
718 int i;
719 /*
720 * Check the URL and remove any fragment identifier
721 */
722 uri = xmlParseURI((const char *)url);
723 if (uri == NULL) {
724 xmlGenericError(xmlGenericErrorContext,
725 "XInclude: invalid value URI %s\n", url);
726 return;
727 }
728 if (uri->fragment != NULL) {
729 fragment = (xmlChar *) uri->fragment;
730 uri->fragment = NULL;
731 }
732 URL = xmlSaveUri(uri);
733 xmlFreeURI(uri);
734 if (URL == NULL) {
735 xmlGenericError(xmlGenericErrorContext,
736 "XInclude: invalid value URI %s\n", url);
737 if (fragment != NULL)
738 xmlFree(fragment);
739 return;
740 }
741
742 /*
743 * Handling of references to the local document are done
744 * directly through ctxt->doc.
745 */
746 if ((URL[0] == 0) || (URL[0] == '#')) {
747 doc = NULL;
748 goto loaded;
749 }
750
751 /*
752 * Prevent reloading twice the document.
753 */
754 for (i = 0; i < ctxt->docNr; i++) {
755 if (xmlStrEqual(URL, ctxt->urlTab[i])) {
756 doc = ctxt->docTab[i];
757 goto loaded;
758 }
759 }
760 /*
761 * Load it.
762 */
763 doc = xmlParseFile((const char *)URL);
764 if (doc == NULL) {
765 xmlGenericError(xmlGenericErrorContext,
766 "XInclude: could not load %s\n", URL);
767 xmlFree(URL);
768 if (fragment != NULL)
769 xmlFree(fragment);
770 return;
771 }
772 xmlXIncludeAddDoc(ctxt, doc, URL);
773
774loaded:
775 if (fragment == NULL) {
776 /*
777 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +0000778 */
779 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +0000780 {
781 /* Hopefully a DTD declaration won't be copied from
782 * the same document */
Owen Taylor3473f882001-02-23 17:55:21 +0000783 ctxt->repTab[nr] = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000784 } else {
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000785 ctxt->repTab[nr] = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
786 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000787 }
Owen Taylor3473f882001-02-23 17:55:21 +0000788 } else {
789 /*
790 * Computes the XPointer expression and make a copy used
791 * as the replacement copy.
792 */
793 xmlXPathObjectPtr xptr;
794 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +0000795 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +0000796
797 if (doc == NULL) {
798 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr], NULL);
799 } else {
800 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
801 }
802 if (xptrctxt == NULL) {
803 xmlGenericError(xmlGenericErrorContext,
804 "XInclude: could create XPointer context\n");
805 xmlFree(URL);
806 xmlFree(fragment);
807 return;
808 }
809 xptr = xmlXPtrEval(fragment, xptrctxt);
810 if (xptr == NULL) {
811 xmlGenericError(xmlGenericErrorContext,
812 "XInclude: XPointer evaluation failed: #%s\n",
813 fragment);
814 xmlXPathFreeContext(xptrctxt);
815 xmlFree(URL);
816 xmlFree(fragment);
817 return;
818 }
Daniel Veillard39196eb2001-06-19 18:09:42 +0000819 switch (xptr->type) {
820 case XPATH_UNDEFINED:
821 case XPATH_BOOLEAN:
822 case XPATH_NUMBER:
823 case XPATH_STRING:
824 case XPATH_POINT:
825 case XPATH_USERS:
826 case XPATH_XSLT_TREE:
827 xmlGenericError(xmlGenericErrorContext,
828 "XInclude: XPointer is not a range: #%s\n",
829 fragment);
830 xmlXPathFreeContext(xptrctxt);
831 xmlFree(URL);
832 xmlFree(fragment);
833 return;
834 case XPATH_NODESET:
835 case XPATH_RANGE:
836 case XPATH_LOCATIONSET:
837 break;
838 }
839 set = xptr->nodesetval;
840 if (set != NULL) {
841 for (i = 0;i < set->nodeNr;i++) {
842 if (set->nodeTab[i] == NULL)
843 continue;
844 switch (set->nodeTab[i]->type) {
845 case XML_TEXT_NODE:
846 case XML_CDATA_SECTION_NODE:
847 case XML_ELEMENT_NODE:
848 case XML_ENTITY_REF_NODE:
849 case XML_ENTITY_NODE:
850 case XML_PI_NODE:
851 case XML_COMMENT_NODE:
852 case XML_DOCUMENT_NODE:
853 case XML_HTML_DOCUMENT_NODE:
854#ifdef LIBXML_DOCB_ENABLED
855 case XML_DOCB_DOCUMENT_NODE:
856#endif
857 continue;
858 case XML_ATTRIBUTE_NODE:
859 xmlGenericError(xmlGenericErrorContext,
860 "XInclude: XPointer selects an attribute: #%s\n",
861 fragment);
862 set->nodeTab[i] = NULL;
863 continue;
864 case XML_NAMESPACE_DECL:
865 xmlGenericError(xmlGenericErrorContext,
866 "XInclude: XPointer selects a namespace: #%s\n",
867 fragment);
868 set->nodeTab[i] = NULL;
869 continue;
870 case XML_DOCUMENT_TYPE_NODE:
871 case XML_DOCUMENT_FRAG_NODE:
872 case XML_NOTATION_NODE:
873 case XML_DTD_NODE:
874 case XML_ELEMENT_DECL:
875 case XML_ATTRIBUTE_DECL:
876 case XML_ENTITY_DECL:
877 case XML_XINCLUDE_START:
878 case XML_XINCLUDE_END:
879 xmlGenericError(xmlGenericErrorContext,
880 "XInclude: XPointer selects unexpected nodes: #%s\n",
881 fragment);
882 set->nodeTab[i] = NULL;
883 set->nodeTab[i] = NULL;
884 continue; /* for */
885 }
886 }
887 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000888 ctxt->repTab[nr] = xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
Owen Taylor3473f882001-02-23 17:55:21 +0000889 xmlXPathFreeObject(xptr);
890 xmlXPathFreeContext(xptrctxt);
891 xmlFree(fragment);
892 }
893 xmlFree(URL);
894}
895
896/**
897 * xmlXIncludeLoadTxt:
898 * @ctxt: the XInclude context
899 * @url: the associated URL
900 * @nr: the xinclude node number
901 *
902 * Load the content, and store the result in the XInclude context
903 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000904static void
Owen Taylor3473f882001-02-23 17:55:21 +0000905xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
906 xmlParserInputBufferPtr buf;
907 xmlNodePtr node;
908 xmlURIPtr uri;
909 xmlChar *URL;
910 int i;
911 /*
912 * Check the URL and remove any fragment identifier
913 */
914 uri = xmlParseURI((const char *)url);
915 if (uri == NULL) {
916 xmlGenericError(xmlGenericErrorContext,
917 "XInclude: invalid value URI %s\n", url);
918 return;
919 }
920 if (uri->fragment != NULL) {
921 xmlGenericError(xmlGenericErrorContext,
922 "XInclude: fragment identifier forbidden for text: %s\n",
923 uri->fragment);
924 xmlFreeURI(uri);
925 return;
926 }
927 URL = xmlSaveUri(uri);
928 xmlFreeURI(uri);
929 if (URL == NULL) {
930 xmlGenericError(xmlGenericErrorContext,
931 "XInclude: invalid value URI %s\n", url);
932 return;
933 }
934
935 /*
936 * Handling of references to the local document are done
937 * directly through ctxt->doc.
938 */
939 if (URL[0] == 0) {
940 xmlGenericError(xmlGenericErrorContext,
941 "XInclude: text serialization of document not available\n");
942 xmlFree(URL);
943 return;
944 }
945
946 /*
947 * Prevent reloading twice the document.
948 */
949 for (i = 0; i < ctxt->txtNr; i++) {
950 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
951 node = xmlCopyNode(ctxt->txtTab[i], 1);
952 goto loaded;
953 }
954 }
955 /*
956 * Load it.
957 * Issue 62: how to detect the encoding
958 */
959 buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
960 if (buf == NULL) {
961 xmlGenericError(xmlGenericErrorContext,
962 "XInclude: could not load %s\n", URL);
963 xmlFree(URL);
964 return;
965 }
966 node = xmlNewText(NULL);
967
968 /*
969 * Scan all chars from the resource and add the to the node
970 */
971 while (xmlParserInputBufferRead(buf, 128) > 0) {
972 int len;
973 const xmlChar *content;
974
975 content = xmlBufferContent(buf->buffer);
976 len = xmlBufferLength(buf->buffer);
977 for (i = 0;i < len; i++) {
978 /*
979 * TODO: if the encoding issue is solved, scan UTF8 chars instead
980 */
981 if (!IS_CHAR(content[i])) {
982 xmlGenericError(xmlGenericErrorContext,
983 "XInclude: %s contains invalid char %d\n", URL, content[i]);
984 } else {
985 xmlNodeAddContentLen(node, &content[i], 1);
986 }
987 }
988 xmlBufferShrink(buf->buffer, len);
989 }
990 xmlFreeParserInputBuffer(buf);
991 xmlXIncludeAddTxt(ctxt, node, URL);
992
993loaded:
994 /*
995 * Add the element as the replacement copy.
996 */
997 ctxt->repTab[nr] = node;
998 xmlFree(URL);
999}
1000
1001/************************************************************************
1002 * *
1003 * XInclude Processing *
1004 * *
1005 ************************************************************************/
1006
1007/**
1008 * xmlXIncludePreProcessNode:
1009 * @ctxt: an XInclude context
1010 * @node: an XInclude node
1011 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001012 * Implement the XInclude preprocessing, currently just adding the element
1013 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001014 *
1015 * Returns the result list or NULL in case of error
1016 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001017static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001018xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1019 xmlXIncludeAddNode(ctxt, node);
1020 return(0);
1021}
1022
1023/**
1024 * xmlXIncludeLoadNode:
1025 * @ctxt: an XInclude context
1026 * @nr: the node number
1027 *
1028 * Find and load the infoset replacement for the given node.
1029 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001030 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001031 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001032static int
Owen Taylor3473f882001-02-23 17:55:21 +00001033xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1034 xmlNodePtr cur;
1035 xmlChar *href;
1036 xmlChar *parse;
1037 xmlChar *base;
1038 xmlChar *URI;
1039 int xml = 1; /* default Issue 64 */
1040
1041 if (ctxt == NULL)
1042 return(-1);
1043 if ((nr < 0) || (nr >= ctxt->incNr))
1044 return(-1);
1045 cur = ctxt->incTab[nr];
1046 if (cur == NULL)
1047 return(-1);
1048
1049#ifdef DEBUG_XINCLUDE
1050 xmlDebugDumpNode(stdout, cur, 0);
1051#endif
1052 /*
1053 * read the attributes
1054 */
1055 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1056 if (href == NULL) {
1057 href = xmlGetProp(cur, XINCLUDE_HREF);
1058 if (href == NULL) {
1059 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1060 return(-1);
1061 }
1062 }
1063 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1064 if (parse == NULL) {
1065 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1066 }
1067 if (parse != NULL) {
1068 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1069 xml = 1;
1070 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1071 xml = 0;
1072 else {
1073 xmlGenericError(xmlGenericErrorContext,
1074 "XInclude: invalid value %s for %s\n",
1075 parse, XINCLUDE_PARSE);
1076 if (href != NULL)
1077 xmlFree(href);
1078 if (parse != NULL)
1079 xmlFree(parse);
1080 return(-1);
1081 }
1082 }
1083
1084 /*
1085 * compute the URI
1086 */
1087 base = xmlNodeGetBase(ctxt->doc, cur);
1088 if (base == NULL) {
1089 URI = xmlBuildURI(href, ctxt->doc->URL);
1090 } else {
1091 URI = xmlBuildURI(href, base);
1092 }
1093 if (URI == NULL) {
1094 xmlChar *escbase;
1095 xmlChar *eschref;
1096 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001097 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001098 */
1099 escbase = xmlURIEscape(base);
1100 eschref = xmlURIEscape(href);
1101 URI = xmlBuildURI(eschref, escbase);
1102 if (escbase != NULL)
1103 xmlFree(escbase);
1104 if (eschref != NULL)
1105 xmlFree(eschref);
1106 }
1107 if (URI == NULL) {
1108 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1109 if (parse != NULL)
1110 xmlFree(parse);
1111 if (href != NULL)
1112 xmlFree(href);
1113 if (base != NULL)
1114 xmlFree(base);
1115 return(-1);
1116 }
1117#ifdef DEBUG_XINCLUDE
1118 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1119 xml ? "xml": "text");
1120 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1121#endif
1122
1123 /*
1124 * Cleanup
1125 */
1126 if (xml) {
1127 xmlXIncludeLoadDoc(ctxt, URI, nr);
1128 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1129 } else {
1130 xmlXIncludeLoadTxt(ctxt, URI, nr);
1131 }
1132
1133 /*
1134 * Cleanup
1135 */
1136 if (URI != NULL)
1137 xmlFree(URI);
1138 if (parse != NULL)
1139 xmlFree(parse);
1140 if (href != NULL)
1141 xmlFree(href);
1142 if (base != NULL)
1143 xmlFree(base);
1144 return(0);
1145}
1146
1147/**
1148 * xmlXIncludeIncludeNode:
1149 * @ctxt: an XInclude context
1150 * @nr: the node number
1151 *
1152 * Inplement the infoset replacement for the given node
1153 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001154 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001155 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001156static int
Owen Taylor3473f882001-02-23 17:55:21 +00001157xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1158 xmlNodePtr cur, end, list;
1159
1160 if (ctxt == NULL)
1161 return(-1);
1162 if ((nr < 0) || (nr >= ctxt->incNr))
1163 return(-1);
1164 cur = ctxt->incTab[nr];
1165 if (cur == NULL)
1166 return(-1);
1167
1168 /*
1169 * Change the current node as an XInclude start one, and add an
1170 * entity end one
1171 */
1172 cur->type = XML_XINCLUDE_START;
1173 end = xmlNewNode(cur->ns, cur->name);
1174 if (end == NULL) {
1175 xmlGenericError(xmlGenericErrorContext,
1176 "XInclude: failed to build node\n");
1177 return(-1);
1178 }
1179 end->type = XML_XINCLUDE_END;
1180 xmlAddNextSibling(cur, end);
1181
1182 /*
1183 * Add the list of nodes
1184 */
1185 list = ctxt->repTab[nr];
1186 ctxt->repTab[nr] = NULL;
1187 while (list != NULL) {
1188 cur = list;
1189 list = list->next;
1190
1191 xmlAddPrevSibling(end, cur);
1192 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001193
1194
Owen Taylor3473f882001-02-23 17:55:21 +00001195 return(0);
1196}
1197
1198/**
1199 * xmlXIncludeTestNode:
Owen Taylor3473f882001-02-23 17:55:21 +00001200 * @node: an XInclude node
1201 *
1202 * test if the node is an XInclude node
1203 *
1204 * Returns 1 true, 0 otherwise
1205 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001206static int
1207xmlXIncludeTestNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001208 if (node == NULL)
1209 return(0);
1210 if (node->ns == NULL)
1211 return(0);
1212 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
1213 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
1214 return(0);
1215}
1216
1217/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001218 * xmlXIncludeDoProcess:
1219 * @ctxt:
Owen Taylor3473f882001-02-23 17:55:21 +00001220 * @doc: an XML document
1221 *
1222 * Implement the XInclude substitution on the XML document @doc
1223 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001224 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001225 * or the number of substitutions done.
1226 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001227static int
1228xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001229 xmlNodePtr cur;
1230 int ret = 0;
1231 int i;
1232
1233 if (doc == NULL)
1234 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001235 if (ctxt == NULL)
1236 return(-1);
1237
1238 /*
1239 * First phase: lookup the elements in the document
1240 */
1241 cur = xmlDocGetRootElement(doc);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001242 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001243 xmlXIncludePreProcessNode(ctxt, cur);
1244 while (cur != NULL) {
1245 /* TODO: need to work on entities -> stack */
1246 if ((cur->children != NULL) &&
1247 (cur->children->type != XML_ENTITY_DECL)) {
1248 cur = cur->children;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001249 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001250 xmlXIncludePreProcessNode(ctxt, cur);
1251 } else if (cur->next != NULL) {
1252 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001253 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001254 xmlXIncludePreProcessNode(ctxt, cur);
1255 } else {
1256 do {
1257 cur = cur->parent;
1258 if (cur == NULL) break; /* do */
1259 if (cur->next != NULL) {
1260 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001261 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001262 xmlXIncludePreProcessNode(ctxt, cur);
1263 break; /* do */
1264 }
1265 } while (cur != NULL);
1266 }
1267 }
1268
1269 /*
1270 * Second Phase : collect the infosets fragments
1271 */
1272 for (i = 0;i < ctxt->incNr; i++) {
1273 xmlXIncludeLoadNode(ctxt, i);
1274 }
1275
1276 /*
1277 * Third phase: extend the original document infoset.
1278 */
1279 for (i = 0;i < ctxt->incNr; i++) {
1280 xmlXIncludeIncludeNode(ctxt, i);
1281 }
1282
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001283 return(ret);
1284}
1285
1286/**
1287 * xmlXIncludeProcess:
1288 * @doc: an XML document
1289 *
1290 * Implement the XInclude substitution on the XML document @doc
1291 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001292 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001293 * or the number of substitutions done.
1294 */
1295int
1296xmlXIncludeProcess(xmlDocPtr doc) {
1297 xmlXIncludeCtxtPtr ctxt;
1298 int ret = 0;
1299
1300 if (doc == NULL)
1301 return(-1);
1302 ctxt = xmlXIncludeNewContext(doc);
1303 if (ctxt == NULL)
1304 return(-1);
1305 ret = xmlXIncludeDoProcess(ctxt, doc);
1306
Owen Taylor3473f882001-02-23 17:55:21 +00001307 xmlXIncludeFreeContext(ctxt);
1308 return(ret);
1309}
1310
1311#else /* !LIBXML_XINCLUDE_ENABLED */
1312#endif