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