blob: b039ff5ceb5f742024900038d4271592a610a26c [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"
Daniel Veillard58e44c92002-08-02 22:19:49 +000035#define XINCLUDE_FALLBACK (const xmlChar *) "fallback"
Owen Taylor3473f882001-02-23 17:55:21 +000036#define XINCLUDE_HREF (const xmlChar *) "href"
37#define XINCLUDE_PARSE (const xmlChar *) "parse"
38#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
39#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
40
41/* #define DEBUG_XINCLUDE */
Daniel Veillard017b1082001-06-21 11:20:21 +000042#ifdef DEBUG_XINCLUDE
43#ifdef LIBXML_DEBUG_ENABLED
44#include <libxml/debugXML.h>
45#endif
46#endif
Owen Taylor3473f882001-02-23 17:55:21 +000047
48/************************************************************************
49 * *
50 * XInclude contexts handling *
51 * *
52 ************************************************************************/
53
54/*
55 * An XInclude context
56 */
Daniel Veillardedac3c92001-02-26 01:36:19 +000057typedef xmlChar *xmlURL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +000058
59typedef struct _xmlXIncludeRef xmlXIncludeRef;
60typedef xmlXIncludeRef *xmlXIncludeRefPtr;
61struct _xmlXIncludeRef {
62 xmlChar *URI; /* the rully resolved resource URL */
63 xmlChar *fragment; /* the fragment in the URI */
64 xmlDocPtr doc; /* the parsed document */
65 xmlNodePtr ref; /* the node making the reference in the source */
66 xmlNodePtr inc; /* the included copy */
67 int xml; /* xml or txt */
68 int count; /* how many refs use that specific doc */
69};
70
Owen Taylor3473f882001-02-23 17:55:21 +000071typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
72typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
73struct _xmlXIncludeCtxt {
74 xmlDocPtr doc; /* the source document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000075 int incBase; /* the first include for this document */
Owen Taylor3473f882001-02-23 17:55:21 +000076 int incNr; /* number of includes */
77 int incMax; /* size of includes tab */
Daniel Veillardbbc72c32002-09-05 10:52:10 +000078 xmlXIncludeRefPtr *incTab; /* array of included references */
79
Owen Taylor3473f882001-02-23 17:55:21 +000080 int txtNr; /* number of unparsed documents */
81 int txtMax; /* size of unparsed documents tab */
82 xmlNodePtr *txtTab; /* array of unparsed text nodes */
Daniel Veillardedac3c92001-02-26 01:36:19 +000083 xmlURL *txturlTab; /* array of unparsed txtuments URLs */
Owen Taylor3473f882001-02-23 17:55:21 +000084};
85
Daniel Veillardd16df9f2001-05-23 13:44:21 +000086static int
87xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc);
Owen Taylor3473f882001-02-23 17:55:21 +000088
89/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +000090 * xmlXIncludeFreeRef:
91 * @ref: the XInclude reference
92 *
93 * Free an XInclude reference
94 */
95static void
96xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
97 if (ref == NULL)
98 return;
99#ifdef DEBUG_XINCLUDE
100 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
101#endif
102 if (ref->doc != NULL) {
103#ifdef DEBUG_XINCLUDE
104 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
105#endif
106 xmlFreeDoc(ref->doc);
107 }
108 if (ref->URI != NULL)
109 xmlFree(ref->URI);
110 if (ref->fragment != NULL)
111 xmlFree(ref->fragment);
112 xmlFree(ref);
113}
114
115/**
116 * xmlXIncludeNewRef:
117 * @ctxt: the XInclude context
118 * @URI: the resource URI
119 *
120 * Creates a new reference within an XInclude context
121 *
122 * Returns the new set
123 */
124static xmlXIncludeRefPtr
125xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
126 xmlNodePtr ref) {
127 xmlXIncludeRefPtr ret;
128
129#ifdef DEBUG_XINCLUDE
130 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
131#endif
132 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
133 if (ret == NULL)
134 return(NULL);
135 memset(ret, 0, sizeof(xmlXIncludeRef));
136 if (URI == NULL)
137 ret->URI = NULL;
138 else
139 ret->URI = xmlStrdup(URI);
140 ret->fragment = NULL;
141 ret->ref = ref;
142 ret->doc = 0;
143 ret->count = 0;
144 ret->xml = 0;
145 ret->inc = NULL;
146 if (ctxt->incMax == 0) {
147 ctxt->incMax = 4;
148 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
149 sizeof(ctxt->incTab[0]));
150 if (ctxt->incTab == NULL) {
151 xmlGenericError(xmlGenericErrorContext,
152 "malloc failed !\n");
153 xmlXIncludeFreeRef(ret);
154 return(NULL);
155 }
156 }
157 if (ctxt->incNr >= ctxt->incMax) {
158 ctxt->incMax *= 2;
159 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
160 ctxt->incMax * sizeof(ctxt->incTab[0]));
161 if (ctxt->incTab == NULL) {
162 xmlGenericError(xmlGenericErrorContext,
163 "realloc failed !\n");
164 xmlXIncludeFreeRef(ret);
165 return(NULL);
166 }
167 }
168 ctxt->incTab[ctxt->incNr++] = ret;
169 return(ret);
170}
171
172/**
Owen Taylor3473f882001-02-23 17:55:21 +0000173 * xmlXIncludeNewContext:
174 * @doc: an XML Document
175 *
176 * Creates a new XInclude context
177 *
178 * Returns the new set
179 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000180static xmlXIncludeCtxtPtr
Owen Taylor3473f882001-02-23 17:55:21 +0000181xmlXIncludeNewContext(xmlDocPtr doc) {
182 xmlXIncludeCtxtPtr ret;
183
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000184#ifdef DEBUG_XINCLUDE
185 xmlGenericError(xmlGenericErrorContext, "New context\n");
186#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000187 if (doc == NULL)
188 return(NULL);
189 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
190 if (ret == NULL)
191 return(NULL);
192 memset(ret, 0, sizeof(xmlXIncludeCtxt));
193 ret->doc = doc;
194 ret->incNr = 0;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000195 ret->incBase = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000196 ret->incMax = 0;
197 ret->incTab = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000198 return(ret);
199}
200
201/**
202 * xmlXIncludeFreeContext:
203 * @ctxt: the XInclude context
204 *
205 * Free an XInclude context
206 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000207static void
Owen Taylor3473f882001-02-23 17:55:21 +0000208xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
209 int i;
210
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000211#ifdef DEBUG_XINCLUDE
212 xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
213#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000214 if (ctxt == NULL)
215 return;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000216 for (i = 0;i < ctxt->incNr;i++) {
217 if (ctxt->incTab[i] != NULL)
218 xmlXIncludeFreeRef(ctxt->incTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000219 }
220 for (i = 0;i < ctxt->txtNr;i++) {
221 if (ctxt->txturlTab[i] != NULL)
222 xmlFree(ctxt->txturlTab[i]);
223 }
224 if (ctxt->incTab != NULL)
225 xmlFree(ctxt->incTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000226 if (ctxt->txtTab != NULL)
227 xmlFree(ctxt->txtTab);
228 if (ctxt->txturlTab != NULL)
229 xmlFree(ctxt->txturlTab);
Owen Taylor3473f882001-02-23 17:55:21 +0000230 xmlFree(ctxt);
231}
232
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000233/**
234 * xmlXIncludeAddNode:
235 * @ctxt: the XInclude context
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000236 * @cur: the new node
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000237 *
238 * Add a new node to process to an XInclude context
239 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000240static int
241xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
242 xmlXIncludeRefPtr ref;
243 xmlURIPtr uri;
244 xmlChar *URL;
245 xmlChar *fragment = NULL;
246 xmlChar *href;
247 xmlChar *parse;
248 xmlChar *base;
249 xmlChar *URI;
250 int xml = 1; /* default Issue 64 */
251
252
253 if (ctxt == NULL)
254 return(-1);
255 if (cur == NULL)
256 return(-1);
257
258#ifdef DEBUG_XINCLUDE
259 xmlGenericError(xmlGenericErrorContext, "Add node\n");
260#endif
261 /*
262 * read the attributes
263 */
264 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
265 if (href == NULL) {
266 href = xmlGetProp(cur, XINCLUDE_HREF);
267 if (href == NULL) {
268 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
269 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000270 }
271 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000272 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
273 if (parse == NULL) {
274 parse = xmlGetProp(cur, XINCLUDE_PARSE);
275 }
276 if (parse != NULL) {
277 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
278 xml = 1;
279 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
280 xml = 0;
281 else {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000282 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000283 "XInclude: invalid value %s for %s\n",
284 parse, XINCLUDE_PARSE);
285 if (href != NULL)
286 xmlFree(href);
287 if (parse != NULL)
288 xmlFree(parse);
289 return(-1);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000290 }
291 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000292
293 /*
294 * compute the URI
295 */
296 base = xmlNodeGetBase(ctxt->doc, cur);
297 if (base == NULL) {
298 URI = xmlBuildURI(href, ctxt->doc->URL);
299 } else {
300 URI = xmlBuildURI(href, base);
301 }
302 if (URI == NULL) {
303 xmlChar *escbase;
304 xmlChar *eschref;
305 /*
306 * Some escaping may be needed
307 */
308 escbase = xmlURIEscape(base);
309 eschref = xmlURIEscape(href);
310 URI = xmlBuildURI(eschref, escbase);
311 if (escbase != NULL)
312 xmlFree(escbase);
313 if (eschref != NULL)
314 xmlFree(eschref);
315 }
316 if (parse != NULL)
317 xmlFree(parse);
318 if (href != NULL)
319 xmlFree(href);
320 if (base != NULL)
321 xmlFree(base);
322 if (URI == NULL) {
323 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
324 return(-1);
325 }
326
327 /*
328 * Check the URL and remove any fragment identifier
329 */
330 uri = xmlParseURI((const char *)URI);
331 if (uri == NULL) {
332 xmlGenericError(xmlGenericErrorContext,
333 "XInclude: invalid value URI %s\n", URI);
334 return(-1);
335 }
336 if (uri->fragment != NULL) {
337 fragment = (xmlChar *) uri->fragment;
338 uri->fragment = NULL;
339 }
340 URL = xmlSaveUri(uri);
341 xmlFreeURI(uri);
342 xmlFree(URI);
343 if (URL == NULL) {
344 xmlGenericError(xmlGenericErrorContext,
345 "XInclude: invalid value URI %s\n", URI);
346 if (fragment != NULL)
347 xmlFree(fragment);
348 return(-1);
349 }
350
351 ref = xmlXIncludeNewRef(ctxt, URL, cur);
352 if (ref == NULL) {
353 return(-1);
354 }
355 ref->fragment = fragment;
356 ref->doc = NULL;
357 ref->xml = xml;
358 ref->count = 1;
359 xmlFree(URL);
360 return(0);
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000361}
362
363/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000364 * xmlXIncludeRecurseDoc:
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000365 * @ctxt: the XInclude context
366 * @doc: the new document
367 * @url: the associated URL
368 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000369 * The XInclude recursive nature is handled at this point.
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000370 */
371static void
Daniel Veillard118aed72002-09-24 14:13:13 +0000372xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000373 const xmlURL url ATTRIBUTE_UNUSED) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000374 xmlXIncludeCtxtPtr newctxt;
375 int i;
376
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000377#ifdef DEBUG_XINCLUDE
378 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
379#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000380 /*
381 * Handle recursion here.
382 */
383
384 newctxt = xmlXIncludeNewContext(doc);
385 if (newctxt != NULL) {
386 /*
387 * Copy the existing document set
388 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000389 newctxt->incMax = ctxt->incMax;
390 newctxt->incNr = ctxt->incNr;
391 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
392 sizeof(newctxt->incTab[0]));
393 if (newctxt->incTab == NULL) {
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000394 xmlGenericError(xmlGenericErrorContext,
395 "malloc failed !\n");
396 xmlFree(newctxt);
397 return;
398 }
399
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000400 /*
401 * Inherit the documents already in use by others includes
402 */
403 newctxt->incBase = ctxt->incNr;
404 for (i = 0;i < ctxt->incNr;i++) {
405 newctxt->incTab[i] = ctxt->incTab[i];
406 newctxt->incTab[i]->count++; /* prevent the recursion from
407 freeing it */
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000408 }
409 xmlXIncludeDoProcess(newctxt, doc);
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000410 for (i = 0;i < ctxt->incNr;i++) {
411 newctxt->incTab[i]->count--;
412 newctxt->incTab[i] = NULL;
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000413 }
414 xmlXIncludeFreeContext(newctxt);
415 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000416#ifdef DEBUG_XINCLUDE
417 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
418#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000419}
420
421/**
422 * xmlXIncludeAddTxt:
423 * @ctxt: the XInclude context
424 * @txt: the new text node
425 * @url: the associated URL
426 *
427 * Add a new txtument to the list
428 */
429static void
430xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000431#ifdef DEBUG_XINCLUDE
432 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
433#endif
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000434 if (ctxt->txtMax == 0) {
435 ctxt->txtMax = 4;
436 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
437 sizeof(ctxt->txtTab[0]));
438 if (ctxt->txtTab == NULL) {
439 xmlGenericError(xmlGenericErrorContext,
440 "malloc failed !\n");
441 return;
442 }
443 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
444 sizeof(ctxt->txturlTab[0]));
445 if (ctxt->txturlTab == NULL) {
446 xmlGenericError(xmlGenericErrorContext,
447 "malloc failed !\n");
448 return;
449 }
450 }
451 if (ctxt->txtNr >= ctxt->txtMax) {
452 ctxt->txtMax *= 2;
453 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
454 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
455 if (ctxt->txtTab == NULL) {
456 xmlGenericError(xmlGenericErrorContext,
457 "realloc failed !\n");
458 return;
459 }
460 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000461 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
Daniel Veillardd16df9f2001-05-23 13:44:21 +0000462 if (ctxt->txturlTab == NULL) {
463 xmlGenericError(xmlGenericErrorContext,
464 "realloc failed !\n");
465 return;
466 }
467 }
468 ctxt->txtTab[ctxt->txtNr] = txt;
469 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
470 ctxt->txtNr++;
471}
472
Owen Taylor3473f882001-02-23 17:55:21 +0000473/************************************************************************
474 * *
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000475 * Node copy with specific semantic *
476 * *
477 ************************************************************************/
478
479/**
480 * xmlXIncludeCopyNode:
481 * @ctxt: the XInclude context
482 * @target: the document target
483 * @source: the document source
484 * @elem: the element
485 *
486 * Make a copy of the node while preserving the XInclude semantic
487 * of the Infoset copy
488 */
489static xmlNodePtr
490xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
491 xmlDocPtr source, xmlNodePtr elem) {
492 xmlNodePtr result = NULL;
493
494 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
495 (elem == NULL))
496 return(NULL);
497 if (elem->type == XML_DTD_NODE)
498 return(NULL);
499 result = xmlDocCopyNode(elem, target, 1);
500 return(result);
501}
502
503/**
504 * xmlXIncludeCopyNodeList:
505 * @ctxt: the XInclude context
506 * @target: the document target
507 * @source: the document source
508 * @elem: the element list
509 *
510 * Make a copy of the node list while preserving the XInclude semantic
511 * of the Infoset copy
512 */
513static xmlNodePtr
514xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
515 xmlDocPtr source, xmlNodePtr elem) {
516 xmlNodePtr cur, res, result = NULL, last = NULL;
517
518 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
519 (elem == NULL))
520 return(NULL);
521 cur = elem;
522 while (cur != NULL) {
523 res = xmlXIncludeCopyNode(ctxt, target, source, cur);
524 if (res != NULL) {
525 if (result == NULL) {
526 result = last = res;
527 } else {
528 last->next = res;
529 res->prev = last;
530 last = res;
531 }
532 }
533 cur = cur->next;
534 }
535 return(result);
536}
537
538/**
539 * xmlXInclueGetNthChild:
540 * @cur: the node
541 * @no: the child number
542 *
543 * Returns the @no'th element child of @cur or NULL
544 */
545static xmlNodePtr
546xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
547 int i;
548 if (cur == NULL)
549 return(cur);
550 cur = cur->children;
551 for (i = 0;i <= no;cur = cur->next) {
552 if (cur == NULL)
553 return(cur);
554 if ((cur->type == XML_ELEMENT_NODE) ||
555 (cur->type == XML_DOCUMENT_NODE) ||
556 (cur->type == XML_HTML_DOCUMENT_NODE)) {
557 i++;
558 if (i == no)
559 break;
560 }
561 }
562 return(cur);
563}
564
565xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
566
567/**
568 * xmlXIncludeCopyRange:
569 * @ctxt: the XInclude context
570 * @target: the document target
571 * @source: the document source
572 * @obj: the XPointer result from the evaluation.
573 *
574 * Build a node list tree copy of the XPointer result.
575 *
576 * Returns an xmlNodePtr list or NULL.
577 * the caller has to free the node tree.
578 */
579static xmlNodePtr
580xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
581 xmlDocPtr source, xmlXPathObjectPtr range) {
582 /* pointers to generated nodes */
583 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
584 /* pointers to traversal nodes */
585 xmlNodePtr start, cur, end;
586 int index1, index2;
587
588 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
589 (range == NULL))
590 return(NULL);
591 if (range->type != XPATH_RANGE)
592 return(NULL);
593 start = (xmlNodePtr) range->user;
594
595 if (start == NULL)
596 return(NULL);
597 end = range->user2;
598 if (end == NULL)
599 return(xmlDocCopyNode(start, target, 1));
600
601 cur = start;
602 index1 = range->index;
603 index2 = range->index2;
604 while (cur != NULL) {
605 if (cur == end) {
606 if (cur->type == XML_TEXT_NODE) {
607 const xmlChar *content = cur->content;
608 int len;
609
610 if (content == NULL) {
611 tmp = xmlNewTextLen(NULL, 0);
612 } else {
613 len = index2;
614 if ((cur == start) && (index1 > 1)) {
615 content += (index1 - 1);
616 len -= (index1 - 1);
617 index1 = 0;
618 } else {
619 len = index2;
620 }
621 tmp = xmlNewTextLen(content, len);
622 }
623 /* single sub text node selection */
624 if (list == NULL)
625 return(tmp);
626 /* prune and return full set */
627 if (last != NULL)
628 xmlAddNextSibling(last, tmp);
629 else
630 xmlAddChild(parent, tmp);
631 return(list);
632 } else {
633 tmp = xmlDocCopyNode(cur, target, 0);
634 if (list == NULL)
635 list = tmp;
636 else {
637 if (last != NULL)
638 xmlAddNextSibling(last, tmp);
639 else
640 xmlAddChild(parent, tmp);
641 }
642 last = NULL;
643 parent = tmp;
644
645 if (index2 > 1) {
646 end = xmlXIncludeGetNthChild(cur, index2 - 1);
647 index2 = 0;
648 }
649 if ((cur == start) && (index1 > 1)) {
650 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
651 index1 = 0;
652 } else {
653 cur = cur->children;
654 }
655 /*
656 * Now gather the remaining nodes from cur to end
657 */
658 continue; /* while */
659 }
660 } else if ((cur == start) &&
661 (list == NULL) /* looks superfluous but ... */ ) {
662 if ((cur->type == XML_TEXT_NODE) ||
663 (cur->type == XML_CDATA_SECTION_NODE)) {
664 const xmlChar *content = cur->content;
665
666 if (content == NULL) {
667 tmp = xmlNewTextLen(NULL, 0);
668 } else {
669 if (index1 > 1) {
670 content += (index1 - 1);
671 }
672 tmp = xmlNewText(content);
673 }
674 last = list = tmp;
675 } else {
676 if ((cur == start) && (index1 > 1)) {
677 tmp = xmlDocCopyNode(cur, target, 0);
678 list = tmp;
679 parent = tmp;
680 last = NULL;
681 cur = xmlXIncludeGetNthChild(cur, index1 - 1);
682 index1 = 0;
683 /*
684 * Now gather the remaining nodes from cur to end
685 */
686 continue; /* while */
687 }
688 tmp = xmlDocCopyNode(cur, target, 1);
689 list = tmp;
690 parent = NULL;
691 last = tmp;
692 }
693 } else {
694 tmp = NULL;
695 switch (cur->type) {
696 case XML_DTD_NODE:
697 case XML_ELEMENT_DECL:
698 case XML_ATTRIBUTE_DECL:
699 case XML_ENTITY_NODE:
700 /* Do not copy DTD informations */
701 break;
702 case XML_ENTITY_DECL:
703 /* handle crossing entities -> stack needed */
704 break;
705 case XML_XINCLUDE_START:
706 case XML_XINCLUDE_END:
707 /* don't consider it part of the tree content */
708 break;
709 case XML_ATTRIBUTE_NODE:
710 /* Humm, should not happen ! */
711 break;
712 default:
713 tmp = xmlDocCopyNode(cur, target, 1);
714 break;
715 }
716 if (tmp != NULL) {
717 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
718 return(NULL);
719 }
720 if (last != NULL)
721 xmlAddNextSibling(last, tmp);
722 else {
723 xmlAddChild(parent, tmp);
724 last = tmp;
725 }
726 }
727 }
728 /*
729 * Skip to next node in document order
730 */
731 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
732 return(NULL);
733 }
734 cur = xmlXPtrAdvanceNode(cur);
735 }
736 return(list);
737}
738
739/**
740 * xmlXIncludeBuildNodeList:
741 * @ctxt: the XInclude context
742 * @target: the document target
743 * @source: the document source
744 * @obj: the XPointer result from the evaluation.
745 *
746 * Build a node list tree copy of the XPointer result.
747 * This will drop Attributes and Namespace declarations.
748 *
749 * Returns an xmlNodePtr list or NULL.
750 * the caller has to free the node tree.
751 */
752static xmlNodePtr
753xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
754 xmlDocPtr source, xmlXPathObjectPtr obj) {
755 xmlNodePtr list = NULL, last = NULL;
756 int i;
757
758 if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
759 (obj == NULL))
760 return(NULL);
761 switch (obj->type) {
762 case XPATH_NODESET: {
763 xmlNodeSetPtr set = obj->nodesetval;
764 if (set == NULL)
765 return(NULL);
766 for (i = 0;i < set->nodeNr;i++) {
767 if (set->nodeTab[i] == NULL)
768 continue;
769 switch (set->nodeTab[i]->type) {
770 case XML_TEXT_NODE:
771 case XML_CDATA_SECTION_NODE:
772 case XML_ELEMENT_NODE:
773 case XML_ENTITY_REF_NODE:
774 case XML_ENTITY_NODE:
775 case XML_PI_NODE:
776 case XML_COMMENT_NODE:
777 case XML_DOCUMENT_NODE:
778 case XML_HTML_DOCUMENT_NODE:
779#ifdef LIBXML_DOCB_ENABLED
780 case XML_DOCB_DOCUMENT_NODE:
781#endif
782 case XML_XINCLUDE_START:
783 case XML_XINCLUDE_END:
784 break;
785 case XML_ATTRIBUTE_NODE:
786 case XML_NAMESPACE_DECL:
787 case XML_DOCUMENT_TYPE_NODE:
788 case XML_DOCUMENT_FRAG_NODE:
789 case XML_NOTATION_NODE:
790 case XML_DTD_NODE:
791 case XML_ELEMENT_DECL:
792 case XML_ATTRIBUTE_DECL:
793 case XML_ENTITY_DECL:
794 continue; /* for */
795 }
796 if (last == NULL)
797 list = last = xmlXIncludeCopyNode(ctxt, target, source,
798 set->nodeTab[i]);
799 else {
800 xmlAddNextSibling(last,
801 xmlXIncludeCopyNode(ctxt, target, source,
802 set->nodeTab[i]));
803 if (last->next != NULL)
804 last = last->next;
805 }
806 }
807 break;
808 }
809 case XPATH_LOCATIONSET: {
810 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
811 if (set == NULL)
812 return(NULL);
813 for (i = 0;i < set->locNr;i++) {
814 if (last == NULL)
815 list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
816 set->locTab[i]);
817 else
818 xmlAddNextSibling(last,
819 xmlXIncludeCopyXPointer(ctxt, target, source,
820 set->locTab[i]));
821 if (last != NULL) {
822 while (last->next != NULL)
823 last = last->next;
824 }
825 }
826 break;
827 }
828 case XPATH_RANGE:
829 return(xmlXIncludeCopyRange(ctxt, target, source, obj));
830 case XPATH_POINT:
831 /* points are ignored in XInclude */
832 break;
833 default:
834 break;
835 }
836 return(list);
837}
838/************************************************************************
839 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000840 * XInclude I/O handling *
841 * *
842 ************************************************************************/
843
844/**
845 * xmlXIncludeLoadDoc:
846 * @ctxt: the XInclude context
847 * @url: the associated URL
848 * @nr: the xinclude node number
849 *
850 * Load the document, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000851 *
852 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000853 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000854static int
Owen Taylor3473f882001-02-23 17:55:21 +0000855xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
856 xmlDocPtr doc;
857 xmlURIPtr uri;
858 xmlChar *URL;
859 xmlChar *fragment = NULL;
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000860 int i = 0;
861
862#ifdef DEBUG_XINCLUDE
863 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
864#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000865 /*
866 * Check the URL and remove any fragment identifier
867 */
868 uri = xmlParseURI((const char *)url);
869 if (uri == NULL) {
870 xmlGenericError(xmlGenericErrorContext,
871 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000872 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000873 }
874 if (uri->fragment != NULL) {
875 fragment = (xmlChar *) uri->fragment;
876 uri->fragment = NULL;
877 }
878 URL = xmlSaveUri(uri);
879 xmlFreeURI(uri);
880 if (URL == NULL) {
881 xmlGenericError(xmlGenericErrorContext,
882 "XInclude: invalid value URI %s\n", url);
883 if (fragment != NULL)
884 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000885 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000886 }
887
888 /*
889 * Handling of references to the local document are done
890 * directly through ctxt->doc.
891 */
892 if ((URL[0] == 0) || (URL[0] == '#')) {
893 doc = NULL;
894 goto loaded;
895 }
896
897 /*
898 * Prevent reloading twice the document.
899 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000900 for (i = 0; i < ctxt->incNr; i++) {
901 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
902 (ctxt->incTab[i]->doc != NULL)) {
903 doc = ctxt->incTab[i]->doc;
904#ifdef DEBUG_XINCLUDE
905 printf("Already loaded %s\n", URL);
906#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000907 goto loaded;
908 }
909 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000910
Owen Taylor3473f882001-02-23 17:55:21 +0000911 /*
912 * Load it.
913 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000914#ifdef DEBUG_XINCLUDE
915 printf("loading %s\n", URL);
916#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000917 doc = xmlParseFile((const char *)URL);
918 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000919 xmlFree(URL);
920 if (fragment != NULL)
921 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000922 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000923 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000924 ctxt->incTab[nr]->doc = doc;
925
926 /*
927 * TODO: Make sure we have all entities fixed up
928 */
929
930 /*
931 * We don't need the DTD anymore, free up space
932 if (doc->intSubset != NULL) {
933 xmlUnlinkNode((xmlNodePtr) doc->intSubset);
934 xmlFreeNode((xmlNodePtr) doc->intSubset);
935 doc->intSubset = NULL;
936 }
937 if (doc->extSubset != NULL) {
938 xmlUnlinkNode((xmlNodePtr) doc->extSubset);
939 xmlFreeNode((xmlNodePtr) doc->extSubset);
940 doc->extSubset = NULL;
941 }
942 */
943 xmlXIncludeRecurseDoc(ctxt, doc, URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000944
945loaded:
946 if (fragment == NULL) {
947 /*
948 * Add the top children list as the replacement copy.
Owen Taylor3473f882001-02-23 17:55:21 +0000949 */
950 if (doc == NULL)
Daniel Veillard4497e692001-06-09 14:19:02 +0000951 {
952 /* Hopefully a DTD declaration won't be copied from
953 * the same document */
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000954 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000955 } else {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000956 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
Daniel Veillardc5f05ad2002-02-10 11:57:22 +0000957 doc, doc->children);
Daniel Veillard4497e692001-06-09 14:19:02 +0000958 }
Owen Taylor3473f882001-02-23 17:55:21 +0000959 } else {
960 /*
961 * Computes the XPointer expression and make a copy used
962 * as the replacement copy.
963 */
964 xmlXPathObjectPtr xptr;
965 xmlXPathContextPtr xptrctxt;
Daniel Veillard39196eb2001-06-19 18:09:42 +0000966 xmlNodeSetPtr set;
Owen Taylor3473f882001-02-23 17:55:21 +0000967
968 if (doc == NULL) {
Daniel Veillardbbc72c32002-09-05 10:52:10 +0000969 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
970 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000971 } else {
972 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
973 }
974 if (xptrctxt == NULL) {
975 xmlGenericError(xmlGenericErrorContext,
976 "XInclude: could create XPointer context\n");
977 xmlFree(URL);
978 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000979 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000980 }
981 xptr = xmlXPtrEval(fragment, xptrctxt);
982 if (xptr == NULL) {
983 xmlGenericError(xmlGenericErrorContext,
984 "XInclude: XPointer evaluation failed: #%s\n",
985 fragment);
986 xmlXPathFreeContext(xptrctxt);
987 xmlFree(URL);
988 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +0000989 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000990 }
Daniel Veillard39196eb2001-06-19 18:09:42 +0000991 switch (xptr->type) {
992 case XPATH_UNDEFINED:
993 case XPATH_BOOLEAN:
994 case XPATH_NUMBER:
995 case XPATH_STRING:
996 case XPATH_POINT:
997 case XPATH_USERS:
998 case XPATH_XSLT_TREE:
999 xmlGenericError(xmlGenericErrorContext,
1000 "XInclude: XPointer is not a range: #%s\n",
1001 fragment);
1002 xmlXPathFreeContext(xptrctxt);
1003 xmlFree(URL);
1004 xmlFree(fragment);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001005 return(-1);
Daniel Veillard39196eb2001-06-19 18:09:42 +00001006 case XPATH_NODESET:
1007 case XPATH_RANGE:
1008 case XPATH_LOCATIONSET:
1009 break;
1010 }
1011 set = xptr->nodesetval;
1012 if (set != NULL) {
1013 for (i = 0;i < set->nodeNr;i++) {
1014 if (set->nodeTab[i] == NULL)
1015 continue;
1016 switch (set->nodeTab[i]->type) {
1017 case XML_TEXT_NODE:
1018 case XML_CDATA_SECTION_NODE:
1019 case XML_ELEMENT_NODE:
1020 case XML_ENTITY_REF_NODE:
1021 case XML_ENTITY_NODE:
1022 case XML_PI_NODE:
1023 case XML_COMMENT_NODE:
1024 case XML_DOCUMENT_NODE:
1025 case XML_HTML_DOCUMENT_NODE:
1026#ifdef LIBXML_DOCB_ENABLED
1027 case XML_DOCB_DOCUMENT_NODE:
1028#endif
1029 continue;
1030 case XML_ATTRIBUTE_NODE:
1031 xmlGenericError(xmlGenericErrorContext,
1032 "XInclude: XPointer selects an attribute: #%s\n",
1033 fragment);
1034 set->nodeTab[i] = NULL;
1035 continue;
1036 case XML_NAMESPACE_DECL:
1037 xmlGenericError(xmlGenericErrorContext,
1038 "XInclude: XPointer selects a namespace: #%s\n",
1039 fragment);
1040 set->nodeTab[i] = NULL;
1041 continue;
1042 case XML_DOCUMENT_TYPE_NODE:
1043 case XML_DOCUMENT_FRAG_NODE:
1044 case XML_NOTATION_NODE:
1045 case XML_DTD_NODE:
1046 case XML_ELEMENT_DECL:
1047 case XML_ATTRIBUTE_DECL:
1048 case XML_ENTITY_DECL:
1049 case XML_XINCLUDE_START:
1050 case XML_XINCLUDE_END:
1051 xmlGenericError(xmlGenericErrorContext,
1052 "XInclude: XPointer selects unexpected nodes: #%s\n",
1053 fragment);
1054 set->nodeTab[i] = NULL;
1055 set->nodeTab[i] = NULL;
1056 continue; /* for */
1057 }
1058 }
1059 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001060 ctxt->incTab[nr]->inc =
1061 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
Owen Taylor3473f882001-02-23 17:55:21 +00001062 xmlXPathFreeObject(xptr);
1063 xmlXPathFreeContext(xptrctxt);
1064 xmlFree(fragment);
1065 }
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001066
1067 /*
1068 * Do the xml:base fixup if needed
1069 */
1070 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1071 xmlNodePtr node;
1072
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001073 node = ctxt->incTab[nr]->inc;
Daniel Veillardc4bad4a2002-08-14 14:45:25 +00001074 while (node != NULL) {
1075 if (node->type == XML_ELEMENT_NODE)
1076 xmlNodeSetBase(node, URL);
1077 node = node->next;
1078 }
1079 }
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001080 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1081 (ctxt->incTab[nr]->count <= 1)) {
1082#ifdef DEBUG_XINCLUDE
1083 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1084#endif
1085 xmlFreeDoc(ctxt->incTab[nr]->doc);
1086 ctxt->incTab[nr]->doc = NULL;
1087 }
Owen Taylor3473f882001-02-23 17:55:21 +00001088 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001089 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001090}
1091
1092/**
1093 * xmlXIncludeLoadTxt:
1094 * @ctxt: the XInclude context
1095 * @url: the associated URL
1096 * @nr: the xinclude node number
1097 *
1098 * Load the content, and store the result in the XInclude context
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001099 *
1100 * Returns 0 in case of success, -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001101 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001102static int
Owen Taylor3473f882001-02-23 17:55:21 +00001103xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1104 xmlParserInputBufferPtr buf;
1105 xmlNodePtr node;
1106 xmlURIPtr uri;
1107 xmlChar *URL;
1108 int i;
1109 /*
1110 * Check the URL and remove any fragment identifier
1111 */
1112 uri = xmlParseURI((const char *)url);
1113 if (uri == NULL) {
1114 xmlGenericError(xmlGenericErrorContext,
1115 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001116 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001117 }
1118 if (uri->fragment != NULL) {
1119 xmlGenericError(xmlGenericErrorContext,
1120 "XInclude: fragment identifier forbidden for text: %s\n",
1121 uri->fragment);
1122 xmlFreeURI(uri);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001123 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001124 }
1125 URL = xmlSaveUri(uri);
1126 xmlFreeURI(uri);
1127 if (URL == NULL) {
1128 xmlGenericError(xmlGenericErrorContext,
1129 "XInclude: invalid value URI %s\n", url);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001130 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001131 }
1132
1133 /*
1134 * Handling of references to the local document are done
1135 * directly through ctxt->doc.
1136 */
1137 if (URL[0] == 0) {
1138 xmlGenericError(xmlGenericErrorContext,
1139 "XInclude: text serialization of document not available\n");
1140 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001141 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001142 }
1143
1144 /*
1145 * Prevent reloading twice the document.
1146 */
1147 for (i = 0; i < ctxt->txtNr; i++) {
1148 if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1149 node = xmlCopyNode(ctxt->txtTab[i], 1);
1150 goto loaded;
1151 }
1152 }
1153 /*
1154 * Load it.
1155 * Issue 62: how to detect the encoding
1156 */
1157 buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
1158 if (buf == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001159 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001160 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001161 }
1162 node = xmlNewText(NULL);
1163
1164 /*
1165 * Scan all chars from the resource and add the to the node
1166 */
1167 while (xmlParserInputBufferRead(buf, 128) > 0) {
1168 int len;
1169 const xmlChar *content;
1170
1171 content = xmlBufferContent(buf->buffer);
1172 len = xmlBufferLength(buf->buffer);
1173 for (i = 0;i < len; i++) {
1174 /*
1175 * TODO: if the encoding issue is solved, scan UTF8 chars instead
1176 */
1177 if (!IS_CHAR(content[i])) {
1178 xmlGenericError(xmlGenericErrorContext,
1179 "XInclude: %s contains invalid char %d\n", URL, content[i]);
1180 } else {
1181 xmlNodeAddContentLen(node, &content[i], 1);
1182 }
1183 }
1184 xmlBufferShrink(buf->buffer, len);
1185 }
1186 xmlFreeParserInputBuffer(buf);
1187 xmlXIncludeAddTxt(ctxt, node, URL);
1188
1189loaded:
1190 /*
1191 * Add the element as the replacement copy.
1192 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001193 ctxt->incTab[nr]->inc = node;
Owen Taylor3473f882001-02-23 17:55:21 +00001194 xmlFree(URL);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001195 return(0);
1196}
1197
1198/**
1199 * xmlXIncludeLoadFallback:
1200 * @ctxt: the XInclude context
1201 * @fallback: the fallback node
1202 * @nr: the xinclude node number
1203 *
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001204 * Load the content of the fallback node, and store the result
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001205 * in the XInclude context
1206 *
1207 * Returns 0 in case of success, -1 in case of failure
1208 */
1209static int
1210xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1211 if ((fallback == NULL) || (ctxt == NULL))
1212 return(-1);
1213
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001214 ctxt->incTab[nr]->inc = xmlCopyNode(fallback->children, 1);
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001215 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00001216}
1217
1218/************************************************************************
1219 * *
1220 * XInclude Processing *
1221 * *
1222 ************************************************************************/
1223
1224/**
1225 * xmlXIncludePreProcessNode:
1226 * @ctxt: an XInclude context
1227 * @node: an XInclude node
1228 *
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001229 * Implement the XInclude preprocessing, currently just adding the element
1230 * for further processing.
Owen Taylor3473f882001-02-23 17:55:21 +00001231 *
1232 * Returns the result list or NULL in case of error
1233 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001234static xmlNodePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001235xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1236 xmlXIncludeAddNode(ctxt, node);
1237 return(0);
1238}
1239
Daniel Veillard118aed72002-09-24 14:13:13 +00001240#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00001241/**
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001242 * xmlXIncludePreloadNode:
1243 * @ctxt: an XInclude context
1244 * @nr: the node number
1245 *
1246 * Do some precomputations and preload shared documents
1247 *
1248 * Returns 0 if substitution succeeded, -1 if some processing failed
1249 */
1250static int
1251xmlXIncludePreloadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1252 xmlNodePtr cur;
1253 xmlChar *href;
1254 xmlChar *parse;
1255 xmlChar *base;
1256 xmlChar *URI;
1257 int xml = 1; /* default Issue 64 */
1258 xmlURIPtr uri;
1259 xmlChar *URL;
1260 xmlChar *fragment = NULL;
1261 int i;
1262
1263
1264 if (ctxt == NULL)
1265 return(-1);
1266 if ((nr < 0) || (nr >= ctxt->incNr))
1267 return(-1);
1268 cur = ctxt->incTab[nr]->ref;
1269 if (cur == NULL)
1270 return(-1);
1271
1272 /*
1273 * read the attributes
1274 */
1275 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1276 if (href == NULL) {
1277 href = xmlGetProp(cur, XINCLUDE_HREF);
1278 if (href == NULL) {
1279 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1280 return(-1);
1281 }
1282 }
1283 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1284 if (parse == NULL) {
1285 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1286 }
1287 if (parse != NULL) {
1288 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1289 xml = 1;
1290 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1291 xml = 0;
1292 else {
1293 xmlGenericError(xmlGenericErrorContext,
1294 "XInclude: invalid value %s for %s\n",
1295 parse, XINCLUDE_PARSE);
1296 if (href != NULL)
1297 xmlFree(href);
1298 if (parse != NULL)
1299 xmlFree(parse);
1300 return(-1);
1301 }
1302 }
1303
1304 /*
1305 * compute the URI
1306 */
1307 base = xmlNodeGetBase(ctxt->doc, cur);
1308 if (base == NULL) {
1309 URI = xmlBuildURI(href, ctxt->doc->URL);
1310 } else {
1311 URI = xmlBuildURI(href, base);
1312 }
1313 if (URI == NULL) {
1314 xmlChar *escbase;
1315 xmlChar *eschref;
1316 /*
1317 * Some escaping may be needed
1318 */
1319 escbase = xmlURIEscape(base);
1320 eschref = xmlURIEscape(href);
1321 URI = xmlBuildURI(eschref, escbase);
1322 if (escbase != NULL)
1323 xmlFree(escbase);
1324 if (eschref != NULL)
1325 xmlFree(eschref);
1326 }
1327 if (parse != NULL)
1328 xmlFree(parse);
1329 if (href != NULL)
1330 xmlFree(href);
1331 if (base != NULL)
1332 xmlFree(base);
1333 if (URI == NULL) {
1334 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1335 return(-1);
1336 }
1337
1338 /*
1339 * Check the URL and remove any fragment identifier
1340 */
1341 uri = xmlParseURI((const char *)URI);
1342 if (uri == NULL) {
1343 xmlGenericError(xmlGenericErrorContext,
1344 "XInclude: invalid value URI %s\n", URI);
1345 xmlFree(URI);
1346 return(-1);
1347 }
1348 if (uri->fragment != NULL) {
1349 fragment = (xmlChar *) uri->fragment;
1350 uri->fragment = NULL;
1351 }
1352 URL = xmlSaveUri(uri);
1353 xmlFreeURI(uri);
1354 if (URL == NULL) {
1355 xmlGenericError(xmlGenericErrorContext,
1356 "XInclude: invalid value URI %s\n", URI);
1357 if (fragment != NULL)
1358 xmlFree(fragment);
1359 xmlFree(URI);
1360 return(-1);
1361 }
1362 xmlFree(URI);
1363 if (fragment != NULL)
1364 xmlFree(fragment);
1365
1366 for (i = 0; i < nr; i++) {
1367 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1368#ifdef DEBUG_XINCLUDE
1369 printf("Incrementing count for %d : %s\n", i, ctxt->incTab[i]->URI);
1370#endif
1371 ctxt->incTab[i]->count++;
1372 break;
1373 }
1374 }
1375 xmlFree(URL);
1376 return(0);
1377}
Daniel Veillard118aed72002-09-24 14:13:13 +00001378#endif
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001379
1380/**
Owen Taylor3473f882001-02-23 17:55:21 +00001381 * xmlXIncludeLoadNode:
1382 * @ctxt: an XInclude context
1383 * @nr: the node number
1384 *
1385 * Find and load the infoset replacement for the given node.
1386 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001387 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001388 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001389static int
Owen Taylor3473f882001-02-23 17:55:21 +00001390xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1391 xmlNodePtr cur;
1392 xmlChar *href;
1393 xmlChar *parse;
1394 xmlChar *base;
1395 xmlChar *URI;
1396 int xml = 1; /* default Issue 64 */
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001397 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00001398
1399 if (ctxt == NULL)
1400 return(-1);
1401 if ((nr < 0) || (nr >= ctxt->incNr))
1402 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001403 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001404 if (cur == NULL)
1405 return(-1);
1406
Owen Taylor3473f882001-02-23 17:55:21 +00001407 /*
1408 * read the attributes
1409 */
1410 href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1411 if (href == NULL) {
1412 href = xmlGetProp(cur, XINCLUDE_HREF);
1413 if (href == NULL) {
1414 xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1415 return(-1);
1416 }
1417 }
1418 parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1419 if (parse == NULL) {
1420 parse = xmlGetProp(cur, XINCLUDE_PARSE);
1421 }
1422 if (parse != NULL) {
1423 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1424 xml = 1;
1425 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1426 xml = 0;
1427 else {
1428 xmlGenericError(xmlGenericErrorContext,
1429 "XInclude: invalid value %s for %s\n",
1430 parse, XINCLUDE_PARSE);
1431 if (href != NULL)
1432 xmlFree(href);
1433 if (parse != NULL)
1434 xmlFree(parse);
1435 return(-1);
1436 }
1437 }
1438
1439 /*
1440 * compute the URI
1441 */
1442 base = xmlNodeGetBase(ctxt->doc, cur);
1443 if (base == NULL) {
1444 URI = xmlBuildURI(href, ctxt->doc->URL);
1445 } else {
1446 URI = xmlBuildURI(href, base);
1447 }
1448 if (URI == NULL) {
1449 xmlChar *escbase;
1450 xmlChar *eschref;
1451 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001452 * Some escaping may be needed
Owen Taylor3473f882001-02-23 17:55:21 +00001453 */
1454 escbase = xmlURIEscape(base);
1455 eschref = xmlURIEscape(href);
1456 URI = xmlBuildURI(eschref, escbase);
1457 if (escbase != NULL)
1458 xmlFree(escbase);
1459 if (eschref != NULL)
1460 xmlFree(eschref);
1461 }
1462 if (URI == NULL) {
1463 xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1464 if (parse != NULL)
1465 xmlFree(parse);
1466 if (href != NULL)
1467 xmlFree(href);
1468 if (base != NULL)
1469 xmlFree(base);
1470 return(-1);
1471 }
1472#ifdef DEBUG_XINCLUDE
1473 xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1474 xml ? "xml": "text");
1475 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1476#endif
1477
1478 /*
1479 * Cleanup
1480 */
1481 if (xml) {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001482 ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
Owen Taylor3473f882001-02-23 17:55:21 +00001483 /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1484 } else {
Daniel Veillarde3b7d9a2002-08-14 14:11:30 +00001485 ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1486 }
1487 if (ret < 0) {
1488 xmlNodePtr children;
1489
1490 /*
1491 * Time to try a fallback if availble
1492 */
1493#ifdef DEBUG_XINCLUDE
1494 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1495#endif
1496 children = cur->children;
1497 while (children != NULL) {
1498 if ((children->type == XML_ELEMENT_NODE) &&
1499 (children->ns != NULL) &&
1500 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1501 (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1502 ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1503 if (ret == 0)
1504 break;
1505 }
1506 children = children->next;
1507 }
1508 }
1509 if (ret < 0) {
1510 xmlGenericError(xmlGenericErrorContext,
1511 "XInclude: could not load %s, and no fallback was found\n",
1512 URI);
Owen Taylor3473f882001-02-23 17:55:21 +00001513 }
1514
1515 /*
1516 * Cleanup
1517 */
1518 if (URI != NULL)
1519 xmlFree(URI);
1520 if (parse != NULL)
1521 xmlFree(parse);
1522 if (href != NULL)
1523 xmlFree(href);
1524 if (base != NULL)
1525 xmlFree(base);
1526 return(0);
1527}
1528
1529/**
1530 * xmlXIncludeIncludeNode:
1531 * @ctxt: an XInclude context
1532 * @nr: the node number
1533 *
1534 * Inplement the infoset replacement for the given node
1535 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001536 * Returns 0 if substitution succeeded, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001537 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001538static int
Owen Taylor3473f882001-02-23 17:55:21 +00001539xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1540 xmlNodePtr cur, end, list;
1541
1542 if (ctxt == NULL)
1543 return(-1);
1544 if ((nr < 0) || (nr >= ctxt->incNr))
1545 return(-1);
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001546 cur = ctxt->incTab[nr]->ref;
Owen Taylor3473f882001-02-23 17:55:21 +00001547 if (cur == NULL)
1548 return(-1);
1549
1550 /*
1551 * Change the current node as an XInclude start one, and add an
1552 * entity end one
1553 */
1554 cur->type = XML_XINCLUDE_START;
1555 end = xmlNewNode(cur->ns, cur->name);
1556 if (end == NULL) {
1557 xmlGenericError(xmlGenericErrorContext,
1558 "XInclude: failed to build node\n");
1559 return(-1);
1560 }
1561 end->type = XML_XINCLUDE_END;
1562 xmlAddNextSibling(cur, end);
1563
1564 /*
1565 * Add the list of nodes
1566 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001567 list = ctxt->incTab[nr]->inc;
1568 ctxt->incTab[nr]->inc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001569 while (list != NULL) {
1570 cur = list;
1571 list = list->next;
1572
1573 xmlAddPrevSibling(end, cur);
1574 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00001575
1576
Owen Taylor3473f882001-02-23 17:55:21 +00001577 return(0);
1578}
1579
1580/**
1581 * xmlXIncludeTestNode:
Owen Taylor3473f882001-02-23 17:55:21 +00001582 * @node: an XInclude node
1583 *
1584 * test if the node is an XInclude node
1585 *
1586 * Returns 1 true, 0 otherwise
1587 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001588static int
1589xmlXIncludeTestNode(xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00001590 if (node == NULL)
1591 return(0);
1592 if (node->ns == NULL)
1593 return(0);
1594 if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
1595 (xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
1596 return(0);
1597}
1598
1599/**
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001600 * xmlXIncludeDoProcess:
1601 * @ctxt:
Owen Taylor3473f882001-02-23 17:55:21 +00001602 * @doc: an XML document
1603 *
1604 * Implement the XInclude substitution on the XML document @doc
1605 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001606 * Returns 0 if no substitution were done, -1 if some processing failed
Owen Taylor3473f882001-02-23 17:55:21 +00001607 * or the number of substitutions done.
1608 */
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001609static int
1610xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001611 xmlNodePtr cur;
1612 int ret = 0;
1613 int i;
1614
1615 if (doc == NULL)
1616 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001617 if (ctxt == NULL)
1618 return(-1);
1619
1620 /*
1621 * First phase: lookup the elements in the document
1622 */
1623 cur = xmlDocGetRootElement(doc);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001624 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001625 xmlXIncludePreProcessNode(ctxt, cur);
1626 while (cur != NULL) {
1627 /* TODO: need to work on entities -> stack */
1628 if ((cur->children != NULL) &&
1629 (cur->children->type != XML_ENTITY_DECL)) {
1630 cur = cur->children;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001631 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001632 xmlXIncludePreProcessNode(ctxt, cur);
1633 } else if (cur->next != NULL) {
1634 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001635 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001636 xmlXIncludePreProcessNode(ctxt, cur);
1637 } else {
1638 do {
1639 cur = cur->parent;
1640 if (cur == NULL) break; /* do */
1641 if (cur->next != NULL) {
1642 cur = cur->next;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001643 if (xmlXIncludeTestNode(cur))
Owen Taylor3473f882001-02-23 17:55:21 +00001644 xmlXIncludePreProcessNode(ctxt, cur);
1645 break; /* do */
1646 }
1647 } while (cur != NULL);
1648 }
1649 }
1650
1651 /*
1652 * Second Phase : collect the infosets fragments
1653 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001654 /*
1655 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
1656 xmlXIncludePreloadNode(ctxt, i);
1657 }
1658 */
1659 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00001660 xmlXIncludeLoadNode(ctxt, i);
1661 }
1662
1663 /*
1664 * Third phase: extend the original document infoset.
1665 */
Daniel Veillardbbc72c32002-09-05 10:52:10 +00001666 for (i = ctxt->incBase;i < ctxt->incNr; i++) {
Owen Taylor3473f882001-02-23 17:55:21 +00001667 xmlXIncludeIncludeNode(ctxt, i);
1668 }
1669
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001670 return(ret);
1671}
1672
1673/**
1674 * xmlXIncludeProcess:
1675 * @doc: an XML document
1676 *
1677 * Implement the XInclude substitution on the XML document @doc
1678 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001679 * Returns 0 if no substitution were done, -1 if some processing failed
Daniel Veillardd16df9f2001-05-23 13:44:21 +00001680 * or the number of substitutions done.
1681 */
1682int
1683xmlXIncludeProcess(xmlDocPtr doc) {
1684 xmlXIncludeCtxtPtr ctxt;
1685 int ret = 0;
1686
1687 if (doc == NULL)
1688 return(-1);
1689 ctxt = xmlXIncludeNewContext(doc);
1690 if (ctxt == NULL)
1691 return(-1);
1692 ret = xmlXIncludeDoProcess(ctxt, doc);
1693
Owen Taylor3473f882001-02-23 17:55:21 +00001694 xmlXIncludeFreeContext(ctxt);
1695 return(ret);
1696}
1697
1698#else /* !LIBXML_XINCLUDE_ENABLED */
1699#endif