blob: 67b7d164f88557b450dd4016b07830b35cf8aae2 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * 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 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillard56a4cb82001-03-24 17:00:36 +000041xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
42
43/************************************************************************
44 * *
45 * A few static variables and macros *
46 * *
47 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000048/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000049const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000052 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000053/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000054const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
55
Owen Taylor3473f882001-02-23 17:55:21 +000056static int xmlCompressMode = 0;
57static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000058
Owen Taylor3473f882001-02-23 17:55:21 +000059#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
60 xmlNodePtr ulccur = (n)->children; \
61 if (ulccur == NULL) { \
62 (n)->last = NULL; \
63 } else { \
64 while (ulccur->next != NULL) { \
65 ulccur->parent = (n); \
66 ulccur = ulccur->next; \
67 } \
68 ulccur->parent = (n); \
69 (n)->last = ulccur; \
70}}
71
72/* #define DEBUG_BUFFER */
73/* #define DEBUG_TREE */
74
75/************************************************************************
76 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000077 * Functions to move to entities.c once the *
78 * API freeze is smoothen and they can be made public. *
79 * *
80 ************************************************************************/
81#include <libxml/hash.h>
82
83/**
84 * xmlGetEntityFromDtd:
85 * @dtd: A pointer to the DTD to search
86 * @name: The entity name
87 *
88 * Do an entity lookup in the DTD entity hash table and
89 * return the corresponding entity, if found.
90 *
91 * Returns A pointer to the entity structure or NULL if not found.
92 */
93static xmlEntityPtr
94xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
95 xmlEntitiesTablePtr table;
96
97 if((dtd != NULL) && (dtd->entities != NULL)) {
98 table = (xmlEntitiesTablePtr) dtd->entities;
99 return((xmlEntityPtr) xmlHashLookup(table, name));
100 /* return(xmlGetEntityFromTable(table, name)); */
101 }
102 return(NULL);
103}
104/**
105 * xmlGetParameterEntityFromDtd:
106 * @dtd: A pointer to the DTD to search
107 * @name: The entity name
108 *
109 * Do an entity lookup in the DTD pararmeter entity hash table and
110 * return the corresponding entity, if found.
111 *
112 * Returns A pointer to the entity structure or NULL if not found.
113 */
114static xmlEntityPtr
115xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
116 xmlEntitiesTablePtr table;
117
118 if ((dtd != NULL) && (dtd->pentities != NULL)) {
119 table = (xmlEntitiesTablePtr) dtd->pentities;
120 return((xmlEntityPtr) xmlHashLookup(table, name));
121 /* return(xmlGetEntityFromTable(table, name)); */
122 }
123 return(NULL);
124}
125
126/************************************************************************
127 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000128 * Allocation and deallocation of basic structures *
129 * *
130 ************************************************************************/
131
132/**
133 * xmlSetBufferAllocationScheme:
134 * @scheme: allocation method to use
135 *
136 * Set the buffer allocation method. Types are
137 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
138 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
139 * improves performance
140 */
141void
142xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
143 xmlBufferAllocScheme = scheme;
144}
145
146/**
147 * xmlGetBufferAllocationScheme:
148 *
149 * Types are
150 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
151 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
152 * improves performance
153 *
154 * Returns the current allocation scheme
155 */
156xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000157xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000158 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000159}
160
161/**
162 * xmlNewNs:
163 * @node: the element carrying the namespace
164 * @href: the URI associated
165 * @prefix: the prefix for the namespace
166 *
167 * Creation of a new Namespace. This function will refuse to create
168 * a namespace with a similar prefix than an existing one present on this
169 * node.
170 * We use href==NULL in the case of an element creation where the namespace
171 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000172 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000173 */
174xmlNsPtr
175xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
176 xmlNsPtr cur;
177
178 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
179 return(NULL);
180
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000181 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
182 return(NULL);
183
Owen Taylor3473f882001-02-23 17:55:21 +0000184 /*
185 * Allocate a new Namespace and fill the fields.
186 */
187 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
188 if (cur == NULL) {
189 xmlGenericError(xmlGenericErrorContext,
190 "xmlNewNs : malloc failed\n");
191 return(NULL);
192 }
193 memset(cur, 0, sizeof(xmlNs));
194 cur->type = XML_LOCAL_NAMESPACE;
195
196 if (href != NULL)
197 cur->href = xmlStrdup(href);
198 if (prefix != NULL)
199 cur->prefix = xmlStrdup(prefix);
200
201 /*
202 * Add it at the end to preserve parsing order ...
203 * and checks for existing use of the prefix
204 */
205 if (node != NULL) {
206 if (node->nsDef == NULL) {
207 node->nsDef = cur;
208 } else {
209 xmlNsPtr prev = node->nsDef;
210
211 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
212 (xmlStrEqual(prev->prefix, cur->prefix))) {
213 xmlFreeNs(cur);
214 return(NULL);
215 }
216 while (prev->next != NULL) {
217 prev = prev->next;
218 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
219 (xmlStrEqual(prev->prefix, cur->prefix))) {
220 xmlFreeNs(cur);
221 return(NULL);
222 }
223 }
224 prev->next = cur;
225 }
226 }
227 return(cur);
228}
229
230/**
231 * xmlSetNs:
232 * @node: a node in the document
233 * @ns: a namespace pointer
234 *
235 * Associate a namespace to a node, a posteriori.
236 */
237void
238xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
239 if (node == NULL) {
240#ifdef DEBUG_TREE
241 xmlGenericError(xmlGenericErrorContext,
242 "xmlSetNs: node == NULL\n");
243#endif
244 return;
245 }
246 node->ns = ns;
247}
248
249/**
250 * xmlFreeNs:
251 * @cur: the namespace pointer
252 *
253 * Free up the structures associated to a namespace
254 */
255void
256xmlFreeNs(xmlNsPtr cur) {
257 if (cur == NULL) {
258#ifdef DEBUG_TREE
259 xmlGenericError(xmlGenericErrorContext,
260 "xmlFreeNs : ns == NULL\n");
261#endif
262 return;
263 }
264 if (cur->href != NULL) xmlFree((char *) cur->href);
265 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000266 xmlFree(cur);
267}
268
269/**
270 * xmlFreeNsList:
271 * @cur: the first namespace pointer
272 *
273 * Free up all the structures associated to the chained namespaces.
274 */
275void
276xmlFreeNsList(xmlNsPtr cur) {
277 xmlNsPtr next;
278 if (cur == NULL) {
279#ifdef DEBUG_TREE
280 xmlGenericError(xmlGenericErrorContext,
281 "xmlFreeNsList : ns == NULL\n");
282#endif
283 return;
284 }
285 while (cur != NULL) {
286 next = cur->next;
287 xmlFreeNs(cur);
288 cur = next;
289 }
290}
291
292/**
293 * xmlNewDtd:
294 * @doc: the document pointer
295 * @name: the DTD name
296 * @ExternalID: the external ID
297 * @SystemID: the system ID
298 *
299 * Creation of a new DTD for the external subset. To create an
300 * internal subset, use xmlCreateIntSubset().
301 *
302 * Returns a pointer to the new DTD structure
303 */
304xmlDtdPtr
305xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
306 const xmlChar *ExternalID, const xmlChar *SystemID) {
307 xmlDtdPtr cur;
308
309 if ((doc != NULL) && (doc->extSubset != NULL)) {
310#ifdef DEBUG_TREE
311 xmlGenericError(xmlGenericErrorContext,
312 "xmlNewDtd(%s): document %s already have a DTD %s\n",
313 /* !!! */ (char *) name, doc->name,
314 /* !!! */ (char *)doc->extSubset->name);
315#endif
316 return(NULL);
317 }
318
319 /*
320 * Allocate a new DTD and fill the fields.
321 */
322 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
323 if (cur == NULL) {
324 xmlGenericError(xmlGenericErrorContext,
325 "xmlNewDtd : malloc failed\n");
326 return(NULL);
327 }
328 memset(cur, 0 , sizeof(xmlDtd));
329 cur->type = XML_DTD_NODE;
330
331 if (name != NULL)
332 cur->name = xmlStrdup(name);
333 if (ExternalID != NULL)
334 cur->ExternalID = xmlStrdup(ExternalID);
335 if (SystemID != NULL)
336 cur->SystemID = xmlStrdup(SystemID);
337 if (doc != NULL)
338 doc->extSubset = cur;
339 cur->doc = doc;
340
341 return(cur);
342}
343
344/**
345 * xmlGetIntSubset:
346 * @doc: the document pointer
347 *
348 * Get the internal subset of a document
349 * Returns a pointer to the DTD structure or NULL if not found
350 */
351
352xmlDtdPtr
353xmlGetIntSubset(xmlDocPtr doc) {
354 xmlNodePtr cur;
355
356 if (doc == NULL)
357 return(NULL);
358 cur = doc->children;
359 while (cur != NULL) {
360 if (cur->type == XML_DTD_NODE)
361 return((xmlDtdPtr) cur);
362 cur = cur->next;
363 }
364 return((xmlDtdPtr) doc->intSubset);
365}
366
367/**
368 * xmlCreateIntSubset:
369 * @doc: the document pointer
370 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000371 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000372 * @SystemID: the system ID
373 *
374 * Create the internal subset of a document
375 * Returns a pointer to the new DTD structure
376 */
377xmlDtdPtr
378xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
379 const xmlChar *ExternalID, const xmlChar *SystemID) {
380 xmlDtdPtr cur;
381
382 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
383#ifdef DEBUG_TREE
384 xmlGenericError(xmlGenericErrorContext,
385
386 "xmlCreateIntSubset(): document %s already have an internal subset\n",
387 doc->name);
388#endif
389 return(NULL);
390 }
391
392 /*
393 * Allocate a new DTD and fill the fields.
394 */
395 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
396 if (cur == NULL) {
397 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000398 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000399 return(NULL);
400 }
401 memset(cur, 0, sizeof(xmlDtd));
402 cur->type = XML_DTD_NODE;
403
404 if (name != NULL)
405 cur->name = xmlStrdup(name);
406 if (ExternalID != NULL)
407 cur->ExternalID = xmlStrdup(ExternalID);
408 if (SystemID != NULL)
409 cur->SystemID = xmlStrdup(SystemID);
410 if (doc != NULL) {
411 doc->intSubset = cur;
412 cur->parent = doc;
413 cur->doc = doc;
414 if (doc->children == NULL) {
415 doc->children = (xmlNodePtr) cur;
416 doc->last = (xmlNodePtr) cur;
417 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000418 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000419 xmlNodePtr prev;
420
Owen Taylor3473f882001-02-23 17:55:21 +0000421 prev = doc->children;
422 prev->prev = (xmlNodePtr) cur;
423 cur->next = prev;
424 doc->children = (xmlNodePtr) cur;
425 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000426 xmlNodePtr next;
427
428 next = doc->children;
429 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
430 next = next->next;
431 if (next == NULL) {
432 cur->prev = doc->last;
433 cur->prev->next = (xmlNodePtr) cur;
434 cur->next = NULL;
435 doc->last = (xmlNodePtr) cur;
436 } else {
437 cur->next = next;
438 cur->prev = next->prev;
439 if (cur->prev == NULL)
440 doc->children = (xmlNodePtr) cur;
441 else
442 cur->prev->next = (xmlNodePtr) cur;
443 next->prev = (xmlNodePtr) cur;
444 }
Owen Taylor3473f882001-02-23 17:55:21 +0000445 }
446 }
447 }
448 return(cur);
449}
450
451/**
452 * xmlFreeDtd:
453 * @cur: the DTD structure to free up
454 *
455 * Free a DTD structure.
456 */
457void
458xmlFreeDtd(xmlDtdPtr cur) {
459 if (cur == NULL) {
460#ifdef DEBUG_TREE
461 xmlGenericError(xmlGenericErrorContext,
462 "xmlFreeDtd : DTD == NULL\n");
463#endif
464 return;
465 }
466 if (cur->children != NULL) {
467 xmlNodePtr next, c = cur->children;
468
469 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000470 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000471 * indexes.
472 */
473 while (c != NULL) {
474 next = c->next;
475 if (c->type == XML_COMMENT_NODE) {
476 xmlUnlinkNode(c);
477 xmlFreeNode(c);
478 }
479 c = next;
480 }
481 }
482 if (cur->name != NULL) xmlFree((char *) cur->name);
483 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
484 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
485 /* TODO !!! */
486 if (cur->notations != NULL)
487 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
488
489 if (cur->elements != NULL)
490 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
491 if (cur->attributes != NULL)
492 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
493 if (cur->entities != NULL)
494 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
495 if (cur->pentities != NULL)
496 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
497
Owen Taylor3473f882001-02-23 17:55:21 +0000498 xmlFree(cur);
499}
500
501/**
502 * xmlNewDoc:
503 * @version: xmlChar string giving the version of XML "1.0"
504 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000505 * Creates a new XML document
506 *
Owen Taylor3473f882001-02-23 17:55:21 +0000507 * Returns a new document
508 */
509xmlDocPtr
510xmlNewDoc(const xmlChar *version) {
511 xmlDocPtr cur;
512
513 if (version == NULL)
514 version = (const xmlChar *) "1.0";
515
516 /*
517 * Allocate a new document and fill the fields.
518 */
519 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
520 if (cur == NULL) {
521 xmlGenericError(xmlGenericErrorContext,
522 "xmlNewDoc : malloc failed\n");
523 return(NULL);
524 }
525 memset(cur, 0, sizeof(xmlDoc));
526 cur->type = XML_DOCUMENT_NODE;
527
528 cur->version = xmlStrdup(version);
529 cur->standalone = -1;
530 cur->compression = -1; /* not initialized */
531 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000532 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000533 return(cur);
534}
535
536/**
537 * xmlFreeDoc:
538 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000539 *
540 * Free up all the structures used by a document, tree included.
541 */
542void
543xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000544 xmlDtdPtr extSubset, intSubset;
545
Owen Taylor3473f882001-02-23 17:55:21 +0000546 if (cur == NULL) {
547#ifdef DEBUG_TREE
548 xmlGenericError(xmlGenericErrorContext,
549 "xmlFreeDoc : document == NULL\n");
550#endif
551 return;
552 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000553 /*
554 * Do this before freeing the children list to avoid ID lookups
555 */
556 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
557 cur->ids = NULL;
558 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
559 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000560 extSubset = cur->extSubset;
561 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000562 if (intSubset == extSubset)
563 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000564 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000565 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000566 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000567 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000568 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000569 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000570 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000571 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000572 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000573 }
574
575 if (cur->children != NULL) xmlFreeNodeList(cur->children);
576
Owen Taylor3473f882001-02-23 17:55:21 +0000577 if (cur->version != NULL) xmlFree((char *) cur->version);
578 if (cur->name != NULL) xmlFree((char *) cur->name);
579 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000580 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000581 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000582 xmlFree(cur);
583}
584
585/**
586 * xmlStringLenGetNodeList:
587 * @doc: the document
588 * @value: the value of the text
589 * @len: the length of the string value
590 *
591 * Parse the value string and build the node list associated. Should
592 * produce a flat tree with only TEXTs and ENTITY_REFs.
593 * Returns a pointer to the first child
594 */
595xmlNodePtr
596xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
597 xmlNodePtr ret = NULL, last = NULL;
598 xmlNodePtr node;
599 xmlChar *val;
600 const xmlChar *cur = value;
601 const xmlChar *q;
602 xmlEntityPtr ent;
603
604 if (value == NULL) return(NULL);
605
606 q = cur;
607 while ((*cur != 0) && (cur - value < len)) {
608 if (*cur == '&') {
609 /*
610 * Save the current text.
611 */
612 if (cur != q) {
613 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
614 xmlNodeAddContentLen(last, q, cur - q);
615 } else {
616 node = xmlNewDocTextLen(doc, q, cur - q);
617 if (node == NULL) return(ret);
618 if (last == NULL)
619 last = ret = node;
620 else {
621 last->next = node;
622 node->prev = last;
623 last = node;
624 }
625 }
626 }
627 /*
628 * Read the entity string
629 */
630 cur++;
631 q = cur;
632 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
633 if ((*cur == 0) || (cur - value >= len)) {
634#ifdef DEBUG_TREE
635 xmlGenericError(xmlGenericErrorContext,
636 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
637#endif
638 return(ret);
639 }
640 if (cur != q) {
641 /*
642 * Predefined entities don't generate nodes
643 */
644 val = xmlStrndup(q, cur - q);
645 ent = xmlGetDocEntity(doc, val);
646 if ((ent != NULL) &&
647 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
648 if (last == NULL) {
649 node = xmlNewDocText(doc, ent->content);
650 last = ret = node;
651 } else
652 xmlNodeAddContent(last, ent->content);
653
654 } else {
655 /*
656 * Create a new REFERENCE_REF node
657 */
658 node = xmlNewReference(doc, val);
659 if (node == NULL) {
660 if (val != NULL) xmlFree(val);
661 return(ret);
662 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000663 else if ((ent != NULL) && (ent->children == NULL)) {
664 xmlNodePtr tmp;
665
666 ent->children =
667 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
668 tmp = ent->children;
669 while (tmp) {
670 tmp->parent = (xmlNodePtr)ent;
671 tmp = tmp->next;
672 }
673 }
Owen Taylor3473f882001-02-23 17:55:21 +0000674 if (last == NULL)
675 last = ret = node;
676 else {
677 last->next = node;
678 node->prev = last;
679 last = node;
680 }
681 }
682 xmlFree(val);
683 }
684 cur++;
685 q = cur;
686 } else
687 cur++;
688 }
689 if (cur != q) {
690 /*
691 * Handle the last piece of text.
692 */
693 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
694 xmlNodeAddContentLen(last, q, cur - q);
695 } else {
696 node = xmlNewDocTextLen(doc, q, cur - q);
697 if (node == NULL) return(ret);
698 if (last == NULL)
699 last = ret = node;
700 else {
701 last->next = node;
702 node->prev = last;
703 last = node;
704 }
705 }
706 }
707 return(ret);
708}
709
710/**
711 * xmlStringGetNodeList:
712 * @doc: the document
713 * @value: the value of the attribute
714 *
715 * Parse the value string and build the node list associated. Should
716 * produce a flat tree with only TEXTs and ENTITY_REFs.
717 * Returns a pointer to the first child
718 */
719xmlNodePtr
720xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
721 xmlNodePtr ret = NULL, last = NULL;
722 xmlNodePtr node;
723 xmlChar *val;
724 const xmlChar *cur = value;
725 const xmlChar *q;
726 xmlEntityPtr ent;
727
728 if (value == NULL) return(NULL);
729
730 q = cur;
731 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000732 if (cur[0] == '&') {
733 int charval = 0;
734 xmlChar tmp;
735
Owen Taylor3473f882001-02-23 17:55:21 +0000736 /*
737 * Save the current text.
738 */
739 if (cur != q) {
740 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
741 xmlNodeAddContentLen(last, q, cur - q);
742 } else {
743 node = xmlNewDocTextLen(doc, q, cur - q);
744 if (node == NULL) return(ret);
745 if (last == NULL)
746 last = ret = node;
747 else {
748 last->next = node;
749 node->prev = last;
750 last = node;
751 }
752 }
753 }
Owen Taylor3473f882001-02-23 17:55:21 +0000754 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000755 if ((cur[1] == '#') && (cur[2] == 'x')) {
756 cur += 3;
757 tmp = *cur;
758 while (tmp != ';') { /* Non input consuming loop */
759 if ((tmp >= '0') && (tmp <= '9'))
760 charval = charval * 16 + (tmp - '0');
761 else if ((tmp >= 'a') && (tmp <= 'f'))
762 charval = charval * 16 + (tmp - 'a') + 10;
763 else if ((tmp >= 'A') && (tmp <= 'F'))
764 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000765 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000766 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000767 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000768 charval = 0;
769 break;
770 }
771 cur++;
772 tmp = *cur;
773 }
774 if (tmp == ';')
775 cur++;
776 q = cur;
777 } else if (cur[1] == '#') {
778 cur += 2;
779 tmp = *cur;
780 while (tmp != ';') { /* Non input consuming loops */
781 if ((tmp >= '0') && (tmp <= '9'))
782 charval = charval * 10 + (tmp - '0');
783 else {
784 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000785 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000786 charval = 0;
787 break;
788 }
789 cur++;
790 tmp = *cur;
791 }
792 if (tmp == ';')
793 cur++;
794 q = cur;
795 } else {
796 /*
797 * Read the entity string
798 */
799 cur++;
800 q = cur;
801 while ((*cur != 0) && (*cur != ';')) cur++;
802 if (*cur == 0) {
803#ifdef DEBUG_TREE
804 xmlGenericError(xmlGenericErrorContext,
805 "xmlStringGetNodeList: unterminated entity %30s\n", q);
806#endif
807 return(ret);
808 }
809 if (cur != q) {
810 /*
811 * Predefined entities don't generate nodes
812 */
813 val = xmlStrndup(q, cur - q);
814 ent = xmlGetDocEntity(doc, val);
815 if ((ent != NULL) &&
816 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
817 if (last == NULL) {
818 node = xmlNewDocText(doc, ent->content);
819 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000820 } else if (last->type != XML_TEXT_NODE) {
821 node = xmlNewDocText(doc, ent->content);
822 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000823 } else
824 xmlNodeAddContent(last, ent->content);
825
826 } else {
827 /*
828 * Create a new REFERENCE_REF node
829 */
830 node = xmlNewReference(doc, val);
831 if (node == NULL) {
832 if (val != NULL) xmlFree(val);
833 return(ret);
834 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000835 else if ((ent != NULL) && (ent->children == NULL)) {
836 xmlNodePtr temp;
837
838 ent->children = xmlStringGetNodeList(doc,
839 (const xmlChar*)node->content);
Daniel Veillard2d84a892002-12-30 00:01:08 +0000840 ent->owner = 1;
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000841 temp = ent->children;
842 while (temp) {
843 temp->parent = (xmlNodePtr)ent;
844 temp = temp->next;
845 }
846 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000847 if (last == NULL) {
848 last = ret = node;
849 } else {
850 last = xmlAddNextSibling(last, node);
851 }
852 }
853 xmlFree(val);
854 }
855 cur++;
856 q = cur;
857 }
858 if (charval != 0) {
859 xmlChar buf[10];
860 int len;
861
862 len = xmlCopyCharMultiByte(buf, charval);
863 buf[len] = 0;
864 node = xmlNewDocText(doc, buf);
865 if (node != NULL) {
866 if (last == NULL) {
867 last = ret = node;
868 } else {
869 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000870 }
871 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000872
873 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000874 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000875 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000876 cur++;
877 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000878 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000879 /*
880 * Handle the last piece of text.
881 */
882 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
883 xmlNodeAddContentLen(last, q, cur - q);
884 } else {
885 node = xmlNewDocTextLen(doc, q, cur - q);
886 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000887 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000888 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000889 } else {
890 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000891 }
892 }
893 }
894 return(ret);
895}
896
897/**
898 * xmlNodeListGetString:
899 * @doc: the document
900 * @list: a Node list
901 * @inLine: should we replace entity contents or show their external form
902 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000903 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +0000904 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000905 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000906 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000907 */
908xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000909xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
910{
Owen Taylor3473f882001-02-23 17:55:21 +0000911 xmlNodePtr node = list;
912 xmlChar *ret = NULL;
913 xmlEntityPtr ent;
914
Daniel Veillard7646b182002-04-20 06:41:40 +0000915 if (list == NULL)
916 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000917
918 while (node != NULL) {
919 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000920 (node->type == XML_CDATA_SECTION_NODE)) {
921 if (inLine) {
922 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000923 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000924 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000925
Daniel Veillard7646b182002-04-20 06:41:40 +0000926 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
927 if (buffer != NULL) {
928 ret = xmlStrcat(ret, buffer);
929 xmlFree(buffer);
930 }
931 }
932 } else if (node->type == XML_ENTITY_REF_NODE) {
933 if (inLine) {
934 ent = xmlGetDocEntity(doc, node->name);
935 if (ent != NULL) {
936 xmlChar *buffer;
937
938 /* an entity content can be any "well balanced chunk",
939 * i.e. the result of the content [43] production:
940 * http://www.w3.org/TR/REC-xml#NT-content.
941 * So it can contain text, CDATA section or nested
942 * entity reference nodes (among others).
943 * -> we recursive call xmlNodeListGetString()
944 * which handles these types */
945 buffer = xmlNodeListGetString(doc, ent->children, 1);
946 if (buffer != NULL) {
947 ret = xmlStrcat(ret, buffer);
948 xmlFree(buffer);
949 }
950 } else {
951 ret = xmlStrcat(ret, node->content);
952 }
953 } else {
954 xmlChar buf[2];
955
956 buf[0] = '&';
957 buf[1] = 0;
958 ret = xmlStrncat(ret, buf, 1);
959 ret = xmlStrcat(ret, node->name);
960 buf[0] = ';';
961 buf[1] = 0;
962 ret = xmlStrncat(ret, buf, 1);
963 }
964 }
965#if 0
966 else {
967 xmlGenericError(xmlGenericErrorContext,
968 "xmlGetNodeListString : invalid node type %d\n",
969 node->type);
970 }
971#endif
972 node = node->next;
973 }
974 return (ret);
975}
Owen Taylor3473f882001-02-23 17:55:21 +0000976/**
977 * xmlNodeListGetRawString:
978 * @doc: the document
979 * @list: a Node list
980 * @inLine: should we replace entity contents or show their external form
981 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000982 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +0000983 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
984 * this function doesn't do any character encoding handling.
985 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000986 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000987 */
988xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000989xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
990{
Owen Taylor3473f882001-02-23 17:55:21 +0000991 xmlNodePtr node = list;
992 xmlChar *ret = NULL;
993 xmlEntityPtr ent;
994
Daniel Veillard7646b182002-04-20 06:41:40 +0000995 if (list == NULL)
996 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000997
998 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000999 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +00001000 (node->type == XML_CDATA_SECTION_NODE)) {
1001 if (inLine) {
1002 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001003 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001004 xmlChar *buffer;
1005
1006 buffer = xmlEncodeSpecialChars(doc, node->content);
1007 if (buffer != NULL) {
1008 ret = xmlStrcat(ret, buffer);
1009 xmlFree(buffer);
1010 }
1011 }
1012 } else if (node->type == XML_ENTITY_REF_NODE) {
1013 if (inLine) {
1014 ent = xmlGetDocEntity(doc, node->name);
1015 if (ent != NULL) {
1016 xmlChar *buffer;
1017
1018 /* an entity content can be any "well balanced chunk",
1019 * i.e. the result of the content [43] production:
1020 * http://www.w3.org/TR/REC-xml#NT-content.
1021 * So it can contain text, CDATA section or nested
1022 * entity reference nodes (among others).
1023 * -> we recursive call xmlNodeListGetRawString()
1024 * which handles these types */
1025 buffer =
1026 xmlNodeListGetRawString(doc, ent->children, 1);
1027 if (buffer != NULL) {
1028 ret = xmlStrcat(ret, buffer);
1029 xmlFree(buffer);
1030 }
1031 } else {
1032 ret = xmlStrcat(ret, node->content);
1033 }
1034 } else {
1035 xmlChar buf[2];
1036
1037 buf[0] = '&';
1038 buf[1] = 0;
1039 ret = xmlStrncat(ret, buf, 1);
1040 ret = xmlStrcat(ret, node->name);
1041 buf[0] = ';';
1042 buf[1] = 0;
1043 ret = xmlStrncat(ret, buf, 1);
1044 }
1045 }
Owen Taylor3473f882001-02-23 17:55:21 +00001046#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001047 else {
1048 xmlGenericError(xmlGenericErrorContext,
1049 "xmlGetNodeListString : invalid node type %d\n",
1050 node->type);
1051 }
Owen Taylor3473f882001-02-23 17:55:21 +00001052#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001053 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001054 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001055 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001056}
1057
1058/**
1059 * xmlNewProp:
1060 * @node: the holding node
1061 * @name: the name of the attribute
1062 * @value: the value of the attribute
1063 *
1064 * Create a new property carried by a node.
1065 * Returns a pointer to the attribute
1066 */
1067xmlAttrPtr
1068xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1069 xmlAttrPtr cur;
1070 xmlDocPtr doc = NULL;
1071
1072 if (name == NULL) {
1073#ifdef DEBUG_TREE
1074 xmlGenericError(xmlGenericErrorContext,
1075 "xmlNewProp : name == NULL\n");
1076#endif
1077 return(NULL);
1078 }
1079
1080 /*
1081 * Allocate a new property and fill the fields.
1082 */
1083 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1084 if (cur == NULL) {
1085 xmlGenericError(xmlGenericErrorContext,
1086 "xmlNewProp : malloc failed\n");
1087 return(NULL);
1088 }
1089 memset(cur, 0, sizeof(xmlAttr));
1090 cur->type = XML_ATTRIBUTE_NODE;
1091
1092 cur->parent = node;
1093 if (node != NULL) {
1094 doc = node->doc;
1095 cur->doc = doc;
1096 }
1097 cur->name = xmlStrdup(name);
1098 if (value != NULL) {
1099 xmlChar *buffer;
1100 xmlNodePtr tmp;
1101
1102 buffer = xmlEncodeEntitiesReentrant(doc, value);
1103 cur->children = xmlStringGetNodeList(doc, buffer);
1104 cur->last = NULL;
1105 tmp = cur->children;
1106 while (tmp != NULL) {
1107 tmp->parent = (xmlNodePtr) cur;
1108 tmp->doc = doc;
1109 if (tmp->next == NULL)
1110 cur->last = tmp;
1111 tmp = tmp->next;
1112 }
1113 xmlFree(buffer);
1114 }
1115
1116 /*
1117 * Add it at the end to preserve parsing order ...
1118 */
1119 if (node != NULL) {
1120 if (node->properties == NULL) {
1121 node->properties = cur;
1122 } else {
1123 xmlAttrPtr prev = node->properties;
1124
1125 while (prev->next != NULL) prev = prev->next;
1126 prev->next = cur;
1127 cur->prev = prev;
1128 }
1129 }
1130 return(cur);
1131}
1132
1133/**
1134 * xmlNewNsProp:
1135 * @node: the holding node
1136 * @ns: the namespace
1137 * @name: the name of the attribute
1138 * @value: the value of the attribute
1139 *
1140 * Create a new property tagged with a namespace and carried by a node.
1141 * Returns a pointer to the attribute
1142 */
1143xmlAttrPtr
1144xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1145 const xmlChar *value) {
1146 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001147 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001148
1149 if (name == NULL) {
1150#ifdef DEBUG_TREE
1151 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001152 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001153#endif
1154 return(NULL);
1155 }
1156
1157 /*
1158 * Allocate a new property and fill the fields.
1159 */
1160 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1161 if (cur == NULL) {
1162 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001163 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001164 return(NULL);
1165 }
1166 memset(cur, 0, sizeof(xmlAttr));
1167 cur->type = XML_ATTRIBUTE_NODE;
1168
1169 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001170 if (node != NULL) {
1171 doc = node->doc;
1172 cur->doc = doc;
1173 }
Owen Taylor3473f882001-02-23 17:55:21 +00001174 cur->ns = ns;
1175 cur->name = xmlStrdup(name);
1176 if (value != NULL) {
1177 xmlChar *buffer;
1178 xmlNodePtr tmp;
1179
Daniel Veillarda682b212001-06-07 19:59:42 +00001180 buffer = xmlEncodeEntitiesReentrant(doc, value);
1181 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001182 cur->last = NULL;
1183 tmp = cur->children;
1184 while (tmp != NULL) {
1185 tmp->parent = (xmlNodePtr) cur;
1186 if (tmp->next == NULL)
1187 cur->last = tmp;
1188 tmp = tmp->next;
1189 }
1190 xmlFree(buffer);
1191 }
1192
1193 /*
1194 * Add it at the end to preserve parsing order ...
1195 */
1196 if (node != NULL) {
1197 if (node->properties == NULL) {
1198 node->properties = cur;
1199 } else {
1200 xmlAttrPtr prev = node->properties;
1201
1202 while (prev->next != NULL) prev = prev->next;
1203 prev->next = cur;
1204 cur->prev = prev;
1205 }
1206 }
1207 return(cur);
1208}
1209
1210/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001211 * xmlNewNsPropEatName:
1212 * @node: the holding node
1213 * @ns: the namespace
1214 * @name: the name of the attribute
1215 * @value: the value of the attribute
1216 *
1217 * Create a new property tagged with a namespace and carried by a node.
1218 * Returns a pointer to the attribute
1219 */
1220xmlAttrPtr
1221xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1222 const xmlChar *value) {
1223 xmlAttrPtr cur;
1224 xmlDocPtr doc = NULL;
1225
1226 if (name == NULL) {
1227#ifdef DEBUG_TREE
1228 xmlGenericError(xmlGenericErrorContext,
1229 "xmlNewNsPropEatName : name == NULL\n");
1230#endif
1231 return(NULL);
1232 }
1233
1234 /*
1235 * Allocate a new property and fill the fields.
1236 */
1237 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1238 if (cur == NULL) {
1239 xmlGenericError(xmlGenericErrorContext,
1240 "xmlNewNsPropEatName : malloc failed\n");
1241 return(NULL);
1242 }
1243 memset(cur, 0, sizeof(xmlAttr));
1244 cur->type = XML_ATTRIBUTE_NODE;
1245
1246 cur->parent = node;
1247 if (node != NULL) {
1248 doc = node->doc;
1249 cur->doc = doc;
1250 }
1251 cur->ns = ns;
1252 cur->name = name;
1253 if (value != NULL) {
1254 xmlChar *buffer;
1255 xmlNodePtr tmp;
1256
1257 buffer = xmlEncodeEntitiesReentrant(doc, value);
1258 cur->children = xmlStringGetNodeList(doc, buffer);
1259 cur->last = NULL;
1260 tmp = cur->children;
1261 while (tmp != NULL) {
1262 tmp->parent = (xmlNodePtr) cur;
1263 if (tmp->next == NULL)
1264 cur->last = tmp;
1265 tmp = tmp->next;
1266 }
1267 xmlFree(buffer);
1268 }
1269
1270 /*
1271 * Add it at the end to preserve parsing order ...
1272 */
1273 if (node != NULL) {
1274 if (node->properties == NULL) {
1275 node->properties = cur;
1276 } else {
1277 xmlAttrPtr prev = node->properties;
1278
1279 while (prev->next != NULL) prev = prev->next;
1280 prev->next = cur;
1281 cur->prev = prev;
1282 }
1283 }
1284 return(cur);
1285}
1286
1287/**
Owen Taylor3473f882001-02-23 17:55:21 +00001288 * xmlNewDocProp:
1289 * @doc: the document
1290 * @name: the name of the attribute
1291 * @value: the value of the attribute
1292 *
1293 * Create a new property carried by a document.
1294 * Returns a pointer to the attribute
1295 */
1296xmlAttrPtr
1297xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1298 xmlAttrPtr cur;
1299
1300 if (name == NULL) {
1301#ifdef DEBUG_TREE
1302 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001303 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001304#endif
1305 return(NULL);
1306 }
1307
1308 /*
1309 * Allocate a new property and fill the fields.
1310 */
1311 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1312 if (cur == NULL) {
1313 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001314 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001315 return(NULL);
1316 }
1317 memset(cur, 0, sizeof(xmlAttr));
1318 cur->type = XML_ATTRIBUTE_NODE;
1319
1320 cur->name = xmlStrdup(name);
1321 cur->doc = doc;
1322 if (value != NULL) {
1323 xmlNodePtr tmp;
1324
1325 cur->children = xmlStringGetNodeList(doc, value);
1326 cur->last = NULL;
1327
1328 tmp = cur->children;
1329 while (tmp != NULL) {
1330 tmp->parent = (xmlNodePtr) cur;
1331 if (tmp->next == NULL)
1332 cur->last = tmp;
1333 tmp = tmp->next;
1334 }
1335 }
1336 return(cur);
1337}
1338
1339/**
1340 * xmlFreePropList:
1341 * @cur: the first property in the list
1342 *
1343 * Free a property and all its siblings, all the children are freed too.
1344 */
1345void
1346xmlFreePropList(xmlAttrPtr cur) {
1347 xmlAttrPtr next;
1348 if (cur == NULL) {
1349#ifdef DEBUG_TREE
1350 xmlGenericError(xmlGenericErrorContext,
1351 "xmlFreePropList : property == NULL\n");
1352#endif
1353 return;
1354 }
1355 while (cur != NULL) {
1356 next = cur->next;
1357 xmlFreeProp(cur);
1358 cur = next;
1359 }
1360}
1361
1362/**
1363 * xmlFreeProp:
1364 * @cur: an attribute
1365 *
1366 * Free one attribute, all the content is freed too
1367 */
1368void
1369xmlFreeProp(xmlAttrPtr cur) {
1370 if (cur == NULL) {
1371#ifdef DEBUG_TREE
1372 xmlGenericError(xmlGenericErrorContext,
1373 "xmlFreeProp : property == NULL\n");
1374#endif
1375 return;
1376 }
1377 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001378 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1379 ((cur->parent->doc->intSubset != NULL) ||
1380 (cur->parent->doc->extSubset != NULL))) {
1381 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1382 xmlRemoveID(cur->parent->doc, cur);
1383 }
Owen Taylor3473f882001-02-23 17:55:21 +00001384 if (cur->name != NULL) xmlFree((char *) cur->name);
1385 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001386 xmlFree(cur);
1387}
1388
1389/**
1390 * xmlRemoveProp:
1391 * @cur: an attribute
1392 *
1393 * Unlink and free one attribute, all the content is freed too
1394 * Note this doesn't work for namespace definition attributes
1395 *
1396 * Returns 0 if success and -1 in case of error.
1397 */
1398int
1399xmlRemoveProp(xmlAttrPtr cur) {
1400 xmlAttrPtr tmp;
1401 if (cur == NULL) {
1402#ifdef DEBUG_TREE
1403 xmlGenericError(xmlGenericErrorContext,
1404 "xmlRemoveProp : cur == NULL\n");
1405#endif
1406 return(-1);
1407 }
1408 if (cur->parent == NULL) {
1409#ifdef DEBUG_TREE
1410 xmlGenericError(xmlGenericErrorContext,
1411 "xmlRemoveProp : cur->parent == NULL\n");
1412#endif
1413 return(-1);
1414 }
1415 tmp = cur->parent->properties;
1416 if (tmp == cur) {
1417 cur->parent->properties = cur->next;
1418 xmlFreeProp(cur);
1419 return(0);
1420 }
1421 while (tmp != NULL) {
1422 if (tmp->next == cur) {
1423 tmp->next = cur->next;
1424 if (tmp->next != NULL)
1425 tmp->next->prev = tmp;
1426 xmlFreeProp(cur);
1427 return(0);
1428 }
1429 tmp = tmp->next;
1430 }
1431#ifdef DEBUG_TREE
1432 xmlGenericError(xmlGenericErrorContext,
1433 "xmlRemoveProp : attribute not owned by its node\n");
1434#endif
1435 return(-1);
1436}
1437
1438/**
1439 * xmlNewPI:
1440 * @name: the processing instruction name
1441 * @content: the PI content
1442 *
1443 * Creation of a processing instruction element.
1444 * Returns a pointer to the new node object.
1445 */
1446xmlNodePtr
1447xmlNewPI(const xmlChar *name, const xmlChar *content) {
1448 xmlNodePtr cur;
1449
1450 if (name == NULL) {
1451#ifdef DEBUG_TREE
1452 xmlGenericError(xmlGenericErrorContext,
1453 "xmlNewPI : name == NULL\n");
1454#endif
1455 return(NULL);
1456 }
1457
1458 /*
1459 * Allocate a new node and fill the fields.
1460 */
1461 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1462 if (cur == NULL) {
1463 xmlGenericError(xmlGenericErrorContext,
1464 "xmlNewPI : malloc failed\n");
1465 return(NULL);
1466 }
1467 memset(cur, 0, sizeof(xmlNode));
1468 cur->type = XML_PI_NODE;
1469
1470 cur->name = xmlStrdup(name);
1471 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001472 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001473 }
1474 return(cur);
1475}
1476
1477/**
1478 * xmlNewNode:
1479 * @ns: namespace if any
1480 * @name: the node name
1481 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001482 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001483 *
1484 * Returns a pointer to the new node object.
1485 */
1486xmlNodePtr
1487xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1488 xmlNodePtr cur;
1489
1490 if (name == NULL) {
1491#ifdef DEBUG_TREE
1492 xmlGenericError(xmlGenericErrorContext,
1493 "xmlNewNode : name == NULL\n");
1494#endif
1495 return(NULL);
1496 }
1497
1498 /*
1499 * Allocate a new node and fill the fields.
1500 */
1501 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1502 if (cur == NULL) {
1503 xmlGenericError(xmlGenericErrorContext,
1504 "xmlNewNode : malloc failed\n");
1505 return(NULL);
1506 }
1507 memset(cur, 0, sizeof(xmlNode));
1508 cur->type = XML_ELEMENT_NODE;
1509
1510 cur->name = xmlStrdup(name);
1511 cur->ns = ns;
1512 return(cur);
1513}
1514
1515/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001516 * xmlNewNodeEatName:
1517 * @ns: namespace if any
1518 * @name: the node name
1519 *
1520 * Creation of a new node element. @ns is optional (NULL).
1521 *
1522 * Returns a pointer to the new node object.
1523 */
1524xmlNodePtr
1525xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1526 xmlNodePtr cur;
1527
1528 if (name == NULL) {
1529#ifdef DEBUG_TREE
1530 xmlGenericError(xmlGenericErrorContext,
1531 "xmlNewNode : name == NULL\n");
1532#endif
1533 return(NULL);
1534 }
1535
1536 /*
1537 * Allocate a new node and fill the fields.
1538 */
1539 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1540 if (cur == NULL) {
1541 xmlGenericError(xmlGenericErrorContext,
1542 "xmlNewNode : malloc failed\n");
1543 return(NULL);
1544 }
1545 memset(cur, 0, sizeof(xmlNode));
1546 cur->type = XML_ELEMENT_NODE;
1547
1548 cur->name = name;
1549 cur->ns = ns;
1550 return(cur);
1551}
1552
1553/**
Owen Taylor3473f882001-02-23 17:55:21 +00001554 * xmlNewDocNode:
1555 * @doc: the document
1556 * @ns: namespace if any
1557 * @name: the node name
1558 * @content: the XML text content if any
1559 *
1560 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001561 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001562 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1563 * references, but XML special chars need to be escaped first by using
1564 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1565 * need entities support.
1566 *
1567 * Returns a pointer to the new node object.
1568 */
1569xmlNodePtr
1570xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1571 const xmlChar *name, const xmlChar *content) {
1572 xmlNodePtr cur;
1573
1574 cur = xmlNewNode(ns, name);
1575 if (cur != NULL) {
1576 cur->doc = doc;
1577 if (content != NULL) {
1578 cur->children = xmlStringGetNodeList(doc, content);
1579 UPDATE_LAST_CHILD_AND_PARENT(cur)
1580 }
1581 }
1582 return(cur);
1583}
1584
Daniel Veillard46de64e2002-05-29 08:21:33 +00001585/**
1586 * xmlNewDocNodeEatName:
1587 * @doc: the document
1588 * @ns: namespace if any
1589 * @name: the node name
1590 * @content: the XML text content if any
1591 *
1592 * Creation of a new node element within a document. @ns and @content
1593 * are optional (NULL).
1594 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1595 * references, but XML special chars need to be escaped first by using
1596 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1597 * need entities support.
1598 *
1599 * Returns a pointer to the new node object.
1600 */
1601xmlNodePtr
1602xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1603 xmlChar *name, const xmlChar *content) {
1604 xmlNodePtr cur;
1605
1606 cur = xmlNewNodeEatName(ns, name);
1607 if (cur != NULL) {
1608 cur->doc = doc;
1609 if (content != NULL) {
1610 cur->children = xmlStringGetNodeList(doc, content);
1611 UPDATE_LAST_CHILD_AND_PARENT(cur)
1612 }
1613 }
1614 return(cur);
1615}
1616
Owen Taylor3473f882001-02-23 17:55:21 +00001617
1618/**
1619 * xmlNewDocRawNode:
1620 * @doc: the document
1621 * @ns: namespace if any
1622 * @name: the node name
1623 * @content: the text content if any
1624 *
1625 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001626 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001627 *
1628 * Returns a pointer to the new node object.
1629 */
1630xmlNodePtr
1631xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1632 const xmlChar *name, const xmlChar *content) {
1633 xmlNodePtr cur;
1634
1635 cur = xmlNewNode(ns, name);
1636 if (cur != NULL) {
1637 cur->doc = doc;
1638 if (content != NULL) {
1639 cur->children = xmlNewDocText(doc, content);
1640 UPDATE_LAST_CHILD_AND_PARENT(cur)
1641 }
1642 }
1643 return(cur);
1644}
1645
1646/**
1647 * xmlNewDocFragment:
1648 * @doc: the document owning the fragment
1649 *
1650 * Creation of a new Fragment node.
1651 * Returns a pointer to the new node object.
1652 */
1653xmlNodePtr
1654xmlNewDocFragment(xmlDocPtr doc) {
1655 xmlNodePtr cur;
1656
1657 /*
1658 * Allocate a new DocumentFragment node and fill the fields.
1659 */
1660 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1661 if (cur == NULL) {
1662 xmlGenericError(xmlGenericErrorContext,
1663 "xmlNewDocFragment : malloc failed\n");
1664 return(NULL);
1665 }
1666 memset(cur, 0, sizeof(xmlNode));
1667 cur->type = XML_DOCUMENT_FRAG_NODE;
1668
1669 cur->doc = doc;
1670 return(cur);
1671}
1672
1673/**
1674 * xmlNewText:
1675 * @content: the text content
1676 *
1677 * Creation of a new text node.
1678 * Returns a pointer to the new node object.
1679 */
1680xmlNodePtr
1681xmlNewText(const xmlChar *content) {
1682 xmlNodePtr cur;
1683
1684 /*
1685 * Allocate a new node and fill the fields.
1686 */
1687 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1688 if (cur == NULL) {
1689 xmlGenericError(xmlGenericErrorContext,
1690 "xmlNewText : malloc failed\n");
1691 return(NULL);
1692 }
1693 memset(cur, 0, sizeof(xmlNode));
1694 cur->type = XML_TEXT_NODE;
1695
1696 cur->name = xmlStringText;
1697 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001698 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001699 }
1700 return(cur);
1701}
1702
1703/**
1704 * xmlNewTextChild:
1705 * @parent: the parent node
1706 * @ns: a namespace if any
1707 * @name: the name of the child
1708 * @content: the text content of the child if any.
1709 *
1710 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001711 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001712 * a child TEXT node will be created containing the string content.
1713 *
1714 * Returns a pointer to the new node object.
1715 */
1716xmlNodePtr
1717xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1718 const xmlChar *name, const xmlChar *content) {
1719 xmlNodePtr cur, prev;
1720
1721 if (parent == NULL) {
1722#ifdef DEBUG_TREE
1723 xmlGenericError(xmlGenericErrorContext,
1724 "xmlNewTextChild : parent == NULL\n");
1725#endif
1726 return(NULL);
1727 }
1728
1729 if (name == NULL) {
1730#ifdef DEBUG_TREE
1731 xmlGenericError(xmlGenericErrorContext,
1732 "xmlNewTextChild : name == NULL\n");
1733#endif
1734 return(NULL);
1735 }
1736
1737 /*
1738 * Allocate a new node
1739 */
1740 if (ns == NULL)
1741 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1742 else
1743 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1744 if (cur == NULL) return(NULL);
1745
1746 /*
1747 * add the new element at the end of the children list.
1748 */
1749 cur->type = XML_ELEMENT_NODE;
1750 cur->parent = parent;
1751 cur->doc = parent->doc;
1752 if (parent->children == NULL) {
1753 parent->children = cur;
1754 parent->last = cur;
1755 } else {
1756 prev = parent->last;
1757 prev->next = cur;
1758 cur->prev = prev;
1759 parent->last = cur;
1760 }
1761
1762 return(cur);
1763}
1764
1765/**
1766 * xmlNewCharRef:
1767 * @doc: the document
1768 * @name: the char ref string, starting with # or "&# ... ;"
1769 *
1770 * Creation of a new character reference node.
1771 * Returns a pointer to the new node object.
1772 */
1773xmlNodePtr
1774xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1775 xmlNodePtr cur;
1776
1777 /*
1778 * Allocate a new node and fill the fields.
1779 */
1780 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1781 if (cur == NULL) {
1782 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001783 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001784 return(NULL);
1785 }
1786 memset(cur, 0, sizeof(xmlNode));
1787 cur->type = XML_ENTITY_REF_NODE;
1788
1789 cur->doc = doc;
1790 if (name[0] == '&') {
1791 int len;
1792 name++;
1793 len = xmlStrlen(name);
1794 if (name[len - 1] == ';')
1795 cur->name = xmlStrndup(name, len - 1);
1796 else
1797 cur->name = xmlStrndup(name, len);
1798 } else
1799 cur->name = xmlStrdup(name);
1800 return(cur);
1801}
1802
1803/**
1804 * xmlNewReference:
1805 * @doc: the document
1806 * @name: the reference name, or the reference string with & and ;
1807 *
1808 * Creation of a new reference node.
1809 * Returns a pointer to the new node object.
1810 */
1811xmlNodePtr
1812xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1813 xmlNodePtr cur;
1814 xmlEntityPtr ent;
1815
1816 /*
1817 * Allocate a new node and fill the fields.
1818 */
1819 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1820 if (cur == NULL) {
1821 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001822 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001823 return(NULL);
1824 }
1825 memset(cur, 0, sizeof(xmlNode));
1826 cur->type = XML_ENTITY_REF_NODE;
1827
1828 cur->doc = doc;
1829 if (name[0] == '&') {
1830 int len;
1831 name++;
1832 len = xmlStrlen(name);
1833 if (name[len - 1] == ';')
1834 cur->name = xmlStrndup(name, len - 1);
1835 else
1836 cur->name = xmlStrndup(name, len);
1837 } else
1838 cur->name = xmlStrdup(name);
1839
1840 ent = xmlGetDocEntity(doc, cur->name);
1841 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001842 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001843 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001844 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001845 * updated. Not sure if this is 100% correct.
1846 * -George
1847 */
1848 cur->children = (xmlNodePtr) ent;
1849 cur->last = (xmlNodePtr) ent;
1850 }
1851 return(cur);
1852}
1853
1854/**
1855 * xmlNewDocText:
1856 * @doc: the document
1857 * @content: the text content
1858 *
1859 * Creation of a new text node within a document.
1860 * Returns a pointer to the new node object.
1861 */
1862xmlNodePtr
1863xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1864 xmlNodePtr cur;
1865
1866 cur = xmlNewText(content);
1867 if (cur != NULL) cur->doc = doc;
1868 return(cur);
1869}
1870
1871/**
1872 * xmlNewTextLen:
1873 * @content: the text content
1874 * @len: the text len.
1875 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001876 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001877 * Returns a pointer to the new node object.
1878 */
1879xmlNodePtr
1880xmlNewTextLen(const xmlChar *content, int len) {
1881 xmlNodePtr cur;
1882
1883 /*
1884 * Allocate a new node and fill the fields.
1885 */
1886 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1887 if (cur == NULL) {
1888 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001889 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001890 return(NULL);
1891 }
1892 memset(cur, 0, sizeof(xmlNode));
1893 cur->type = XML_TEXT_NODE;
1894
1895 cur->name = xmlStringText;
1896 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001897 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001898 }
1899 return(cur);
1900}
1901
1902/**
1903 * xmlNewDocTextLen:
1904 * @doc: the document
1905 * @content: the text content
1906 * @len: the text len.
1907 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001908 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001909 * text node pertain to a given document.
1910 * Returns a pointer to the new node object.
1911 */
1912xmlNodePtr
1913xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1914 xmlNodePtr cur;
1915
1916 cur = xmlNewTextLen(content, len);
1917 if (cur != NULL) cur->doc = doc;
1918 return(cur);
1919}
1920
1921/**
1922 * xmlNewComment:
1923 * @content: the comment content
1924 *
1925 * Creation of a new node containing a comment.
1926 * Returns a pointer to the new node object.
1927 */
1928xmlNodePtr
1929xmlNewComment(const xmlChar *content) {
1930 xmlNodePtr cur;
1931
1932 /*
1933 * Allocate a new node and fill the fields.
1934 */
1935 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1936 if (cur == NULL) {
1937 xmlGenericError(xmlGenericErrorContext,
1938 "xmlNewComment : malloc failed\n");
1939 return(NULL);
1940 }
1941 memset(cur, 0, sizeof(xmlNode));
1942 cur->type = XML_COMMENT_NODE;
1943
1944 cur->name = xmlStringComment;
1945 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001946 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001947 }
1948 return(cur);
1949}
1950
1951/**
1952 * xmlNewCDataBlock:
1953 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001954 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001955 * @len: the length of the block
1956 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001957 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001958 * Returns a pointer to the new node object.
1959 */
1960xmlNodePtr
1961xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1962 xmlNodePtr cur;
1963
1964 /*
1965 * Allocate a new node and fill the fields.
1966 */
1967 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1968 if (cur == NULL) {
1969 xmlGenericError(xmlGenericErrorContext,
1970 "xmlNewCDataBlock : malloc failed\n");
1971 return(NULL);
1972 }
1973 memset(cur, 0, sizeof(xmlNode));
1974 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001975 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001976
1977 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001978 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001979 }
1980 return(cur);
1981}
1982
1983/**
1984 * xmlNewDocComment:
1985 * @doc: the document
1986 * @content: the comment content
1987 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001988 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001989 * Returns a pointer to the new node object.
1990 */
1991xmlNodePtr
1992xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1993 xmlNodePtr cur;
1994
1995 cur = xmlNewComment(content);
1996 if (cur != NULL) cur->doc = doc;
1997 return(cur);
1998}
1999
2000/**
2001 * xmlSetTreeDoc:
2002 * @tree: the top element
2003 * @doc: the document
2004 *
2005 * update all nodes under the tree to point to the right document
2006 */
2007void
2008xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002009 xmlAttrPtr prop;
2010
Owen Taylor3473f882001-02-23 17:55:21 +00002011 if (tree == NULL)
2012 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002013 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002014 if(tree->type == XML_ELEMENT_NODE) {
2015 prop = tree->properties;
2016 while (prop != NULL) {
2017 prop->doc = doc;
2018 xmlSetListDoc(prop->children, doc);
2019 prop = prop->next;
2020 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002021 }
Owen Taylor3473f882001-02-23 17:55:21 +00002022 if (tree->children != NULL)
2023 xmlSetListDoc(tree->children, doc);
2024 tree->doc = doc;
2025 }
2026}
2027
2028/**
2029 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002030 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002031 * @doc: the document
2032 *
2033 * update all nodes in the list to point to the right document
2034 */
2035void
2036xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2037 xmlNodePtr cur;
2038
2039 if (list == NULL)
2040 return;
2041 cur = list;
2042 while (cur != NULL) {
2043 if (cur->doc != doc)
2044 xmlSetTreeDoc(cur, doc);
2045 cur = cur->next;
2046 }
2047}
2048
2049
2050/**
2051 * xmlNewChild:
2052 * @parent: the parent node
2053 * @ns: a namespace if any
2054 * @name: the name of the child
2055 * @content: the XML content of the child if any.
2056 *
2057 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002058 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002059 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2060 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2061 * references, but XML special chars need to be escaped first by using
2062 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2063 * support is not needed.
2064 *
2065 * Returns a pointer to the new node object.
2066 */
2067xmlNodePtr
2068xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2069 const xmlChar *name, const xmlChar *content) {
2070 xmlNodePtr cur, prev;
2071
2072 if (parent == NULL) {
2073#ifdef DEBUG_TREE
2074 xmlGenericError(xmlGenericErrorContext,
2075 "xmlNewChild : parent == NULL\n");
2076#endif
2077 return(NULL);
2078 }
2079
2080 if (name == NULL) {
2081#ifdef DEBUG_TREE
2082 xmlGenericError(xmlGenericErrorContext,
2083 "xmlNewChild : name == NULL\n");
2084#endif
2085 return(NULL);
2086 }
2087
2088 /*
2089 * Allocate a new node
2090 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002091 if (parent->type == XML_ELEMENT_NODE) {
2092 if (ns == NULL)
2093 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2094 else
2095 cur = xmlNewDocNode(parent->doc, ns, name, content);
2096 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2097 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2098 if (ns == NULL)
2099 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2100 else
2101 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002102 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2103 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002104 } else {
2105 return(NULL);
2106 }
Owen Taylor3473f882001-02-23 17:55:21 +00002107 if (cur == NULL) return(NULL);
2108
2109 /*
2110 * add the new element at the end of the children list.
2111 */
2112 cur->type = XML_ELEMENT_NODE;
2113 cur->parent = parent;
2114 cur->doc = parent->doc;
2115 if (parent->children == NULL) {
2116 parent->children = cur;
2117 parent->last = cur;
2118 } else {
2119 prev = parent->last;
2120 prev->next = cur;
2121 cur->prev = prev;
2122 parent->last = cur;
2123 }
2124
2125 return(cur);
2126}
2127
2128/**
2129 * xmlAddNextSibling:
2130 * @cur: the child node
2131 * @elem: the new node
2132 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002133 * Add a new node @elem as the next sibling of @cur
2134 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002135 * first unlinked from its existing context.
2136 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002137 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2138 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002139 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002140 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002141 */
2142xmlNodePtr
2143xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2144 if (cur == NULL) {
2145#ifdef DEBUG_TREE
2146 xmlGenericError(xmlGenericErrorContext,
2147 "xmlAddNextSibling : cur == NULL\n");
2148#endif
2149 return(NULL);
2150 }
2151 if (elem == NULL) {
2152#ifdef DEBUG_TREE
2153 xmlGenericError(xmlGenericErrorContext,
2154 "xmlAddNextSibling : elem == NULL\n");
2155#endif
2156 return(NULL);
2157 }
2158
2159 xmlUnlinkNode(elem);
2160
2161 if (elem->type == XML_TEXT_NODE) {
2162 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002163 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002164 xmlFreeNode(elem);
2165 return(cur);
2166 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002167 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2168 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002169 xmlChar *tmp;
2170
2171 tmp = xmlStrdup(elem->content);
2172 tmp = xmlStrcat(tmp, cur->next->content);
2173 xmlNodeSetContent(cur->next, tmp);
2174 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002175 xmlFreeNode(elem);
2176 return(cur->next);
2177 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002178 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2179 /* check if an attribute with the same name exists */
2180 xmlAttrPtr attr;
2181
2182 if (elem->ns == NULL)
2183 attr = xmlHasProp(cur->parent, elem->name);
2184 else
2185 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2186 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2187 /* different instance, destroy it (attributes must be unique) */
2188 xmlFreeProp(attr);
2189 }
Owen Taylor3473f882001-02-23 17:55:21 +00002190 }
2191
2192 if (elem->doc != cur->doc) {
2193 xmlSetTreeDoc(elem, cur->doc);
2194 }
2195 elem->parent = cur->parent;
2196 elem->prev = cur;
2197 elem->next = cur->next;
2198 cur->next = elem;
2199 if (elem->next != NULL)
2200 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002201 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002202 elem->parent->last = elem;
2203 return(elem);
2204}
2205
2206/**
2207 * xmlAddPrevSibling:
2208 * @cur: the child node
2209 * @elem: the new node
2210 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002211 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002212 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002213 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002214 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002215 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2216 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002217 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002218 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002219 */
2220xmlNodePtr
2221xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2222 if (cur == NULL) {
2223#ifdef DEBUG_TREE
2224 xmlGenericError(xmlGenericErrorContext,
2225 "xmlAddPrevSibling : cur == NULL\n");
2226#endif
2227 return(NULL);
2228 }
2229 if (elem == NULL) {
2230#ifdef DEBUG_TREE
2231 xmlGenericError(xmlGenericErrorContext,
2232 "xmlAddPrevSibling : elem == NULL\n");
2233#endif
2234 return(NULL);
2235 }
2236
2237 xmlUnlinkNode(elem);
2238
2239 if (elem->type == XML_TEXT_NODE) {
2240 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002241 xmlChar *tmp;
2242
2243 tmp = xmlStrdup(elem->content);
2244 tmp = xmlStrcat(tmp, cur->content);
2245 xmlNodeSetContent(cur, tmp);
2246 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002247 xmlFreeNode(elem);
2248 return(cur);
2249 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002250 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2251 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002252 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002253 xmlFreeNode(elem);
2254 return(cur->prev);
2255 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002256 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2257 /* check if an attribute with the same name exists */
2258 xmlAttrPtr attr;
2259
2260 if (elem->ns == NULL)
2261 attr = xmlHasProp(cur->parent, elem->name);
2262 else
2263 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2264 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2265 /* different instance, destroy it (attributes must be unique) */
2266 xmlFreeProp(attr);
2267 }
Owen Taylor3473f882001-02-23 17:55:21 +00002268 }
2269
2270 if (elem->doc != cur->doc) {
2271 xmlSetTreeDoc(elem, cur->doc);
2272 }
2273 elem->parent = cur->parent;
2274 elem->next = cur;
2275 elem->prev = cur->prev;
2276 cur->prev = elem;
2277 if (elem->prev != NULL)
2278 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002279 if (elem->parent != NULL) {
2280 if (elem->type == XML_ATTRIBUTE_NODE) {
2281 if (elem->parent->properties == (xmlAttrPtr) cur) {
2282 elem->parent->properties = (xmlAttrPtr) elem;
2283 }
2284 } else {
2285 if (elem->parent->children == cur) {
2286 elem->parent->children = elem;
2287 }
2288 }
2289 }
Owen Taylor3473f882001-02-23 17:55:21 +00002290 return(elem);
2291}
2292
2293/**
2294 * xmlAddSibling:
2295 * @cur: the child node
2296 * @elem: the new node
2297 *
2298 * Add a new element @elem to the list of siblings of @cur
2299 * merging adjacent TEXT nodes (@elem may be freed)
2300 * If the new element was already inserted in a document it is
2301 * first unlinked from its existing context.
2302 *
2303 * Returns the new element or NULL in case of error.
2304 */
2305xmlNodePtr
2306xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2307 xmlNodePtr parent;
2308
2309 if (cur == NULL) {
2310#ifdef DEBUG_TREE
2311 xmlGenericError(xmlGenericErrorContext,
2312 "xmlAddSibling : cur == NULL\n");
2313#endif
2314 return(NULL);
2315 }
2316
2317 if (elem == NULL) {
2318#ifdef DEBUG_TREE
2319 xmlGenericError(xmlGenericErrorContext,
2320 "xmlAddSibling : elem == NULL\n");
2321#endif
2322 return(NULL);
2323 }
2324
2325 /*
2326 * Constant time is we can rely on the ->parent->last to find
2327 * the last sibling.
2328 */
2329 if ((cur->parent != NULL) &&
2330 (cur->parent->children != NULL) &&
2331 (cur->parent->last != NULL) &&
2332 (cur->parent->last->next == NULL)) {
2333 cur = cur->parent->last;
2334 } else {
2335 while (cur->next != NULL) cur = cur->next;
2336 }
2337
2338 xmlUnlinkNode(elem);
2339
2340 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002341 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002342 xmlFreeNode(elem);
2343 return(cur);
2344 }
2345
2346 if (elem->doc != cur->doc) {
2347 xmlSetTreeDoc(elem, cur->doc);
2348 }
2349 parent = cur->parent;
2350 elem->prev = cur;
2351 elem->next = NULL;
2352 elem->parent = parent;
2353 cur->next = elem;
2354 if (parent != NULL)
2355 parent->last = elem;
2356
2357 return(elem);
2358}
2359
2360/**
2361 * xmlAddChildList:
2362 * @parent: the parent node
2363 * @cur: the first node in the list
2364 *
2365 * Add a list of node at the end of the child list of the parent
2366 * merging adjacent TEXT nodes (@cur may be freed)
2367 *
2368 * Returns the last child or NULL in case of error.
2369 */
2370xmlNodePtr
2371xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2372 xmlNodePtr prev;
2373
2374 if (parent == NULL) {
2375#ifdef DEBUG_TREE
2376 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002377 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002378#endif
2379 return(NULL);
2380 }
2381
2382 if (cur == NULL) {
2383#ifdef DEBUG_TREE
2384 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002385 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002386#endif
2387 return(NULL);
2388 }
2389
2390 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2391 (cur->doc != parent->doc)) {
2392#ifdef DEBUG_TREE
2393 xmlGenericError(xmlGenericErrorContext,
2394 "Elements moved to a different document\n");
2395#endif
2396 }
2397
2398 /*
2399 * add the first element at the end of the children list.
2400 */
2401 if (parent->children == NULL) {
2402 parent->children = cur;
2403 } else {
2404 /*
2405 * If cur and parent->last both are TEXT nodes, then merge them.
2406 */
2407 if ((cur->type == XML_TEXT_NODE) &&
2408 (parent->last->type == XML_TEXT_NODE) &&
2409 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002410 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002411 /*
2412 * if it's the only child, nothing more to be done.
2413 */
2414 if (cur->next == NULL) {
2415 xmlFreeNode(cur);
2416 return(parent->last);
2417 }
2418 prev = cur;
2419 cur = cur->next;
2420 xmlFreeNode(prev);
2421 }
2422 prev = parent->last;
2423 prev->next = cur;
2424 cur->prev = prev;
2425 }
2426 while (cur->next != NULL) {
2427 cur->parent = parent;
2428 if (cur->doc != parent->doc) {
2429 xmlSetTreeDoc(cur, parent->doc);
2430 }
2431 cur = cur->next;
2432 }
2433 cur->parent = parent;
2434 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2435 parent->last = cur;
2436
2437 return(cur);
2438}
2439
2440/**
2441 * xmlAddChild:
2442 * @parent: the parent node
2443 * @cur: the child node
2444 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002445 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002446 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002447 * If the new node was already inserted in a document it is
2448 * first unlinked from its existing context.
2449 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2450 * If there is an attribute with equal name, it is first destroyed.
2451 *
Owen Taylor3473f882001-02-23 17:55:21 +00002452 * Returns the child or NULL in case of error.
2453 */
2454xmlNodePtr
2455xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2456 xmlNodePtr prev;
2457
2458 if (parent == NULL) {
2459#ifdef DEBUG_TREE
2460 xmlGenericError(xmlGenericErrorContext,
2461 "xmlAddChild : parent == NULL\n");
2462#endif
2463 return(NULL);
2464 }
2465
2466 if (cur == NULL) {
2467#ifdef DEBUG_TREE
2468 xmlGenericError(xmlGenericErrorContext,
2469 "xmlAddChild : child == NULL\n");
2470#endif
2471 return(NULL);
2472 }
2473
Owen Taylor3473f882001-02-23 17:55:21 +00002474 /*
2475 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002476 * cur is then freed.
2477 */
2478 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002479 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002480 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002481 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002482 xmlFreeNode(cur);
2483 return(parent);
2484 }
2485 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2486 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002487 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002488 xmlFreeNode(cur);
2489 return(parent->last);
2490 }
2491 }
2492
2493 /*
2494 * add the new element at the end of the children list.
2495 */
2496 cur->parent = parent;
2497 if (cur->doc != parent->doc) {
2498 xmlSetTreeDoc(cur, parent->doc);
2499 }
2500
2501 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002502 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002503 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002504 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002505 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002506 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002507 xmlFreeNode(cur);
2508 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002509 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002510 if (cur->type == XML_ATTRIBUTE_NODE) {
2511 if (parent->properties == NULL) {
2512 parent->properties = (xmlAttrPtr) cur;
2513 } else {
2514 /* check if an attribute with the same name exists */
2515 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002516
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002517 if (cur->ns == NULL)
2518 lastattr = xmlHasProp(parent, cur->name);
2519 else
2520 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2521 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2522 /* different instance, destroy it (attributes must be unique) */
2523 xmlFreeProp(lastattr);
2524 }
2525 /* find the end */
2526 lastattr = parent->properties;
2527 while (lastattr->next != NULL) {
2528 lastattr = lastattr->next;
2529 }
2530 lastattr->next = (xmlAttrPtr) cur;
2531 ((xmlAttrPtr) cur)->prev = lastattr;
2532 }
2533 } else {
2534 if (parent->children == NULL) {
2535 parent->children = cur;
2536 parent->last = cur;
2537 } else {
2538 prev = parent->last;
2539 prev->next = cur;
2540 cur->prev = prev;
2541 parent->last = cur;
2542 }
2543 }
Owen Taylor3473f882001-02-23 17:55:21 +00002544 return(cur);
2545}
2546
2547/**
2548 * xmlGetLastChild:
2549 * @parent: the parent node
2550 *
2551 * Search the last child of a node.
2552 * Returns the last child or NULL if none.
2553 */
2554xmlNodePtr
2555xmlGetLastChild(xmlNodePtr parent) {
2556 if (parent == NULL) {
2557#ifdef DEBUG_TREE
2558 xmlGenericError(xmlGenericErrorContext,
2559 "xmlGetLastChild : parent == NULL\n");
2560#endif
2561 return(NULL);
2562 }
2563 return(parent->last);
2564}
2565
2566/**
2567 * xmlFreeNodeList:
2568 * @cur: the first node in the list
2569 *
2570 * Free a node and all its siblings, this is a recursive behaviour, all
2571 * the children are freed too.
2572 */
2573void
2574xmlFreeNodeList(xmlNodePtr cur) {
2575 xmlNodePtr next;
2576 if (cur == NULL) {
2577#ifdef DEBUG_TREE
2578 xmlGenericError(xmlGenericErrorContext,
2579 "xmlFreeNodeList : node == NULL\n");
2580#endif
2581 return;
2582 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002583 if (cur->type == XML_NAMESPACE_DECL) {
2584 xmlFreeNsList((xmlNsPtr) cur);
2585 return;
2586 }
Owen Taylor3473f882001-02-23 17:55:21 +00002587 while (cur != NULL) {
2588 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002589 /* unroll to speed up freeing the document */
2590 if (cur->type != XML_DTD_NODE) {
2591 if ((cur->children != NULL) &&
2592 (cur->type != XML_ENTITY_REF_NODE))
2593 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002594 if (((cur->type == XML_ELEMENT_NODE) ||
2595 (cur->type == XML_XINCLUDE_START) ||
2596 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002597 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002598 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002599 if ((cur->type != XML_ELEMENT_NODE) &&
2600 (cur->type != XML_XINCLUDE_START) &&
2601 (cur->type != XML_XINCLUDE_END) &&
2602 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002603 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002604 }
2605 if (((cur->type == XML_ELEMENT_NODE) ||
2606 (cur->type == XML_XINCLUDE_START) ||
2607 (cur->type == XML_XINCLUDE_END)) &&
2608 (cur->nsDef != NULL))
2609 xmlFreeNsList(cur->nsDef);
2610
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002611 /*
2612 * When a node is a text node or a comment, it uses a global static
2613 * variable for the name of the node.
2614 *
2615 * The xmlStrEqual comparisons need to be done when (happened with
2616 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002617 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002618 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002619 * the string addresses compare are not sufficient.
2620 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002621 if ((cur->name != NULL) &&
2622 (cur->name != xmlStringText) &&
2623 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002624 (cur->name != xmlStringComment)) {
2625 if (cur->type == XML_TEXT_NODE) {
2626 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2627 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2628 xmlFree((char *) cur->name);
2629 } else if (cur->type == XML_COMMENT_NODE) {
2630 if (!xmlStrEqual(cur->name, xmlStringComment))
2631 xmlFree((char *) cur->name);
2632 } else
2633 xmlFree((char *) cur->name);
2634 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002635 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002636 xmlFree(cur);
2637 }
Owen Taylor3473f882001-02-23 17:55:21 +00002638 cur = next;
2639 }
2640}
2641
2642/**
2643 * xmlFreeNode:
2644 * @cur: the node
2645 *
2646 * Free a node, this is a recursive behaviour, all the children are freed too.
2647 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2648 */
2649void
2650xmlFreeNode(xmlNodePtr cur) {
2651 if (cur == NULL) {
2652#ifdef DEBUG_TREE
2653 xmlGenericError(xmlGenericErrorContext,
2654 "xmlFreeNode : node == NULL\n");
2655#endif
2656 return;
2657 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002658 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002659 if (cur->type == XML_DTD_NODE) {
2660 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002661 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002662 }
2663 if (cur->type == XML_NAMESPACE_DECL) {
2664 xmlFreeNs((xmlNsPtr) cur);
2665 return;
2666 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00002667 if (cur->type == XML_ATTRIBUTE_NODE) {
2668 xmlFreeProp((xmlAttrPtr) cur);
2669 return;
2670 }
Owen Taylor3473f882001-02-23 17:55:21 +00002671 if ((cur->children != NULL) &&
2672 (cur->type != XML_ENTITY_REF_NODE))
2673 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002674 if (((cur->type == XML_ELEMENT_NODE) ||
2675 (cur->type == XML_XINCLUDE_START) ||
2676 (cur->type == XML_XINCLUDE_END)) &&
2677 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002678 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002679 if ((cur->type != XML_ELEMENT_NODE) &&
2680 (cur->content != NULL) &&
2681 (cur->type != XML_ENTITY_REF_NODE) &&
2682 (cur->type != XML_XINCLUDE_END) &&
2683 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002684 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002685 }
2686
Daniel Veillardacd370f2001-06-09 17:17:51 +00002687 /*
2688 * When a node is a text node or a comment, it uses a global static
2689 * variable for the name of the node.
2690 *
2691 * The xmlStrEqual comparisons need to be done when (happened with
2692 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002693 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002694 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002695 * are not sufficient.
2696 */
Owen Taylor3473f882001-02-23 17:55:21 +00002697 if ((cur->name != NULL) &&
2698 (cur->name != xmlStringText) &&
2699 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002700 (cur->name != xmlStringComment)) {
2701 if (cur->type == XML_TEXT_NODE) {
2702 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2703 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2704 xmlFree((char *) cur->name);
2705 } else if (cur->type == XML_COMMENT_NODE) {
2706 if (!xmlStrEqual(cur->name, xmlStringComment))
2707 xmlFree((char *) cur->name);
2708 } else
2709 xmlFree((char *) cur->name);
2710 }
2711
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002712 if (((cur->type == XML_ELEMENT_NODE) ||
2713 (cur->type == XML_XINCLUDE_START) ||
2714 (cur->type == XML_XINCLUDE_END)) &&
2715 (cur->nsDef != NULL))
2716 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002717 xmlFree(cur);
2718}
2719
2720/**
2721 * xmlUnlinkNode:
2722 * @cur: the node
2723 *
2724 * Unlink a node from it's current context, the node is not freed
2725 */
2726void
2727xmlUnlinkNode(xmlNodePtr cur) {
2728 if (cur == NULL) {
2729#ifdef DEBUG_TREE
2730 xmlGenericError(xmlGenericErrorContext,
2731 "xmlUnlinkNode : node == NULL\n");
2732#endif
2733 return;
2734 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002735 if (cur->type == XML_DTD_NODE) {
2736 xmlDocPtr doc;
2737 doc = cur->doc;
2738 if (doc->intSubset == (xmlDtdPtr) cur)
2739 doc->intSubset = NULL;
2740 if (doc->extSubset == (xmlDtdPtr) cur)
2741 doc->extSubset = NULL;
2742 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002743 if (cur->parent != NULL) {
2744 xmlNodePtr parent;
2745 parent = cur->parent;
2746 if (cur->type == XML_ATTRIBUTE_NODE) {
2747 if (parent->properties == (xmlAttrPtr) cur)
2748 parent->properties = ((xmlAttrPtr) cur)->next;
2749 } else {
2750 if (parent->children == cur)
2751 parent->children = cur->next;
2752 if (parent->last == cur)
2753 parent->last = cur->prev;
2754 }
2755 cur->parent = NULL;
2756 }
Owen Taylor3473f882001-02-23 17:55:21 +00002757 if (cur->next != NULL)
2758 cur->next->prev = cur->prev;
2759 if (cur->prev != NULL)
2760 cur->prev->next = cur->next;
2761 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002762}
2763
2764/**
2765 * xmlReplaceNode:
2766 * @old: the old node
2767 * @cur: the node
2768 *
2769 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002770 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002771 * first unlinked from its existing context.
2772 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002773 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002774 */
2775xmlNodePtr
2776xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2777 if (old == NULL) {
2778#ifdef DEBUG_TREE
2779 xmlGenericError(xmlGenericErrorContext,
2780 "xmlReplaceNode : old == NULL\n");
2781#endif
2782 return(NULL);
2783 }
2784 if (cur == NULL) {
2785 xmlUnlinkNode(old);
2786 return(old);
2787 }
2788 if (cur == old) {
2789 return(old);
2790 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002791 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2792#ifdef DEBUG_TREE
2793 xmlGenericError(xmlGenericErrorContext,
2794 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2795#endif
2796 return(old);
2797 }
2798 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2799#ifdef DEBUG_TREE
2800 xmlGenericError(xmlGenericErrorContext,
2801 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2802#endif
2803 return(old);
2804 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002805 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2806#ifdef DEBUG_TREE
2807 xmlGenericError(xmlGenericErrorContext,
2808 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2809#endif
2810 return(old);
2811 }
2812 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2813#ifdef DEBUG_TREE
2814 xmlGenericError(xmlGenericErrorContext,
2815 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2816#endif
2817 return(old);
2818 }
Owen Taylor3473f882001-02-23 17:55:21 +00002819 xmlUnlinkNode(cur);
2820 cur->doc = old->doc;
2821 cur->parent = old->parent;
2822 cur->next = old->next;
2823 if (cur->next != NULL)
2824 cur->next->prev = cur;
2825 cur->prev = old->prev;
2826 if (cur->prev != NULL)
2827 cur->prev->next = cur;
2828 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002829 if (cur->type == XML_ATTRIBUTE_NODE) {
2830 if (cur->parent->properties == (xmlAttrPtr)old)
2831 cur->parent->properties = ((xmlAttrPtr) cur);
2832 } else {
2833 if (cur->parent->children == old)
2834 cur->parent->children = cur;
2835 if (cur->parent->last == old)
2836 cur->parent->last = cur;
2837 }
Owen Taylor3473f882001-02-23 17:55:21 +00002838 }
2839 old->next = old->prev = NULL;
2840 old->parent = NULL;
2841 return(old);
2842}
2843
2844/************************************************************************
2845 * *
2846 * Copy operations *
2847 * *
2848 ************************************************************************/
2849
2850/**
2851 * xmlCopyNamespace:
2852 * @cur: the namespace
2853 *
2854 * Do a copy of the namespace.
2855 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002856 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002857 */
2858xmlNsPtr
2859xmlCopyNamespace(xmlNsPtr cur) {
2860 xmlNsPtr ret;
2861
2862 if (cur == NULL) return(NULL);
2863 switch (cur->type) {
2864 case XML_LOCAL_NAMESPACE:
2865 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2866 break;
2867 default:
2868#ifdef DEBUG_TREE
2869 xmlGenericError(xmlGenericErrorContext,
2870 "xmlCopyNamespace: invalid type %d\n", cur->type);
2871#endif
2872 return(NULL);
2873 }
2874 return(ret);
2875}
2876
2877/**
2878 * xmlCopyNamespaceList:
2879 * @cur: the first namespace
2880 *
2881 * Do a copy of an namespace list.
2882 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002883 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002884 */
2885xmlNsPtr
2886xmlCopyNamespaceList(xmlNsPtr cur) {
2887 xmlNsPtr ret = NULL;
2888 xmlNsPtr p = NULL,q;
2889
2890 while (cur != NULL) {
2891 q = xmlCopyNamespace(cur);
2892 if (p == NULL) {
2893 ret = p = q;
2894 } else {
2895 p->next = q;
2896 p = q;
2897 }
2898 cur = cur->next;
2899 }
2900 return(ret);
2901}
2902
2903static xmlNodePtr
2904xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2905/**
2906 * xmlCopyProp:
2907 * @target: the element where the attribute will be grafted
2908 * @cur: the attribute
2909 *
2910 * Do a copy of the attribute.
2911 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002912 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002913 */
2914xmlAttrPtr
2915xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2916 xmlAttrPtr ret;
2917
2918 if (cur == NULL) return(NULL);
2919 if (target != NULL)
2920 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2921 else if (cur->parent != NULL)
2922 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2923 else if (cur->children != NULL)
2924 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2925 else
2926 ret = xmlNewDocProp(NULL, cur->name, NULL);
2927 if (ret == NULL) return(NULL);
2928 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002929
Owen Taylor3473f882001-02-23 17:55:21 +00002930 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002931 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002932/*
2933 * if (target->doc)
2934 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2935 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2936 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2937 * else
2938 * ns = NULL;
2939 * ret->ns = ns;
2940 */
2941 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2942 if (ns == NULL) {
2943 /*
2944 * Humm, we are copying an element whose namespace is defined
2945 * out of the new tree scope. Search it in the original tree
2946 * and add it at the top of the new tree
2947 */
2948 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2949 if (ns != NULL) {
2950 xmlNodePtr root = target;
2951 xmlNodePtr pred = NULL;
2952
2953 while (root->parent != NULL) {
2954 pred = root;
2955 root = root->parent;
2956 }
2957 if (root == (xmlNodePtr) target->doc) {
2958 /* correct possibly cycling above the document elt */
2959 root = pred;
2960 }
2961 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2962 }
2963 } else {
2964 /*
2965 * we have to find something appropriate here since
2966 * we cant be sure, that the namespce we found is identified
2967 * by the prefix
2968 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002969 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002970 /* this is the nice case */
2971 ret->ns = ns;
2972 } else {
2973 /*
2974 * we are in trouble: we need a new reconcilied namespace.
2975 * This is expensive
2976 */
2977 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2978 }
2979 }
2980
Owen Taylor3473f882001-02-23 17:55:21 +00002981 } else
2982 ret->ns = NULL;
2983
2984 if (cur->children != NULL) {
2985 xmlNodePtr tmp;
2986
2987 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2988 ret->last = NULL;
2989 tmp = ret->children;
2990 while (tmp != NULL) {
2991 /* tmp->parent = (xmlNodePtr)ret; */
2992 if (tmp->next == NULL)
2993 ret->last = tmp;
2994 tmp = tmp->next;
2995 }
2996 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002997 /*
2998 * Try to handle IDs
2999 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00003000 if ((target!= NULL) && (cur!= NULL) &&
3001 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003002 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3003 if (xmlIsID(cur->doc, cur->parent, cur)) {
3004 xmlChar *id;
3005
3006 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3007 if (id != NULL) {
3008 xmlAddID(NULL, target->doc, id, ret);
3009 xmlFree(id);
3010 }
3011 }
3012 }
Owen Taylor3473f882001-02-23 17:55:21 +00003013 return(ret);
3014}
3015
3016/**
3017 * xmlCopyPropList:
3018 * @target: the element where the attributes will be grafted
3019 * @cur: the first attribute
3020 *
3021 * Do a copy of an attribute list.
3022 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003023 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003024 */
3025xmlAttrPtr
3026xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3027 xmlAttrPtr ret = NULL;
3028 xmlAttrPtr p = NULL,q;
3029
3030 while (cur != NULL) {
3031 q = xmlCopyProp(target, cur);
3032 if (p == NULL) {
3033 ret = p = q;
3034 } else {
3035 p->next = q;
3036 q->prev = p;
3037 p = q;
3038 }
3039 cur = cur->next;
3040 }
3041 return(ret);
3042}
3043
3044/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003045 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003046 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003047 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003048 * tricky reason: namespaces. Doing a direct copy of a node
3049 * say RPM:Copyright without changing the namespace pointer to
3050 * something else can produce stale links. One way to do it is
3051 * to keep a reference counter but this doesn't work as soon
3052 * as one move the element or the subtree out of the scope of
3053 * the existing namespace. The actual solution seems to add
3054 * a copy of the namespace at the top of the copied tree if
3055 * not available in the subtree.
3056 * Hence two functions, the public front-end call the inner ones
3057 */
3058
3059static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003060xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003061 int recursive) {
3062 xmlNodePtr ret;
3063
3064 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003065 switch (node->type) {
3066 case XML_TEXT_NODE:
3067 case XML_CDATA_SECTION_NODE:
3068 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003069 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003070 case XML_ENTITY_REF_NODE:
3071 case XML_ENTITY_NODE:
3072 case XML_PI_NODE:
3073 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003074 case XML_XINCLUDE_START:
3075 case XML_XINCLUDE_END:
3076 break;
3077 case XML_ATTRIBUTE_NODE:
3078 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3079 case XML_NAMESPACE_DECL:
3080 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3081
Daniel Veillard39196eb2001-06-19 18:09:42 +00003082 case XML_DOCUMENT_NODE:
3083 case XML_HTML_DOCUMENT_NODE:
3084#ifdef LIBXML_DOCB_ENABLED
3085 case XML_DOCB_DOCUMENT_NODE:
3086#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003087 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003088 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003089 case XML_NOTATION_NODE:
3090 case XML_DTD_NODE:
3091 case XML_ELEMENT_DECL:
3092 case XML_ATTRIBUTE_DECL:
3093 case XML_ENTITY_DECL:
3094 return(NULL);
3095 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003096
Owen Taylor3473f882001-02-23 17:55:21 +00003097 /*
3098 * Allocate a new node and fill the fields.
3099 */
3100 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3101 if (ret == NULL) {
3102 xmlGenericError(xmlGenericErrorContext,
3103 "xmlStaticCopyNode : malloc failed\n");
3104 return(NULL);
3105 }
3106 memset(ret, 0, sizeof(xmlNode));
3107 ret->type = node->type;
3108
3109 ret->doc = doc;
3110 ret->parent = parent;
3111 if (node->name == xmlStringText)
3112 ret->name = xmlStringText;
3113 else if (node->name == xmlStringTextNoenc)
3114 ret->name = xmlStringTextNoenc;
3115 else if (node->name == xmlStringComment)
3116 ret->name = xmlStringComment;
3117 else if (node->name != NULL)
3118 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003119 if ((node->type != XML_ELEMENT_NODE) &&
3120 (node->content != NULL) &&
3121 (node->type != XML_ENTITY_REF_NODE) &&
3122 (node->type != XML_XINCLUDE_END) &&
3123 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003124 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003125 }else{
3126 if (node->type == XML_ELEMENT_NODE)
3127 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003128 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003129 if (parent != NULL) {
3130 xmlNodePtr tmp;
3131
3132 tmp = xmlAddChild(parent, ret);
3133 /* node could have coalesced */
3134 if (tmp != ret)
3135 return(tmp);
3136 }
Owen Taylor3473f882001-02-23 17:55:21 +00003137
3138 if (!recursive) return(ret);
3139 if (node->nsDef != NULL)
3140 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3141
3142 if (node->ns != NULL) {
3143 xmlNsPtr ns;
3144
3145 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3146 if (ns == NULL) {
3147 /*
3148 * Humm, we are copying an element whose namespace is defined
3149 * out of the new tree scope. Search it in the original tree
3150 * and add it at the top of the new tree
3151 */
3152 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3153 if (ns != NULL) {
3154 xmlNodePtr root = ret;
3155
3156 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003157 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003158 }
3159 } else {
3160 /*
3161 * reference the existing namespace definition in our own tree.
3162 */
3163 ret->ns = ns;
3164 }
3165 }
3166 if (node->properties != NULL)
3167 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003168 if (node->type == XML_ENTITY_REF_NODE) {
3169 if ((doc == NULL) || (node->doc != doc)) {
3170 /*
3171 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003172 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003173 * we cannot keep the reference. Try to find it in the
3174 * target document.
3175 */
3176 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3177 } else {
3178 ret->children = node->children;
3179 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003180 ret->last = ret->children;
3181 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003182 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003183 UPDATE_LAST_CHILD_AND_PARENT(ret)
3184 }
Owen Taylor3473f882001-02-23 17:55:21 +00003185 return(ret);
3186}
3187
3188static xmlNodePtr
3189xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3190 xmlNodePtr ret = NULL;
3191 xmlNodePtr p = NULL,q;
3192
3193 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003194 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003195 if (doc == NULL) {
3196 node = node->next;
3197 continue;
3198 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003199 if (doc->intSubset == NULL) {
3200 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3201 q->doc = doc;
3202 q->parent = parent;
3203 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003204 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003205 } else {
3206 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003207 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003208 }
3209 } else
3210 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003211 if (ret == NULL) {
3212 q->prev = NULL;
3213 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003214 } else if (p != q) {
3215 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003216 p->next = q;
3217 q->prev = p;
3218 p = q;
3219 }
3220 node = node->next;
3221 }
3222 return(ret);
3223}
3224
3225/**
3226 * xmlCopyNode:
3227 * @node: the node
3228 * @recursive: if 1 do a recursive copy.
3229 *
3230 * Do a copy of the node.
3231 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003232 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003233 */
3234xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003235xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003236 xmlNodePtr ret;
3237
3238 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3239 return(ret);
3240}
3241
3242/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003243 * xmlDocCopyNode:
3244 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003245 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003246 * @recursive: if 1 do a recursive copy.
3247 *
3248 * Do a copy of the node to a given document.
3249 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003250 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003251 */
3252xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003253xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003254 xmlNodePtr ret;
3255
3256 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3257 return(ret);
3258}
3259
3260/**
Owen Taylor3473f882001-02-23 17:55:21 +00003261 * xmlCopyNodeList:
3262 * @node: the first node in the list.
3263 *
3264 * Do a recursive copy of the node list.
3265 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003266 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003267 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003268xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003269 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3270 return(ret);
3271}
3272
3273/**
Owen Taylor3473f882001-02-23 17:55:21 +00003274 * xmlCopyDtd:
3275 * @dtd: the dtd
3276 *
3277 * Do a copy of the dtd.
3278 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003279 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003280 */
3281xmlDtdPtr
3282xmlCopyDtd(xmlDtdPtr dtd) {
3283 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003284 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003285
3286 if (dtd == NULL) return(NULL);
3287 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3288 if (ret == NULL) return(NULL);
3289 if (dtd->entities != NULL)
3290 ret->entities = (void *) xmlCopyEntitiesTable(
3291 (xmlEntitiesTablePtr) dtd->entities);
3292 if (dtd->notations != NULL)
3293 ret->notations = (void *) xmlCopyNotationTable(
3294 (xmlNotationTablePtr) dtd->notations);
3295 if (dtd->elements != NULL)
3296 ret->elements = (void *) xmlCopyElementTable(
3297 (xmlElementTablePtr) dtd->elements);
3298 if (dtd->attributes != NULL)
3299 ret->attributes = (void *) xmlCopyAttributeTable(
3300 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003301 if (dtd->pentities != NULL)
3302 ret->pentities = (void *) xmlCopyEntitiesTable(
3303 (xmlEntitiesTablePtr) dtd->pentities);
3304
3305 cur = dtd->children;
3306 while (cur != NULL) {
3307 q = NULL;
3308
3309 if (cur->type == XML_ENTITY_DECL) {
3310 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3311 switch (tmp->etype) {
3312 case XML_INTERNAL_GENERAL_ENTITY:
3313 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3314 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3315 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3316 break;
3317 case XML_INTERNAL_PARAMETER_ENTITY:
3318 case XML_EXTERNAL_PARAMETER_ENTITY:
3319 q = (xmlNodePtr)
3320 xmlGetParameterEntityFromDtd(ret, tmp->name);
3321 break;
3322 case XML_INTERNAL_PREDEFINED_ENTITY:
3323 break;
3324 }
3325 } else if (cur->type == XML_ELEMENT_DECL) {
3326 xmlElementPtr tmp = (xmlElementPtr) cur;
3327 q = (xmlNodePtr)
3328 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3329 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3330 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3331 q = (xmlNodePtr)
3332 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3333 } else if (cur->type == XML_COMMENT_NODE) {
3334 q = xmlCopyNode(cur, 0);
3335 }
3336
3337 if (q == NULL) {
3338 cur = cur->next;
3339 continue;
3340 }
3341
3342 if (p == NULL)
3343 ret->children = q;
3344 else
3345 p->next = q;
3346
3347 q->prev = p;
3348 q->parent = (xmlNodePtr) ret;
3349 q->next = NULL;
3350 ret->last = q;
3351 p = q;
3352 cur = cur->next;
3353 }
3354
Owen Taylor3473f882001-02-23 17:55:21 +00003355 return(ret);
3356}
3357
3358/**
3359 * xmlCopyDoc:
3360 * @doc: the document
3361 * @recursive: if 1 do a recursive copy.
3362 *
3363 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003364 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003365 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003366 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003367 */
3368xmlDocPtr
3369xmlCopyDoc(xmlDocPtr doc, int recursive) {
3370 xmlDocPtr ret;
3371
3372 if (doc == NULL) return(NULL);
3373 ret = xmlNewDoc(doc->version);
3374 if (ret == NULL) return(NULL);
3375 if (doc->name != NULL)
3376 ret->name = xmlMemStrdup(doc->name);
3377 if (doc->encoding != NULL)
3378 ret->encoding = xmlStrdup(doc->encoding);
3379 ret->charset = doc->charset;
3380 ret->compression = doc->compression;
3381 ret->standalone = doc->standalone;
3382 if (!recursive) return(ret);
3383
Daniel Veillardb33c2012001-04-25 12:59:04 +00003384 ret->last = NULL;
3385 ret->children = NULL;
3386 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003387 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003388 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003389 ret->intSubset->parent = ret;
3390 }
Owen Taylor3473f882001-02-23 17:55:21 +00003391 if (doc->oldNs != NULL)
3392 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3393 if (doc->children != NULL) {
3394 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003395
3396 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3397 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003398 ret->last = NULL;
3399 tmp = ret->children;
3400 while (tmp != NULL) {
3401 if (tmp->next == NULL)
3402 ret->last = tmp;
3403 tmp = tmp->next;
3404 }
3405 }
3406 return(ret);
3407}
3408
3409/************************************************************************
3410 * *
3411 * Content access functions *
3412 * *
3413 ************************************************************************/
3414
3415/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003416 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003417 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003418 *
3419 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003420 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003421 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003422 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003423 */
3424long
3425xmlGetLineNo(xmlNodePtr node)
3426{
3427 long result = -1;
3428
3429 if (!node)
3430 return result;
3431 if (node->type == XML_ELEMENT_NODE)
3432 result = (long) node->content;
3433 else if ((node->prev != NULL) &&
3434 ((node->prev->type == XML_ELEMENT_NODE) ||
3435 (node->prev->type == XML_TEXT_NODE)))
3436 result = xmlGetLineNo(node->prev);
3437 else if ((node->parent != NULL) &&
3438 ((node->parent->type == XML_ELEMENT_NODE) ||
3439 (node->parent->type == XML_TEXT_NODE)))
3440 result = xmlGetLineNo(node->parent);
3441
3442 return result;
3443}
3444
3445/**
3446 * xmlGetNodePath:
3447 * @node: a node
3448 *
3449 * Build a structure based Path for the given node
3450 *
3451 * Returns the new path or NULL in case of error. The caller must free
3452 * the returned string
3453 */
3454xmlChar *
3455xmlGetNodePath(xmlNodePtr node)
3456{
3457 xmlNodePtr cur, tmp, next;
3458 xmlChar *buffer = NULL, *temp;
3459 size_t buf_len;
3460 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003461 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003462 const char *name;
3463 char nametemp[100];
3464 int occur = 0;
3465
3466 if (node == NULL)
3467 return (NULL);
3468
3469 buf_len = 500;
3470 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3471 if (buffer == NULL)
3472 return (NULL);
3473 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3474 if (buf == NULL) {
3475 xmlFree(buffer);
3476 return (NULL);
3477 }
3478
3479 buffer[0] = 0;
3480 cur = node;
3481 do {
3482 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003483 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003484 occur = 0;
3485 if ((cur->type == XML_DOCUMENT_NODE) ||
3486 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3487 if (buffer[0] == '/')
3488 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003489 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003490 next = NULL;
3491 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003492 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003493 name = (const char *) cur->name;
3494 if (cur->ns) {
3495 snprintf(nametemp, sizeof(nametemp) - 1,
3496 "%s:%s", cur->ns->prefix, cur->name);
3497 nametemp[sizeof(nametemp) - 1] = 0;
3498 name = nametemp;
3499 }
3500 next = cur->parent;
3501
3502 /*
3503 * Thumbler index computation
3504 */
3505 tmp = cur->prev;
3506 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003507 if ((tmp->type == XML_ELEMENT_NODE) &&
3508 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003509 occur++;
3510 tmp = tmp->prev;
3511 }
3512 if (occur == 0) {
3513 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003514 while (tmp != NULL && occur == 0) {
3515 if ((tmp->type == XML_ELEMENT_NODE) &&
3516 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003517 occur++;
3518 tmp = tmp->next;
3519 }
3520 if (occur != 0)
3521 occur = 1;
3522 } else
3523 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003524 } else if (cur->type == XML_COMMENT_NODE) {
3525 sep = "/";
3526 name = "comment()";
3527 next = cur->parent;
3528
3529 /*
3530 * Thumbler index computation
3531 */
3532 tmp = cur->prev;
3533 while (tmp != NULL) {
3534 if (tmp->type == XML_COMMENT_NODE)
3535 occur++;
3536 tmp = tmp->prev;
3537 }
3538 if (occur == 0) {
3539 tmp = cur->next;
3540 while (tmp != NULL && occur == 0) {
3541 if (tmp->type == XML_COMMENT_NODE)
3542 occur++;
3543 tmp = tmp->next;
3544 }
3545 if (occur != 0)
3546 occur = 1;
3547 } else
3548 occur++;
3549 } else if ((cur->type == XML_TEXT_NODE) ||
3550 (cur->type == XML_CDATA_SECTION_NODE)) {
3551 sep = "/";
3552 name = "text()";
3553 next = cur->parent;
3554
3555 /*
3556 * Thumbler index computation
3557 */
3558 tmp = cur->prev;
3559 while (tmp != NULL) {
3560 if ((cur->type == XML_TEXT_NODE) ||
3561 (cur->type == XML_CDATA_SECTION_NODE))
3562 occur++;
3563 tmp = tmp->prev;
3564 }
3565 if (occur == 0) {
3566 tmp = cur->next;
3567 while (tmp != NULL && occur == 0) {
3568 if ((cur->type == XML_TEXT_NODE) ||
3569 (cur->type == XML_CDATA_SECTION_NODE))
3570 occur++;
3571 tmp = tmp->next;
3572 }
3573 if (occur != 0)
3574 occur = 1;
3575 } else
3576 occur++;
3577 } else if (cur->type == XML_PI_NODE) {
3578 sep = "/";
3579 snprintf(nametemp, sizeof(nametemp) - 1,
3580 "processing-instruction('%s')", cur->name);
3581 nametemp[sizeof(nametemp) - 1] = 0;
3582 name = nametemp;
3583
3584 next = cur->parent;
3585
3586 /*
3587 * Thumbler index computation
3588 */
3589 tmp = cur->prev;
3590 while (tmp != NULL) {
3591 if ((tmp->type == XML_PI_NODE) &&
3592 (xmlStrEqual(cur->name, tmp->name)))
3593 occur++;
3594 tmp = tmp->prev;
3595 }
3596 if (occur == 0) {
3597 tmp = cur->next;
3598 while (tmp != NULL && occur == 0) {
3599 if ((tmp->type == XML_PI_NODE) &&
3600 (xmlStrEqual(cur->name, tmp->name)))
3601 occur++;
3602 tmp = tmp->next;
3603 }
3604 if (occur != 0)
3605 occur = 1;
3606 } else
3607 occur++;
3608
Daniel Veillard8faa7832001-11-26 15:58:08 +00003609 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003610 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003611 name = (const char *) (((xmlAttrPtr) cur)->name);
3612 next = ((xmlAttrPtr) cur)->parent;
3613 } else {
3614 next = cur->parent;
3615 }
3616
3617 /*
3618 * Make sure there is enough room
3619 */
3620 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3621 buf_len =
3622 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3623 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3624 if (temp == NULL) {
3625 xmlFree(buf);
3626 xmlFree(buffer);
3627 return (NULL);
3628 }
3629 buffer = temp;
3630 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3631 if (temp == NULL) {
3632 xmlFree(buf);
3633 xmlFree(buffer);
3634 return (NULL);
3635 }
3636 buf = temp;
3637 }
3638 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003639 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003640 sep, name, (char *) buffer);
3641 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003642 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003643 sep, name, occur, (char *) buffer);
3644 snprintf((char *) buffer, buf_len, "%s", buf);
3645 cur = next;
3646 } while (cur != NULL);
3647 xmlFree(buf);
3648 return (buffer);
3649}
3650
3651/**
Owen Taylor3473f882001-02-23 17:55:21 +00003652 * xmlDocGetRootElement:
3653 * @doc: the document
3654 *
3655 * Get the root element of the document (doc->children is a list
3656 * containing possibly comments, PIs, etc ...).
3657 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003658 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003659 */
3660xmlNodePtr
3661xmlDocGetRootElement(xmlDocPtr doc) {
3662 xmlNodePtr ret;
3663
3664 if (doc == NULL) return(NULL);
3665 ret = doc->children;
3666 while (ret != NULL) {
3667 if (ret->type == XML_ELEMENT_NODE)
3668 return(ret);
3669 ret = ret->next;
3670 }
3671 return(ret);
3672}
3673
3674/**
3675 * xmlDocSetRootElement:
3676 * @doc: the document
3677 * @root: the new document root element
3678 *
3679 * Set the root element of the document (doc->children is a list
3680 * containing possibly comments, PIs, etc ...).
3681 *
3682 * Returns the old root element if any was found
3683 */
3684xmlNodePtr
3685xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3686 xmlNodePtr old = NULL;
3687
3688 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003689 if (root == NULL)
3690 return(NULL);
3691 xmlUnlinkNode(root);
3692 root->doc = doc;
3693 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003694 old = doc->children;
3695 while (old != NULL) {
3696 if (old->type == XML_ELEMENT_NODE)
3697 break;
3698 old = old->next;
3699 }
3700 if (old == NULL) {
3701 if (doc->children == NULL) {
3702 doc->children = root;
3703 doc->last = root;
3704 } else {
3705 xmlAddSibling(doc->children, root);
3706 }
3707 } else {
3708 xmlReplaceNode(old, root);
3709 }
3710 return(old);
3711}
3712
3713/**
3714 * xmlNodeSetLang:
3715 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003716 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003717 *
3718 * Set the language of a node, i.e. the values of the xml:lang
3719 * attribute.
3720 */
3721void
3722xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003723 xmlNsPtr ns;
3724
Owen Taylor3473f882001-02-23 17:55:21 +00003725 if (cur == NULL) return;
3726 switch(cur->type) {
3727 case XML_TEXT_NODE:
3728 case XML_CDATA_SECTION_NODE:
3729 case XML_COMMENT_NODE:
3730 case XML_DOCUMENT_NODE:
3731 case XML_DOCUMENT_TYPE_NODE:
3732 case XML_DOCUMENT_FRAG_NODE:
3733 case XML_NOTATION_NODE:
3734 case XML_HTML_DOCUMENT_NODE:
3735 case XML_DTD_NODE:
3736 case XML_ELEMENT_DECL:
3737 case XML_ATTRIBUTE_DECL:
3738 case XML_ENTITY_DECL:
3739 case XML_PI_NODE:
3740 case XML_ENTITY_REF_NODE:
3741 case XML_ENTITY_NODE:
3742 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003743#ifdef LIBXML_DOCB_ENABLED
3744 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003745#endif
3746 case XML_XINCLUDE_START:
3747 case XML_XINCLUDE_END:
3748 return;
3749 case XML_ELEMENT_NODE:
3750 case XML_ATTRIBUTE_NODE:
3751 break;
3752 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003753 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3754 if (ns == NULL)
3755 return;
3756 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003757}
3758
3759/**
3760 * xmlNodeGetLang:
3761 * @cur: the node being checked
3762 *
3763 * Searches the language of a node, i.e. the values of the xml:lang
3764 * attribute or the one carried by the nearest ancestor.
3765 *
3766 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003767 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003768 */
3769xmlChar *
3770xmlNodeGetLang(xmlNodePtr cur) {
3771 xmlChar *lang;
3772
3773 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003774 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003775 if (lang != NULL)
3776 return(lang);
3777 cur = cur->parent;
3778 }
3779 return(NULL);
3780}
3781
3782
3783/**
3784 * xmlNodeSetSpacePreserve:
3785 * @cur: the node being changed
3786 * @val: the xml:space value ("0": default, 1: "preserve")
3787 *
3788 * Set (or reset) the space preserving behaviour of a node, i.e. the
3789 * value of the xml:space attribute.
3790 */
3791void
3792xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003793 xmlNsPtr ns;
3794
Owen Taylor3473f882001-02-23 17:55:21 +00003795 if (cur == NULL) return;
3796 switch(cur->type) {
3797 case XML_TEXT_NODE:
3798 case XML_CDATA_SECTION_NODE:
3799 case XML_COMMENT_NODE:
3800 case XML_DOCUMENT_NODE:
3801 case XML_DOCUMENT_TYPE_NODE:
3802 case XML_DOCUMENT_FRAG_NODE:
3803 case XML_NOTATION_NODE:
3804 case XML_HTML_DOCUMENT_NODE:
3805 case XML_DTD_NODE:
3806 case XML_ELEMENT_DECL:
3807 case XML_ATTRIBUTE_DECL:
3808 case XML_ENTITY_DECL:
3809 case XML_PI_NODE:
3810 case XML_ENTITY_REF_NODE:
3811 case XML_ENTITY_NODE:
3812 case XML_NAMESPACE_DECL:
3813 case XML_XINCLUDE_START:
3814 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003815#ifdef LIBXML_DOCB_ENABLED
3816 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003817#endif
3818 return;
3819 case XML_ELEMENT_NODE:
3820 case XML_ATTRIBUTE_NODE:
3821 break;
3822 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003823 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3824 if (ns == NULL)
3825 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003826 switch (val) {
3827 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003828 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003829 break;
3830 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003831 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003832 break;
3833 }
3834}
3835
3836/**
3837 * xmlNodeGetSpacePreserve:
3838 * @cur: the node being checked
3839 *
3840 * Searches the space preserving behaviour of a node, i.e. the values
3841 * of the xml:space attribute or the one carried by the nearest
3842 * ancestor.
3843 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003844 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003845 */
3846int
3847xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3848 xmlChar *space;
3849
3850 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003851 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003852 if (space != NULL) {
3853 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3854 xmlFree(space);
3855 return(1);
3856 }
3857 if (xmlStrEqual(space, BAD_CAST "default")) {
3858 xmlFree(space);
3859 return(0);
3860 }
3861 xmlFree(space);
3862 }
3863 cur = cur->parent;
3864 }
3865 return(-1);
3866}
3867
3868/**
3869 * xmlNodeSetName:
3870 * @cur: the node being changed
3871 * @name: the new tag name
3872 *
3873 * Set (or reset) the name of a node.
3874 */
3875void
3876xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3877 if (cur == NULL) return;
3878 if (name == NULL) return;
3879 switch(cur->type) {
3880 case XML_TEXT_NODE:
3881 case XML_CDATA_SECTION_NODE:
3882 case XML_COMMENT_NODE:
3883 case XML_DOCUMENT_TYPE_NODE:
3884 case XML_DOCUMENT_FRAG_NODE:
3885 case XML_NOTATION_NODE:
3886 case XML_HTML_DOCUMENT_NODE:
3887 case XML_NAMESPACE_DECL:
3888 case XML_XINCLUDE_START:
3889 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003890#ifdef LIBXML_DOCB_ENABLED
3891 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003892#endif
3893 return;
3894 case XML_ELEMENT_NODE:
3895 case XML_ATTRIBUTE_NODE:
3896 case XML_PI_NODE:
3897 case XML_ENTITY_REF_NODE:
3898 case XML_ENTITY_NODE:
3899 case XML_DTD_NODE:
3900 case XML_DOCUMENT_NODE:
3901 case XML_ELEMENT_DECL:
3902 case XML_ATTRIBUTE_DECL:
3903 case XML_ENTITY_DECL:
3904 break;
3905 }
3906 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3907 cur->name = xmlStrdup(name);
3908}
3909
3910/**
3911 * xmlNodeSetBase:
3912 * @cur: the node being changed
3913 * @uri: the new base URI
3914 *
3915 * Set (or reset) the base URI of a node, i.e. the value of the
3916 * xml:base attribute.
3917 */
3918void
3919xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003920 xmlNsPtr ns;
3921
Owen Taylor3473f882001-02-23 17:55:21 +00003922 if (cur == NULL) return;
3923 switch(cur->type) {
3924 case XML_TEXT_NODE:
3925 case XML_CDATA_SECTION_NODE:
3926 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003927 case XML_DOCUMENT_TYPE_NODE:
3928 case XML_DOCUMENT_FRAG_NODE:
3929 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003930 case XML_DTD_NODE:
3931 case XML_ELEMENT_DECL:
3932 case XML_ATTRIBUTE_DECL:
3933 case XML_ENTITY_DECL:
3934 case XML_PI_NODE:
3935 case XML_ENTITY_REF_NODE:
3936 case XML_ENTITY_NODE:
3937 case XML_NAMESPACE_DECL:
3938 case XML_XINCLUDE_START:
3939 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003940 return;
3941 case XML_ELEMENT_NODE:
3942 case XML_ATTRIBUTE_NODE:
3943 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003944 case XML_DOCUMENT_NODE:
3945#ifdef LIBXML_DOCB_ENABLED
3946 case XML_DOCB_DOCUMENT_NODE:
3947#endif
3948 case XML_HTML_DOCUMENT_NODE: {
3949 xmlDocPtr doc = (xmlDocPtr) cur;
3950
3951 if (doc->URL != NULL)
3952 xmlFree((xmlChar *) doc->URL);
3953 if (uri == NULL)
3954 doc->URL = NULL;
3955 else
3956 doc->URL = xmlStrdup(uri);
3957 return;
3958 }
Owen Taylor3473f882001-02-23 17:55:21 +00003959 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003960
3961 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3962 if (ns == NULL)
3963 return;
3964 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003965}
3966
3967/**
Owen Taylor3473f882001-02-23 17:55:21 +00003968 * xmlNodeGetBase:
3969 * @doc: the document the node pertains to
3970 * @cur: the node being checked
3971 *
3972 * Searches for the BASE URL. The code should work on both XML
3973 * and HTML document even if base mechanisms are completely different.
3974 * It returns the base as defined in RFC 2396 sections
3975 * 5.1.1. Base URI within Document Content
3976 * and
3977 * 5.1.2. Base URI from the Encapsulating Entity
3978 * However it does not return the document base (5.1.3), use
3979 * xmlDocumentGetBase() for this
3980 *
3981 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003982 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003983 */
3984xmlChar *
3985xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003986 xmlChar *oldbase = NULL;
3987 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003988
3989 if ((cur == NULL) && (doc == NULL))
3990 return(NULL);
3991 if (doc == NULL) doc = cur->doc;
3992 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3993 cur = doc->children;
3994 while ((cur != NULL) && (cur->name != NULL)) {
3995 if (cur->type != XML_ELEMENT_NODE) {
3996 cur = cur->next;
3997 continue;
3998 }
3999 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
4000 cur = cur->children;
4001 continue;
4002 }
4003 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4004 cur = cur->children;
4005 continue;
4006 }
4007 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4008 return(xmlGetProp(cur, BAD_CAST "href"));
4009 }
4010 cur = cur->next;
4011 }
4012 return(NULL);
4013 }
4014 while (cur != NULL) {
4015 if (cur->type == XML_ENTITY_DECL) {
4016 xmlEntityPtr ent = (xmlEntityPtr) cur;
4017 return(xmlStrdup(ent->URI));
4018 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004019 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004020 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004021 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004022 if (oldbase != NULL) {
4023 newbase = xmlBuildURI(oldbase, base);
4024 if (newbase != NULL) {
4025 xmlFree(oldbase);
4026 xmlFree(base);
4027 oldbase = newbase;
4028 } else {
4029 xmlFree(oldbase);
4030 xmlFree(base);
4031 return(NULL);
4032 }
4033 } else {
4034 oldbase = base;
4035 }
4036 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4037 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4038 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4039 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004040 }
4041 }
Owen Taylor3473f882001-02-23 17:55:21 +00004042 cur = cur->parent;
4043 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004044 if ((doc != NULL) && (doc->URL != NULL)) {
4045 if (oldbase == NULL)
4046 return(xmlStrdup(doc->URL));
4047 newbase = xmlBuildURI(oldbase, doc->URL);
4048 xmlFree(oldbase);
4049 return(newbase);
4050 }
4051 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004052}
4053
4054/**
4055 * xmlNodeGetContent:
4056 * @cur: the node being read
4057 *
4058 * Read the value of a node, this can be either the text carried
4059 * directly by this node if it's a TEXT node or the aggregate string
4060 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004061 * Entity references are substituted.
4062 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004063 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004064 */
4065xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004066xmlNodeGetContent(xmlNodePtr cur)
4067{
4068 if (cur == NULL)
4069 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004070 switch (cur->type) {
4071 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004072 case XML_ELEMENT_NODE:{
4073 xmlNodePtr tmp = cur;
4074 xmlBufferPtr buffer;
4075 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004076
Daniel Veillard7646b182002-04-20 06:41:40 +00004077 buffer = xmlBufferCreate();
4078 if (buffer == NULL)
4079 return (NULL);
4080 while (tmp != NULL) {
4081 switch (tmp->type) {
4082 case XML_CDATA_SECTION_NODE:
4083 case XML_TEXT_NODE:
4084 if (tmp->content != NULL)
4085 xmlBufferCat(buffer, tmp->content);
4086 break;
4087 case XML_ENTITY_REF_NODE:{
4088 /* recursive substitution of entity references */
4089 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004090
Daniel Veillard7646b182002-04-20 06:41:40 +00004091 if (cont) {
4092 xmlBufferCat(buffer,
4093 (const xmlChar *) cont);
4094 xmlFree(cont);
4095 }
4096 break;
4097 }
4098 default:
4099 break;
4100 }
4101 /*
4102 * Skip to next node
4103 */
4104 if (tmp->children != NULL) {
4105 if (tmp->children->type != XML_ENTITY_DECL) {
4106 tmp = tmp->children;
4107 continue;
4108 }
4109 }
4110 if (tmp == cur)
4111 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004112
Daniel Veillard7646b182002-04-20 06:41:40 +00004113 if (tmp->next != NULL) {
4114 tmp = tmp->next;
4115 continue;
4116 }
4117
4118 do {
4119 tmp = tmp->parent;
4120 if (tmp == NULL)
4121 break;
4122 if (tmp == cur) {
4123 tmp = NULL;
4124 break;
4125 }
4126 if (tmp->next != NULL) {
4127 tmp = tmp->next;
4128 break;
4129 }
4130 } while (tmp != NULL);
4131 }
4132 ret = buffer->content;
4133 buffer->content = NULL;
4134 xmlBufferFree(buffer);
4135 return (ret);
4136 }
4137 case XML_ATTRIBUTE_NODE:{
4138 xmlAttrPtr attr = (xmlAttrPtr) cur;
4139
4140 if (attr->parent != NULL)
4141 return (xmlNodeListGetString
4142 (attr->parent->doc, attr->children, 1));
4143 else
4144 return (xmlNodeListGetString(NULL, attr->children, 1));
4145 break;
4146 }
Owen Taylor3473f882001-02-23 17:55:21 +00004147 case XML_COMMENT_NODE:
4148 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004149 if (cur->content != NULL)
4150 return (xmlStrdup(cur->content));
4151 return (NULL);
4152 case XML_ENTITY_REF_NODE:{
4153 xmlEntityPtr ent;
4154 xmlNodePtr tmp;
4155 xmlBufferPtr buffer;
4156 xmlChar *ret;
4157
4158 /* lookup entity declaration */
4159 ent = xmlGetDocEntity(cur->doc, cur->name);
4160 if (ent == NULL)
4161 return (NULL);
4162
4163 buffer = xmlBufferCreate();
4164 if (buffer == NULL)
4165 return (NULL);
4166
4167 /* an entity content can be any "well balanced chunk",
4168 * i.e. the result of the content [43] production:
4169 * http://www.w3.org/TR/REC-xml#NT-content
4170 * -> we iterate through child nodes and recursive call
4171 * xmlNodeGetContent() which handles all possible node types */
4172 tmp = ent->children;
4173 while (tmp) {
4174 xmlChar *cont = xmlNodeGetContent(tmp);
4175
4176 if (cont) {
4177 xmlBufferCat(buffer, (const xmlChar *) cont);
4178 xmlFree(cont);
4179 }
4180 tmp = tmp->next;
4181 }
4182
4183 ret = buffer->content;
4184 buffer->content = NULL;
4185 xmlBufferFree(buffer);
4186 return (ret);
4187 }
Owen Taylor3473f882001-02-23 17:55:21 +00004188 case XML_ENTITY_NODE:
4189 case XML_DOCUMENT_NODE:
4190 case XML_HTML_DOCUMENT_NODE:
4191 case XML_DOCUMENT_TYPE_NODE:
4192 case XML_NOTATION_NODE:
4193 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004194 case XML_XINCLUDE_START:
4195 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004196#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004197 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004198#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004199 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004200 case XML_NAMESPACE_DECL: {
4201 xmlChar *tmp;
4202
4203 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4204 return (tmp);
4205 }
Owen Taylor3473f882001-02-23 17:55:21 +00004206 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004207 /* TODO !!! */
4208 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004209 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004210 /* TODO !!! */
4211 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004212 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004213 /* TODO !!! */
4214 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004215 case XML_CDATA_SECTION_NODE:
4216 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004217 if (cur->content != NULL)
4218 return (xmlStrdup(cur->content));
4219 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004220 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004221 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004222}
Owen Taylor3473f882001-02-23 17:55:21 +00004223/**
4224 * xmlNodeSetContent:
4225 * @cur: the node being modified
4226 * @content: the new value of the content
4227 *
4228 * Replace the content of a node.
4229 */
4230void
4231xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4232 if (cur == NULL) {
4233#ifdef DEBUG_TREE
4234 xmlGenericError(xmlGenericErrorContext,
4235 "xmlNodeSetContent : node == NULL\n");
4236#endif
4237 return;
4238 }
4239 switch (cur->type) {
4240 case XML_DOCUMENT_FRAG_NODE:
4241 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004242 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004243 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4244 cur->children = xmlStringGetNodeList(cur->doc, content);
4245 UPDATE_LAST_CHILD_AND_PARENT(cur)
4246 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004247 case XML_TEXT_NODE:
4248 case XML_CDATA_SECTION_NODE:
4249 case XML_ENTITY_REF_NODE:
4250 case XML_ENTITY_NODE:
4251 case XML_PI_NODE:
4252 case XML_COMMENT_NODE:
4253 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004254 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004255 }
4256 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4257 cur->last = cur->children = NULL;
4258 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004259 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004260 } else
4261 cur->content = NULL;
4262 break;
4263 case XML_DOCUMENT_NODE:
4264 case XML_HTML_DOCUMENT_NODE:
4265 case XML_DOCUMENT_TYPE_NODE:
4266 case XML_XINCLUDE_START:
4267 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004268#ifdef LIBXML_DOCB_ENABLED
4269 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004270#endif
4271 break;
4272 case XML_NOTATION_NODE:
4273 break;
4274 case XML_DTD_NODE:
4275 break;
4276 case XML_NAMESPACE_DECL:
4277 break;
4278 case XML_ELEMENT_DECL:
4279 /* TODO !!! */
4280 break;
4281 case XML_ATTRIBUTE_DECL:
4282 /* TODO !!! */
4283 break;
4284 case XML_ENTITY_DECL:
4285 /* TODO !!! */
4286 break;
4287 }
4288}
4289
4290/**
4291 * xmlNodeSetContentLen:
4292 * @cur: the node being modified
4293 * @content: the new value of the content
4294 * @len: the size of @content
4295 *
4296 * Replace the content of a node.
4297 */
4298void
4299xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4300 if (cur == NULL) {
4301#ifdef DEBUG_TREE
4302 xmlGenericError(xmlGenericErrorContext,
4303 "xmlNodeSetContentLen : node == NULL\n");
4304#endif
4305 return;
4306 }
4307 switch (cur->type) {
4308 case XML_DOCUMENT_FRAG_NODE:
4309 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004310 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004311 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4312 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4313 UPDATE_LAST_CHILD_AND_PARENT(cur)
4314 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004315 case XML_TEXT_NODE:
4316 case XML_CDATA_SECTION_NODE:
4317 case XML_ENTITY_REF_NODE:
4318 case XML_ENTITY_NODE:
4319 case XML_PI_NODE:
4320 case XML_COMMENT_NODE:
4321 case XML_NOTATION_NODE:
4322 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004323 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004324 }
4325 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4326 cur->children = cur->last = NULL;
4327 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004328 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004329 } else
4330 cur->content = NULL;
4331 break;
4332 case XML_DOCUMENT_NODE:
4333 case XML_DTD_NODE:
4334 case XML_HTML_DOCUMENT_NODE:
4335 case XML_DOCUMENT_TYPE_NODE:
4336 case XML_NAMESPACE_DECL:
4337 case XML_XINCLUDE_START:
4338 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004339#ifdef LIBXML_DOCB_ENABLED
4340 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004341#endif
4342 break;
4343 case XML_ELEMENT_DECL:
4344 /* TODO !!! */
4345 break;
4346 case XML_ATTRIBUTE_DECL:
4347 /* TODO !!! */
4348 break;
4349 case XML_ENTITY_DECL:
4350 /* TODO !!! */
4351 break;
4352 }
4353}
4354
4355/**
4356 * xmlNodeAddContentLen:
4357 * @cur: the node being modified
4358 * @content: extra content
4359 * @len: the size of @content
4360 *
4361 * Append the extra substring to the node content.
4362 */
4363void
4364xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4365 if (cur == NULL) {
4366#ifdef DEBUG_TREE
4367 xmlGenericError(xmlGenericErrorContext,
4368 "xmlNodeAddContentLen : node == NULL\n");
4369#endif
4370 return;
4371 }
4372 if (len <= 0) return;
4373 switch (cur->type) {
4374 case XML_DOCUMENT_FRAG_NODE:
4375 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004376 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004377
Daniel Veillard7db37732001-07-12 01:20:08 +00004378 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004379 newNode = xmlNewTextLen(content, len);
4380 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004381 tmp = xmlAddChild(cur, newNode);
4382 if (tmp != newNode)
4383 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004384 if ((last != NULL) && (last->next == newNode)) {
4385 xmlTextMerge(last, newNode);
4386 }
4387 }
4388 break;
4389 }
4390 case XML_ATTRIBUTE_NODE:
4391 break;
4392 case XML_TEXT_NODE:
4393 case XML_CDATA_SECTION_NODE:
4394 case XML_ENTITY_REF_NODE:
4395 case XML_ENTITY_NODE:
4396 case XML_PI_NODE:
4397 case XML_COMMENT_NODE:
4398 case XML_NOTATION_NODE:
4399 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004400 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004401 }
4402 case XML_DOCUMENT_NODE:
4403 case XML_DTD_NODE:
4404 case XML_HTML_DOCUMENT_NODE:
4405 case XML_DOCUMENT_TYPE_NODE:
4406 case XML_NAMESPACE_DECL:
4407 case XML_XINCLUDE_START:
4408 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004409#ifdef LIBXML_DOCB_ENABLED
4410 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004411#endif
4412 break;
4413 case XML_ELEMENT_DECL:
4414 case XML_ATTRIBUTE_DECL:
4415 case XML_ENTITY_DECL:
4416 break;
4417 }
4418}
4419
4420/**
4421 * xmlNodeAddContent:
4422 * @cur: the node being modified
4423 * @content: extra content
4424 *
4425 * Append the extra substring to the node content.
4426 */
4427void
4428xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4429 int len;
4430
4431 if (cur == NULL) {
4432#ifdef DEBUG_TREE
4433 xmlGenericError(xmlGenericErrorContext,
4434 "xmlNodeAddContent : node == NULL\n");
4435#endif
4436 return;
4437 }
4438 if (content == NULL) return;
4439 len = xmlStrlen(content);
4440 xmlNodeAddContentLen(cur, content, len);
4441}
4442
4443/**
4444 * xmlTextMerge:
4445 * @first: the first text node
4446 * @second: the second text node being merged
4447 *
4448 * Merge two text nodes into one
4449 * Returns the first text node augmented
4450 */
4451xmlNodePtr
4452xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4453 if (first == NULL) return(second);
4454 if (second == NULL) return(first);
4455 if (first->type != XML_TEXT_NODE) return(first);
4456 if (second->type != XML_TEXT_NODE) return(first);
4457 if (second->name != first->name)
4458 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004459 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004460 xmlUnlinkNode(second);
4461 xmlFreeNode(second);
4462 return(first);
4463}
4464
4465/**
4466 * xmlGetNsList:
4467 * @doc: the document
4468 * @node: the current node
4469 *
4470 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004471 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004472 * that need to be freed by the caller or NULL if no
4473 * namespace if defined
4474 */
4475xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004476xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4477{
Owen Taylor3473f882001-02-23 17:55:21 +00004478 xmlNsPtr cur;
4479 xmlNsPtr *ret = NULL;
4480 int nbns = 0;
4481 int maxns = 10;
4482 int i;
4483
4484 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004485 if (node->type == XML_ELEMENT_NODE) {
4486 cur = node->nsDef;
4487 while (cur != NULL) {
4488 if (ret == NULL) {
4489 ret =
4490 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4491 sizeof(xmlNsPtr));
4492 if (ret == NULL) {
4493 xmlGenericError(xmlGenericErrorContext,
4494 "xmlGetNsList : out of memory!\n");
4495 return (NULL);
4496 }
4497 ret[nbns] = NULL;
4498 }
4499 for (i = 0; i < nbns; i++) {
4500 if ((cur->prefix == ret[i]->prefix) ||
4501 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4502 break;
4503 }
4504 if (i >= nbns) {
4505 if (nbns >= maxns) {
4506 maxns *= 2;
4507 ret = (xmlNsPtr *) xmlRealloc(ret,
4508 (maxns +
4509 1) *
4510 sizeof(xmlNsPtr));
4511 if (ret == NULL) {
4512 xmlGenericError(xmlGenericErrorContext,
4513 "xmlGetNsList : realloc failed!\n");
4514 return (NULL);
4515 }
4516 }
4517 ret[nbns++] = cur;
4518 ret[nbns] = NULL;
4519 }
Owen Taylor3473f882001-02-23 17:55:21 +00004520
Daniel Veillard77044732001-06-29 21:31:07 +00004521 cur = cur->next;
4522 }
4523 }
4524 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004525 }
Daniel Veillard77044732001-06-29 21:31:07 +00004526 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004527}
4528
4529/**
4530 * xmlSearchNs:
4531 * @doc: the document
4532 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004533 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004534 *
4535 * Search a Ns registered under a given name space for a document.
4536 * recurse on the parents until it finds the defined namespace
4537 * or return NULL otherwise.
4538 * @nameSpace can be NULL, this is a search for the default namespace.
4539 * We don't allow to cross entities boundaries. If you don't declare
4540 * the namespace within those you will be in troubles !!! A warning
4541 * is generated to cover this case.
4542 *
4543 * Returns the namespace pointer or NULL.
4544 */
4545xmlNsPtr
4546xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4547 xmlNsPtr cur;
4548
4549 if (node == NULL) return(NULL);
4550 if ((nameSpace != NULL) &&
4551 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004552 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4553 /*
4554 * The XML-1.0 namespace is normally held on the root
4555 * element. In this case exceptionally create it on the
4556 * node element.
4557 */
4558 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4559 if (cur == NULL) {
4560 xmlGenericError(xmlGenericErrorContext,
4561 "xmlSearchNs : malloc failed\n");
4562 return(NULL);
4563 }
4564 memset(cur, 0, sizeof(xmlNs));
4565 cur->type = XML_LOCAL_NAMESPACE;
4566 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4567 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4568 cur->next = node->nsDef;
4569 node->nsDef = cur;
4570 return(cur);
4571 }
Owen Taylor3473f882001-02-23 17:55:21 +00004572 if (doc->oldNs == NULL) {
4573 /*
4574 * Allocate a new Namespace and fill the fields.
4575 */
4576 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4577 if (doc->oldNs == NULL) {
4578 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004579 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004580 return(NULL);
4581 }
4582 memset(doc->oldNs, 0, sizeof(xmlNs));
4583 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4584
4585 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4586 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4587 }
4588 return(doc->oldNs);
4589 }
4590 while (node != NULL) {
4591 if ((node->type == XML_ENTITY_REF_NODE) ||
4592 (node->type == XML_ENTITY_NODE) ||
4593 (node->type == XML_ENTITY_DECL))
4594 return(NULL);
4595 if (node->type == XML_ELEMENT_NODE) {
4596 cur = node->nsDef;
4597 while (cur != NULL) {
4598 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4599 (cur->href != NULL))
4600 return(cur);
4601 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4602 (cur->href != NULL) &&
4603 (xmlStrEqual(cur->prefix, nameSpace)))
4604 return(cur);
4605 cur = cur->next;
4606 }
4607 }
4608 node = node->parent;
4609 }
4610 return(NULL);
4611}
4612
4613/**
4614 * xmlSearchNsByHref:
4615 * @doc: the document
4616 * @node: the current node
4617 * @href: the namespace value
4618 *
4619 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4620 * the defined namespace or return NULL otherwise.
4621 * Returns the namespace pointer or NULL.
4622 */
4623xmlNsPtr
4624xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4625 xmlNsPtr cur;
4626 xmlNodePtr orig = node;
4627
4628 if ((node == NULL) || (href == NULL)) return(NULL);
4629 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004630 /*
4631 * Only the document can hold the XML spec namespace.
4632 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004633 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4634 /*
4635 * The XML-1.0 namespace is normally held on the root
4636 * element. In this case exceptionally create it on the
4637 * node element.
4638 */
4639 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4640 if (cur == NULL) {
4641 xmlGenericError(xmlGenericErrorContext,
4642 "xmlSearchNs : malloc failed\n");
4643 return(NULL);
4644 }
4645 memset(cur, 0, sizeof(xmlNs));
4646 cur->type = XML_LOCAL_NAMESPACE;
4647 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4648 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4649 cur->next = node->nsDef;
4650 node->nsDef = cur;
4651 return(cur);
4652 }
Owen Taylor3473f882001-02-23 17:55:21 +00004653 if (doc->oldNs == NULL) {
4654 /*
4655 * Allocate a new Namespace and fill the fields.
4656 */
4657 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4658 if (doc->oldNs == NULL) {
4659 xmlGenericError(xmlGenericErrorContext,
4660 "xmlSearchNsByHref : malloc failed\n");
4661 return(NULL);
4662 }
4663 memset(doc->oldNs, 0, sizeof(xmlNs));
4664 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4665
4666 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4667 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4668 }
4669 return(doc->oldNs);
4670 }
4671 while (node != NULL) {
4672 cur = node->nsDef;
4673 while (cur != NULL) {
4674 if ((cur->href != NULL) && (href != NULL) &&
4675 (xmlStrEqual(cur->href, href))) {
4676 /*
4677 * Check that the prefix is not shadowed between orig and node
4678 */
4679 xmlNodePtr check = orig;
4680 xmlNsPtr tst;
4681
4682 while (check != node) {
4683 tst = check->nsDef;
4684 while (tst != NULL) {
4685 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4686 goto shadowed;
4687 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4688 (xmlStrEqual(tst->prefix, cur->prefix)))
4689 goto shadowed;
4690 tst = tst->next;
4691 }
4692 check = check->parent;
4693 }
4694 return(cur);
4695 }
4696shadowed:
4697 cur = cur->next;
4698 }
4699 node = node->parent;
4700 }
4701 return(NULL);
4702}
4703
4704/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004705 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004706 * @doc: the document
4707 * @tree: a node expected to hold the new namespace
4708 * @ns: the original namespace
4709 *
4710 * This function tries to locate a namespace definition in a tree
4711 * ancestors, or create a new namespace definition node similar to
4712 * @ns trying to reuse the same prefix. However if the given prefix is
4713 * null (default namespace) or reused within the subtree defined by
4714 * @tree or on one of its ancestors then a new prefix is generated.
4715 * Returns the (new) namespace definition or NULL in case of error
4716 */
4717xmlNsPtr
4718xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4719 xmlNsPtr def;
4720 xmlChar prefix[50];
4721 int counter = 1;
4722
4723 if (tree == NULL) {
4724#ifdef DEBUG_TREE
4725 xmlGenericError(xmlGenericErrorContext,
4726 "xmlNewReconciliedNs : tree == NULL\n");
4727#endif
4728 return(NULL);
4729 }
4730 if (ns == NULL) {
4731#ifdef DEBUG_TREE
4732 xmlGenericError(xmlGenericErrorContext,
4733 "xmlNewReconciliedNs : ns == NULL\n");
4734#endif
4735 return(NULL);
4736 }
4737 /*
4738 * Search an existing namespace definition inherited.
4739 */
4740 def = xmlSearchNsByHref(doc, tree, ns->href);
4741 if (def != NULL)
4742 return(def);
4743
4744 /*
4745 * Find a close prefix which is not already in use.
4746 * Let's strip namespace prefixes longer than 20 chars !
4747 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004748 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004749 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004750 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004751 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004752
Owen Taylor3473f882001-02-23 17:55:21 +00004753 def = xmlSearchNs(doc, tree, prefix);
4754 while (def != NULL) {
4755 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004756 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004757 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004758 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004759 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004760 def = xmlSearchNs(doc, tree, prefix);
4761 }
4762
4763 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004764 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004765 */
4766 def = xmlNewNs(tree, ns->href, prefix);
4767 return(def);
4768}
4769
4770/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004771 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004772 * @doc: the document
4773 * @tree: a node defining the subtree to reconciliate
4774 *
4775 * This function checks that all the namespaces declared within the given
4776 * tree are properly declared. This is needed for example after Copy or Cut
4777 * and then paste operations. The subtree may still hold pointers to
4778 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004779 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004780 * the new environment. If not possible the new namespaces are redeclared
4781 * on @tree at the top of the given subtree.
4782 * Returns the number of namespace declarations created or -1 in case of error.
4783 */
4784int
4785xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4786 xmlNsPtr *oldNs = NULL;
4787 xmlNsPtr *newNs = NULL;
4788 int sizeCache = 0;
4789 int nbCache = 0;
4790
4791 xmlNsPtr n;
4792 xmlNodePtr node = tree;
4793 xmlAttrPtr attr;
4794 int ret = 0, i;
4795
4796 while (node != NULL) {
4797 /*
4798 * Reconciliate the node namespace
4799 */
4800 if (node->ns != NULL) {
4801 /*
4802 * initialize the cache if needed
4803 */
4804 if (sizeCache == 0) {
4805 sizeCache = 10;
4806 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4807 sizeof(xmlNsPtr));
4808 if (oldNs == NULL) {
4809 xmlGenericError(xmlGenericErrorContext,
4810 "xmlReconciliateNs : memory pbm\n");
4811 return(-1);
4812 }
4813 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4814 sizeof(xmlNsPtr));
4815 if (newNs == NULL) {
4816 xmlGenericError(xmlGenericErrorContext,
4817 "xmlReconciliateNs : memory pbm\n");
4818 xmlFree(oldNs);
4819 return(-1);
4820 }
4821 }
4822 for (i = 0;i < nbCache;i++) {
4823 if (oldNs[i] == node->ns) {
4824 node->ns = newNs[i];
4825 break;
4826 }
4827 }
4828 if (i == nbCache) {
4829 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004830 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004831 */
4832 n = xmlNewReconciliedNs(doc, tree, node->ns);
4833 if (n != NULL) { /* :-( what if else ??? */
4834 /*
4835 * check if we need to grow the cache buffers.
4836 */
4837 if (sizeCache <= nbCache) {
4838 sizeCache *= 2;
4839 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4840 sizeof(xmlNsPtr));
4841 if (oldNs == NULL) {
4842 xmlGenericError(xmlGenericErrorContext,
4843 "xmlReconciliateNs : memory pbm\n");
4844 xmlFree(newNs);
4845 return(-1);
4846 }
4847 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4848 sizeof(xmlNsPtr));
4849 if (newNs == NULL) {
4850 xmlGenericError(xmlGenericErrorContext,
4851 "xmlReconciliateNs : memory pbm\n");
4852 xmlFree(oldNs);
4853 return(-1);
4854 }
4855 }
4856 newNs[nbCache] = n;
4857 oldNs[nbCache++] = node->ns;
4858 node->ns = n;
4859 }
4860 }
4861 }
4862 /*
4863 * now check for namespace hold by attributes on the node.
4864 */
4865 attr = node->properties;
4866 while (attr != NULL) {
4867 if (attr->ns != NULL) {
4868 /*
4869 * initialize the cache if needed
4870 */
4871 if (sizeCache == 0) {
4872 sizeCache = 10;
4873 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4874 sizeof(xmlNsPtr));
4875 if (oldNs == NULL) {
4876 xmlGenericError(xmlGenericErrorContext,
4877 "xmlReconciliateNs : memory pbm\n");
4878 return(-1);
4879 }
4880 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4881 sizeof(xmlNsPtr));
4882 if (newNs == NULL) {
4883 xmlGenericError(xmlGenericErrorContext,
4884 "xmlReconciliateNs : memory pbm\n");
4885 xmlFree(oldNs);
4886 return(-1);
4887 }
4888 }
4889 for (i = 0;i < nbCache;i++) {
4890 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00004891 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00004892 break;
4893 }
4894 }
4895 if (i == nbCache) {
4896 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004897 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004898 */
4899 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4900 if (n != NULL) { /* :-( what if else ??? */
4901 /*
4902 * check if we need to grow the cache buffers.
4903 */
4904 if (sizeCache <= nbCache) {
4905 sizeCache *= 2;
4906 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4907 sizeof(xmlNsPtr));
4908 if (oldNs == NULL) {
4909 xmlGenericError(xmlGenericErrorContext,
4910 "xmlReconciliateNs : memory pbm\n");
4911 xmlFree(newNs);
4912 return(-1);
4913 }
4914 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4915 sizeof(xmlNsPtr));
4916 if (newNs == NULL) {
4917 xmlGenericError(xmlGenericErrorContext,
4918 "xmlReconciliateNs : memory pbm\n");
4919 xmlFree(oldNs);
4920 return(-1);
4921 }
4922 }
4923 newNs[nbCache] = n;
4924 oldNs[nbCache++] = attr->ns;
4925 attr->ns = n;
4926 }
4927 }
4928 }
4929 attr = attr->next;
4930 }
4931
4932 /*
4933 * Browse the full subtree, deep first
4934 */
4935 if (node->children != NULL) {
4936 /* deep first */
4937 node = node->children;
4938 } else if ((node != tree) && (node->next != NULL)) {
4939 /* then siblings */
4940 node = node->next;
4941 } else if (node != tree) {
4942 /* go up to parents->next if needed */
4943 while (node != tree) {
4944 if (node->parent != NULL)
4945 node = node->parent;
4946 if ((node != tree) && (node->next != NULL)) {
4947 node = node->next;
4948 break;
4949 }
4950 if (node->parent == NULL) {
4951 node = NULL;
4952 break;
4953 }
4954 }
4955 /* exit condition */
4956 if (node == tree)
4957 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004958 } else
4959 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004960 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004961 if (oldNs != NULL)
4962 xmlFree(oldNs);
4963 if (newNs != NULL)
4964 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004965 return(ret);
4966}
4967
4968/**
4969 * xmlHasProp:
4970 * @node: the node
4971 * @name: the attribute name
4972 *
4973 * Search an attribute associated to a node
4974 * This function also looks in DTD attribute declaration for #FIXED or
4975 * default declaration values unless DTD use has been turned off.
4976 *
4977 * Returns the attribute or the attribute declaration or NULL if
4978 * neither was found.
4979 */
4980xmlAttrPtr
4981xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4982 xmlAttrPtr prop;
4983 xmlDocPtr doc;
4984
4985 if ((node == NULL) || (name == NULL)) return(NULL);
4986 /*
4987 * Check on the properties attached to the node
4988 */
4989 prop = node->properties;
4990 while (prop != NULL) {
4991 if (xmlStrEqual(prop->name, name)) {
4992 return(prop);
4993 }
4994 prop = prop->next;
4995 }
4996 if (!xmlCheckDTD) return(NULL);
4997
4998 /*
4999 * Check if there is a default declaration in the internal
5000 * or external subsets
5001 */
5002 doc = node->doc;
5003 if (doc != NULL) {
5004 xmlAttributePtr attrDecl;
5005 if (doc->intSubset != NULL) {
5006 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5007 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5008 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5009 if (attrDecl != NULL)
5010 return((xmlAttrPtr) attrDecl);
5011 }
5012 }
5013 return(NULL);
5014}
5015
5016/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005017 * xmlHasNsProp:
5018 * @node: the node
5019 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005020 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005021 *
5022 * Search for an attribute associated to a node
5023 * This attribute has to be anchored in the namespace specified.
5024 * This does the entity substitution.
5025 * This function looks in DTD attribute declaration for #FIXED or
5026 * default declaration values unless DTD use has been turned off.
5027 *
5028 * Returns the attribute or the attribute declaration or NULL
5029 * if neither was found.
5030 */
5031xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005032xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005033 xmlAttrPtr prop;
5034 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005035
5036 if (node == NULL)
5037 return(NULL);
5038
5039 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005040 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005041 return(xmlHasProp(node, name));
5042 while (prop != NULL) {
5043 /*
5044 * One need to have
5045 * - same attribute names
5046 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005047 */
5048 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005049 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5050 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005051 }
5052 prop = prop->next;
5053 }
5054 if (!xmlCheckDTD) return(NULL);
5055
5056 /*
5057 * Check if there is a default declaration in the internal
5058 * or external subsets
5059 */
5060 doc = node->doc;
5061 if (doc != NULL) {
5062 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005063 xmlAttributePtr attrDecl = NULL;
5064 xmlNsPtr *nsList, *cur;
5065 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005066
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005067 nsList = xmlGetNsList(node->doc, node);
5068 if (nsList == NULL)
5069 return(NULL);
5070 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5071 ename = xmlStrdup(node->ns->prefix);
5072 ename = xmlStrcat(ename, BAD_CAST ":");
5073 ename = xmlStrcat(ename, node->name);
5074 } else {
5075 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005076 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005077 if (ename == NULL) {
5078 xmlFree(nsList);
5079 return(NULL);
5080 }
5081
5082 cur = nsList;
5083 while (*cur != NULL) {
5084 if (xmlStrEqual((*cur)->href, nameSpace)) {
5085 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5086 name, (*cur)->prefix);
5087 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5088 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5089 name, (*cur)->prefix);
5090 }
5091 cur++;
5092 }
5093 xmlFree(nsList);
5094 xmlFree(ename);
5095 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005096 }
5097 }
5098 return(NULL);
5099}
5100
5101/**
Owen Taylor3473f882001-02-23 17:55:21 +00005102 * xmlGetProp:
5103 * @node: the node
5104 * @name: the attribute name
5105 *
5106 * Search and get the value of an attribute associated to a node
5107 * This does the entity substitution.
5108 * This function looks in DTD attribute declaration for #FIXED or
5109 * default declaration values unless DTD use has been turned off.
5110 *
5111 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005112 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005113 */
5114xmlChar *
5115xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5116 xmlAttrPtr prop;
5117 xmlDocPtr doc;
5118
5119 if ((node == NULL) || (name == NULL)) return(NULL);
5120 /*
5121 * Check on the properties attached to the node
5122 */
5123 prop = node->properties;
5124 while (prop != NULL) {
5125 if (xmlStrEqual(prop->name, name)) {
5126 xmlChar *ret;
5127
5128 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5129 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5130 return(ret);
5131 }
5132 prop = prop->next;
5133 }
5134 if (!xmlCheckDTD) return(NULL);
5135
5136 /*
5137 * Check if there is a default declaration in the internal
5138 * or external subsets
5139 */
5140 doc = node->doc;
5141 if (doc != NULL) {
5142 xmlAttributePtr attrDecl;
5143 if (doc->intSubset != NULL) {
5144 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5145 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5146 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5147 if (attrDecl != NULL)
5148 return(xmlStrdup(attrDecl->defaultValue));
5149 }
5150 }
5151 return(NULL);
5152}
5153
5154/**
5155 * xmlGetNsProp:
5156 * @node: the node
5157 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005158 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005159 *
5160 * Search and get the value of an attribute associated to a node
5161 * This attribute has to be anchored in the namespace specified.
5162 * This does the entity substitution.
5163 * This function looks in DTD attribute declaration for #FIXED or
5164 * default declaration values unless DTD use has been turned off.
5165 *
5166 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005167 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005168 */
5169xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005170xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005171 xmlAttrPtr prop;
5172 xmlDocPtr doc;
5173 xmlNsPtr ns;
5174
5175 if (node == NULL)
5176 return(NULL);
5177
5178 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005179 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005180 return(xmlGetProp(node, name));
5181 while (prop != NULL) {
5182 /*
5183 * One need to have
5184 * - same attribute names
5185 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005186 */
5187 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005188 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005189 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005190 xmlChar *ret;
5191
5192 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5193 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5194 return(ret);
5195 }
5196 prop = prop->next;
5197 }
5198 if (!xmlCheckDTD) return(NULL);
5199
5200 /*
5201 * Check if there is a default declaration in the internal
5202 * or external subsets
5203 */
5204 doc = node->doc;
5205 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005206 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005207 xmlAttributePtr attrDecl;
5208
Owen Taylor3473f882001-02-23 17:55:21 +00005209 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5210 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5211 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5212
5213 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5214 /*
5215 * The DTD declaration only allows a prefix search
5216 */
5217 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005218 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005219 return(xmlStrdup(attrDecl->defaultValue));
5220 }
5221 }
5222 }
5223 return(NULL);
5224}
5225
5226/**
5227 * xmlSetProp:
5228 * @node: the node
5229 * @name: the attribute name
5230 * @value: the attribute value
5231 *
5232 * Set (or reset) an attribute carried by a node.
5233 * Returns the attribute pointer.
5234 */
5235xmlAttrPtr
5236xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005237 xmlAttrPtr prop;
5238 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005239
5240 if ((node == NULL) || (name == NULL))
5241 return(NULL);
5242 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005243 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005244 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005245 if ((xmlStrEqual(prop->name, name)) &&
5246 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005247 xmlNodePtr oldprop = prop->children;
5248
Owen Taylor3473f882001-02-23 17:55:21 +00005249 prop->children = NULL;
5250 prop->last = NULL;
5251 if (value != NULL) {
5252 xmlChar *buffer;
5253 xmlNodePtr tmp;
5254
5255 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5256 prop->children = xmlStringGetNodeList(node->doc, buffer);
5257 prop->last = NULL;
5258 prop->doc = doc;
5259 tmp = prop->children;
5260 while (tmp != NULL) {
5261 tmp->parent = (xmlNodePtr) prop;
5262 tmp->doc = doc;
5263 if (tmp->next == NULL)
5264 prop->last = tmp;
5265 tmp = tmp->next;
5266 }
5267 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005268 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005269 if (oldprop != NULL)
5270 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005271 return(prop);
5272 }
5273 prop = prop->next;
5274 }
5275 prop = xmlNewProp(node, name, value);
5276 return(prop);
5277}
5278
5279/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005280 * xmlUnsetProp:
5281 * @node: the node
5282 * @name: the attribute name
5283 *
5284 * Remove an attribute carried by a node.
5285 * Returns 0 if successful, -1 if not found
5286 */
5287int
5288xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5289 xmlAttrPtr prop = node->properties, prev = NULL;;
5290
5291 if ((node == NULL) || (name == NULL))
5292 return(-1);
5293 while (prop != NULL) {
5294 if ((xmlStrEqual(prop->name, name)) &&
5295 (prop->ns == NULL)) {
5296 if (prev == NULL)
5297 node->properties = prop->next;
5298 else
5299 prev->next = prop->next;
5300 xmlFreeProp(prop);
5301 return(0);
5302 }
5303 prev = prop;
5304 prop = prop->next;
5305 }
5306 return(-1);
5307}
5308
5309/**
Owen Taylor3473f882001-02-23 17:55:21 +00005310 * xmlSetNsProp:
5311 * @node: the node
5312 * @ns: the namespace definition
5313 * @name: the attribute name
5314 * @value: the attribute value
5315 *
5316 * Set (or reset) an attribute carried by a node.
5317 * The ns structure must be in scope, this is not checked.
5318 *
5319 * Returns the attribute pointer.
5320 */
5321xmlAttrPtr
5322xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5323 const xmlChar *value) {
5324 xmlAttrPtr prop;
5325
5326 if ((node == NULL) || (name == NULL))
5327 return(NULL);
5328
5329 if (ns == NULL)
5330 return(xmlSetProp(node, name, value));
5331 if (ns->href == NULL)
5332 return(NULL);
5333 prop = node->properties;
5334
5335 while (prop != NULL) {
5336 /*
5337 * One need to have
5338 * - same attribute names
5339 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005340 */
5341 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005342 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005343 if (prop->children != NULL)
5344 xmlFreeNodeList(prop->children);
5345 prop->children = NULL;
5346 prop->last = NULL;
5347 prop->ns = ns;
5348 if (value != NULL) {
5349 xmlChar *buffer;
5350 xmlNodePtr tmp;
5351
5352 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5353 prop->children = xmlStringGetNodeList(node->doc, buffer);
5354 prop->last = NULL;
5355 tmp = prop->children;
5356 while (tmp != NULL) {
5357 tmp->parent = (xmlNodePtr) prop;
5358 if (tmp->next == NULL)
5359 prop->last = tmp;
5360 tmp = tmp->next;
5361 }
5362 xmlFree(buffer);
5363 }
5364 return(prop);
5365 }
5366 prop = prop->next;
5367 }
5368 prop = xmlNewNsProp(node, ns, name, value);
5369 return(prop);
5370}
5371
5372/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005373 * xmlUnsetNsProp:
5374 * @node: the node
5375 * @ns: the namespace definition
5376 * @name: the attribute name
5377 *
5378 * Remove an attribute carried by a node.
5379 * Returns 0 if successful, -1 if not found
5380 */
5381int
5382xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5383 xmlAttrPtr prop = node->properties, prev = NULL;;
5384
5385 if ((node == NULL) || (name == NULL))
5386 return(-1);
5387 if (ns == NULL)
5388 return(xmlUnsetProp(node, name));
5389 if (ns->href == NULL)
5390 return(-1);
5391 while (prop != NULL) {
5392 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005393 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005394 if (prev == NULL)
5395 node->properties = prop->next;
5396 else
5397 prev->next = prop->next;
5398 xmlFreeProp(prop);
5399 return(0);
5400 }
5401 prev = prop;
5402 prop = prop->next;
5403 }
5404 return(-1);
5405}
5406
5407/**
Owen Taylor3473f882001-02-23 17:55:21 +00005408 * xmlNodeIsText:
5409 * @node: the node
5410 *
5411 * Is this node a Text node ?
5412 * Returns 1 yes, 0 no
5413 */
5414int
5415xmlNodeIsText(xmlNodePtr node) {
5416 if (node == NULL) return(0);
5417
5418 if (node->type == XML_TEXT_NODE) return(1);
5419 return(0);
5420}
5421
5422/**
5423 * xmlIsBlankNode:
5424 * @node: the node
5425 *
5426 * Checks whether this node is an empty or whitespace only
5427 * (and possibly ignorable) text-node.
5428 *
5429 * Returns 1 yes, 0 no
5430 */
5431int
5432xmlIsBlankNode(xmlNodePtr node) {
5433 const xmlChar *cur;
5434 if (node == NULL) return(0);
5435
Daniel Veillard7db37732001-07-12 01:20:08 +00005436 if ((node->type != XML_TEXT_NODE) &&
5437 (node->type != XML_CDATA_SECTION_NODE))
5438 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005439 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005440 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005441 while (*cur != 0) {
5442 if (!IS_BLANK(*cur)) return(0);
5443 cur++;
5444 }
5445
5446 return(1);
5447}
5448
5449/**
5450 * xmlTextConcat:
5451 * @node: the node
5452 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005453 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005454 *
5455 * Concat the given string at the end of the existing node content
5456 */
5457
5458void
5459xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5460 if (node == NULL) return;
5461
5462 if ((node->type != XML_TEXT_NODE) &&
5463 (node->type != XML_CDATA_SECTION_NODE)) {
5464#ifdef DEBUG_TREE
5465 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005466 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005467#endif
5468 return;
5469 }
Owen Taylor3473f882001-02-23 17:55:21 +00005470 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005471}
5472
5473/************************************************************************
5474 * *
5475 * Output : to a FILE or in memory *
5476 * *
5477 ************************************************************************/
5478
Owen Taylor3473f882001-02-23 17:55:21 +00005479/**
5480 * xmlBufferCreate:
5481 *
5482 * routine to create an XML buffer.
5483 * returns the new structure.
5484 */
5485xmlBufferPtr
5486xmlBufferCreate(void) {
5487 xmlBufferPtr ret;
5488
5489 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5490 if (ret == NULL) {
5491 xmlGenericError(xmlGenericErrorContext,
5492 "xmlBufferCreate : out of memory!\n");
5493 return(NULL);
5494 }
5495 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005496 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005497 ret->alloc = xmlBufferAllocScheme;
5498 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5499 if (ret->content == NULL) {
5500 xmlGenericError(xmlGenericErrorContext,
5501 "xmlBufferCreate : out of memory!\n");
5502 xmlFree(ret);
5503 return(NULL);
5504 }
5505 ret->content[0] = 0;
5506 return(ret);
5507}
5508
5509/**
5510 * xmlBufferCreateSize:
5511 * @size: initial size of buffer
5512 *
5513 * routine to create an XML buffer.
5514 * returns the new structure.
5515 */
5516xmlBufferPtr
5517xmlBufferCreateSize(size_t size) {
5518 xmlBufferPtr ret;
5519
5520 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5521 if (ret == NULL) {
5522 xmlGenericError(xmlGenericErrorContext,
5523 "xmlBufferCreate : out of memory!\n");
5524 return(NULL);
5525 }
5526 ret->use = 0;
5527 ret->alloc = xmlBufferAllocScheme;
5528 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5529 if (ret->size){
5530 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5531 if (ret->content == NULL) {
5532 xmlGenericError(xmlGenericErrorContext,
5533 "xmlBufferCreate : out of memory!\n");
5534 xmlFree(ret);
5535 return(NULL);
5536 }
5537 ret->content[0] = 0;
5538 } else
5539 ret->content = NULL;
5540 return(ret);
5541}
5542
5543/**
5544 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005545 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005546 * @scheme: allocation scheme to use
5547 *
5548 * Sets the allocation scheme for this buffer
5549 */
5550void
5551xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5552 xmlBufferAllocationScheme scheme) {
5553 if (buf == NULL) {
5554#ifdef DEBUG_BUFFER
5555 xmlGenericError(xmlGenericErrorContext,
5556 "xmlBufferSetAllocationScheme: buf == NULL\n");
5557#endif
5558 return;
5559 }
5560
5561 buf->alloc = scheme;
5562}
5563
5564/**
5565 * xmlBufferFree:
5566 * @buf: the buffer to free
5567 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005568 * Frees an XML buffer. It frees both the content and the structure which
5569 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005570 */
5571void
5572xmlBufferFree(xmlBufferPtr buf) {
5573 if (buf == NULL) {
5574#ifdef DEBUG_BUFFER
5575 xmlGenericError(xmlGenericErrorContext,
5576 "xmlBufferFree: buf == NULL\n");
5577#endif
5578 return;
5579 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005580 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005581 xmlFree(buf->content);
5582 }
Owen Taylor3473f882001-02-23 17:55:21 +00005583 xmlFree(buf);
5584}
5585
5586/**
5587 * xmlBufferEmpty:
5588 * @buf: the buffer
5589 *
5590 * empty a buffer.
5591 */
5592void
5593xmlBufferEmpty(xmlBufferPtr buf) {
5594 if (buf->content == NULL) return;
5595 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005596 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005597}
5598
5599/**
5600 * xmlBufferShrink:
5601 * @buf: the buffer to dump
5602 * @len: the number of xmlChar to remove
5603 *
5604 * Remove the beginning of an XML buffer.
5605 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005606 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005607 */
5608int
5609xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5610 if (len == 0) return(0);
5611 if (len > buf->use) return(-1);
5612
5613 buf->use -= len;
5614 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5615
5616 buf->content[buf->use] = 0;
5617 return(len);
5618}
5619
5620/**
5621 * xmlBufferGrow:
5622 * @buf: the buffer
5623 * @len: the minimum free size to allocate
5624 *
5625 * Grow the available space of an XML buffer.
5626 *
5627 * Returns the new available space or -1 in case of error
5628 */
5629int
5630xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5631 int size;
5632 xmlChar *newbuf;
5633
5634 if (len + buf->use < buf->size) return(0);
5635
5636 size = buf->use + len + 100;
5637
5638 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5639 if (newbuf == NULL) return(-1);
5640 buf->content = newbuf;
5641 buf->size = size;
5642 return(buf->size - buf->use);
5643}
5644
5645/**
5646 * xmlBufferDump:
5647 * @file: the file output
5648 * @buf: the buffer to dump
5649 *
5650 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005651 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005652 */
5653int
5654xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5655 int ret;
5656
5657 if (buf == NULL) {
5658#ifdef DEBUG_BUFFER
5659 xmlGenericError(xmlGenericErrorContext,
5660 "xmlBufferDump: buf == NULL\n");
5661#endif
5662 return(0);
5663 }
5664 if (buf->content == NULL) {
5665#ifdef DEBUG_BUFFER
5666 xmlGenericError(xmlGenericErrorContext,
5667 "xmlBufferDump: buf->content == NULL\n");
5668#endif
5669 return(0);
5670 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005671 if (file == NULL)
5672 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005673 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5674 return(ret);
5675}
5676
5677/**
5678 * xmlBufferContent:
5679 * @buf: the buffer
5680 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005681 * Function to extract the content of a buffer
5682 *
Owen Taylor3473f882001-02-23 17:55:21 +00005683 * Returns the internal content
5684 */
5685
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005686const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005687xmlBufferContent(const xmlBufferPtr buf)
5688{
5689 if(!buf)
5690 return NULL;
5691
5692 return buf->content;
5693}
5694
5695/**
5696 * xmlBufferLength:
5697 * @buf: the buffer
5698 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005699 * Function to get the length of a buffer
5700 *
Owen Taylor3473f882001-02-23 17:55:21 +00005701 * Returns the length of data in the internal content
5702 */
5703
5704int
5705xmlBufferLength(const xmlBufferPtr buf)
5706{
5707 if(!buf)
5708 return 0;
5709
5710 return buf->use;
5711}
5712
5713/**
5714 * xmlBufferResize:
5715 * @buf: the buffer to resize
5716 * @size: the desired size
5717 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005718 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005719 *
5720 * Returns 0 in case of problems, 1 otherwise
5721 */
5722int
5723xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5724{
5725 unsigned int newSize;
5726 xmlChar* rebuf = NULL;
5727
5728 /*take care of empty case*/
5729 newSize = (buf->size ? buf->size*2 : size);
5730
5731 /* Don't resize if we don't have to */
5732 if (size < buf->size)
5733 return 1;
5734
5735 /* figure out new size */
5736 switch (buf->alloc){
5737 case XML_BUFFER_ALLOC_DOUBLEIT:
5738 while (size > newSize) newSize *= 2;
5739 break;
5740 case XML_BUFFER_ALLOC_EXACT:
5741 newSize = size+10;
5742 break;
5743 default:
5744 newSize = size+10;
5745 break;
5746 }
5747
5748 if (buf->content == NULL)
5749 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5750 else
5751 rebuf = (xmlChar *) xmlRealloc(buf->content,
5752 newSize * sizeof(xmlChar));
5753 if (rebuf == NULL) {
5754 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005755 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005756 return 0;
5757 }
5758 buf->content = rebuf;
5759 buf->size = newSize;
5760
5761 return 1;
5762}
5763
5764/**
5765 * xmlBufferAdd:
5766 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005767 * @str: the #xmlChar string
5768 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005769 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005770 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005771 * str is recomputed.
5772 */
5773void
5774xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5775 unsigned int needSize;
5776
5777 if (str == NULL) {
5778#ifdef DEBUG_BUFFER
5779 xmlGenericError(xmlGenericErrorContext,
5780 "xmlBufferAdd: str == NULL\n");
5781#endif
5782 return;
5783 }
5784 if (len < -1) {
5785#ifdef DEBUG_BUFFER
5786 xmlGenericError(xmlGenericErrorContext,
5787 "xmlBufferAdd: len < 0\n");
5788#endif
5789 return;
5790 }
5791 if (len == 0) return;
5792
5793 if (len < 0)
5794 len = xmlStrlen(str);
5795
5796 if (len <= 0) return;
5797
5798 needSize = buf->use + len + 2;
5799 if (needSize > buf->size){
5800 if (!xmlBufferResize(buf, needSize)){
5801 xmlGenericError(xmlGenericErrorContext,
5802 "xmlBufferAdd : out of memory!\n");
5803 return;
5804 }
5805 }
5806
5807 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5808 buf->use += len;
5809 buf->content[buf->use] = 0;
5810}
5811
5812/**
5813 * xmlBufferAddHead:
5814 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005815 * @str: the #xmlChar string
5816 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005817 *
5818 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005819 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005820 */
5821void
5822xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5823 unsigned int needSize;
5824
5825 if (str == NULL) {
5826#ifdef DEBUG_BUFFER
5827 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005828 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005829#endif
5830 return;
5831 }
5832 if (len < -1) {
5833#ifdef DEBUG_BUFFER
5834 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005835 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005836#endif
5837 return;
5838 }
5839 if (len == 0) return;
5840
5841 if (len < 0)
5842 len = xmlStrlen(str);
5843
5844 if (len <= 0) return;
5845
5846 needSize = buf->use + len + 2;
5847 if (needSize > buf->size){
5848 if (!xmlBufferResize(buf, needSize)){
5849 xmlGenericError(xmlGenericErrorContext,
5850 "xmlBufferAddHead : out of memory!\n");
5851 return;
5852 }
5853 }
5854
5855 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5856 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5857 buf->use += len;
5858 buf->content[buf->use] = 0;
5859}
5860
5861/**
5862 * xmlBufferCat:
5863 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005864 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005865 *
5866 * Append a zero terminated string to an XML buffer.
5867 */
5868void
5869xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5870 if (str != NULL)
5871 xmlBufferAdd(buf, str, -1);
5872}
5873
5874/**
5875 * xmlBufferCCat:
5876 * @buf: the buffer to dump
5877 * @str: the C char string
5878 *
5879 * Append a zero terminated C string to an XML buffer.
5880 */
5881void
5882xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5883 const char *cur;
5884
5885 if (str == NULL) {
5886#ifdef DEBUG_BUFFER
5887 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005888 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005889#endif
5890 return;
5891 }
5892 for (cur = str;*cur != 0;cur++) {
5893 if (buf->use + 10 >= buf->size) {
5894 if (!xmlBufferResize(buf, buf->use+10)){
5895 xmlGenericError(xmlGenericErrorContext,
5896 "xmlBufferCCat : out of memory!\n");
5897 return;
5898 }
5899 }
5900 buf->content[buf->use++] = *cur;
5901 }
5902 buf->content[buf->use] = 0;
5903}
5904
5905/**
5906 * xmlBufferWriteCHAR:
5907 * @buf: the XML buffer
5908 * @string: the string to add
5909 *
5910 * routine which manages and grows an output buffer. This one adds
5911 * xmlChars at the end of the buffer.
5912 */
5913void
Owen Taylor3473f882001-02-23 17:55:21 +00005914xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00005915(xmlBufferPtr buf, const xmlChar *string) {
5916 xmlBufferCat(buf, string);
5917}
5918
5919/**
5920 * xmlBufferWriteChar:
5921 * @buf: the XML buffer output
5922 * @string: the string to add
5923 *
5924 * routine which manage and grows an output buffer. This one add
5925 * C chars at the end of the array.
5926 */
5927void
5928xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5929 xmlBufferCCat(buf, string);
5930}
5931
5932
5933/**
5934 * xmlBufferWriteQuotedString:
5935 * @buf: the XML buffer output
5936 * @string: the string to add
5937 *
5938 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005939 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005940 * quote or double-quotes internally
5941 */
5942void
5943xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5944 if (xmlStrchr(string, '"')) {
5945 if (xmlStrchr(string, '\'')) {
5946#ifdef DEBUG_BUFFER
5947 xmlGenericError(xmlGenericErrorContext,
5948 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5949#endif
5950 }
5951 xmlBufferCCat(buf, "'");
5952 xmlBufferCat(buf, string);
5953 xmlBufferCCat(buf, "'");
5954 } else {
5955 xmlBufferCCat(buf, "\"");
5956 xmlBufferCat(buf, string);
5957 xmlBufferCCat(buf, "\"");
5958 }
5959}
5960
5961
5962/************************************************************************
5963 * *
5964 * Dumping XML tree content to a simple buffer *
5965 * *
5966 ************************************************************************/
5967
Owen Taylor3473f882001-02-23 17:55:21 +00005968/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005969 * xmlAttrSerializeContent:
5970 * @buf: the XML buffer output
5971 * @doc: the document
5972 * @attr: the attribute pointer
5973 *
5974 * Serialize the attribute in the buffer
5975 */
5976static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00005977xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
5978{
Daniel Veillarda6d05382002-02-13 13:07:41 +00005979 const xmlChar *cur, *base;
5980 xmlNodePtr children;
5981
5982 children = attr->children;
5983 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00005984 switch (children->type) {
5985 case XML_TEXT_NODE:
5986 base = cur = children->content;
5987 while (*cur != 0) {
5988 if (*cur == '\n') {
5989 if (base != cur)
5990 xmlBufferAdd(buf, base, cur - base);
5991 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5992 cur++;
5993 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00005994#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00005995 } else if (*cur == '\'') {
5996 if (base != cur)
5997 xmlBufferAdd(buf, base, cur - base);
5998 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5999 cur++;
6000 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006001#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006002 } else if (*cur == '"') {
6003 if (base != cur)
6004 xmlBufferAdd(buf, base, cur - base);
6005 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6006 cur++;
6007 base = cur;
6008 } else if (*cur == '<') {
6009 if (base != cur)
6010 xmlBufferAdd(buf, base, cur - base);
6011 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6012 cur++;
6013 base = cur;
6014 } else if (*cur == '>') {
6015 if (base != cur)
6016 xmlBufferAdd(buf, base, cur - base);
6017 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6018 cur++;
6019 base = cur;
6020 } else if (*cur == '&') {
6021 if (base != cur)
6022 xmlBufferAdd(buf, base, cur - base);
6023 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6024 cur++;
6025 base = cur;
6026 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6027 (doc->encoding ==
6028 NULL))) {
6029 /*
6030 * We assume we have UTF-8 content.
6031 */
6032 char tmp[10];
6033 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006034
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006035 if (base != cur)
6036 xmlBufferAdd(buf, base, cur - base);
6037 if (*cur < 0xC0) {
6038 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006039 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006040 if (doc != NULL)
6041 doc->encoding =
6042 xmlStrdup(BAD_CAST "ISO-8859-1");
6043 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6044 tmp[sizeof(tmp) - 1] = 0;
6045 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6046 cur++;
6047 base = cur;
6048 continue;
6049 } else if (*cur < 0xE0) {
6050 val = (cur[0]) & 0x1F;
6051 val <<= 6;
6052 val |= (cur[1]) & 0x3F;
6053 l = 2;
6054 } else if (*cur < 0xF0) {
6055 val = (cur[0]) & 0x0F;
6056 val <<= 6;
6057 val |= (cur[1]) & 0x3F;
6058 val <<= 6;
6059 val |= (cur[2]) & 0x3F;
6060 l = 3;
6061 } else if (*cur < 0xF8) {
6062 val = (cur[0]) & 0x07;
6063 val <<= 6;
6064 val |= (cur[1]) & 0x3F;
6065 val <<= 6;
6066 val |= (cur[2]) & 0x3F;
6067 val <<= 6;
6068 val |= (cur[3]) & 0x3F;
6069 l = 4;
6070 }
6071 if ((l == 1) || (!IS_CHAR(val))) {
6072 xmlGenericError(xmlGenericErrorContext,
6073 "xmlAttrSerializeContent : char out of range\n");
6074 if (doc != NULL)
6075 doc->encoding =
6076 xmlStrdup(BAD_CAST "ISO-8859-1");
6077 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6078 tmp[sizeof(tmp) - 1] = 0;
6079 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6080 cur++;
6081 base = cur;
6082 continue;
6083 }
6084 /*
6085 * We could do multiple things here. Just save
6086 * as a char ref
6087 */
6088 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6089 tmp[sizeof(tmp) - 1] = 0;
6090 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6091 cur += l;
6092 base = cur;
6093 } else {
6094 cur++;
6095 }
6096 }
6097 if (base != cur)
6098 xmlBufferAdd(buf, base, cur - base);
6099 break;
6100 case XML_ENTITY_REF_NODE:
6101 xmlBufferAdd(buf, BAD_CAST "&", 1);
6102 xmlBufferAdd(buf, children->name,
6103 xmlStrlen(children->name));
6104 xmlBufferAdd(buf, BAD_CAST ";", 1);
6105 break;
6106 default:
6107 /* should not happen unless we have a badly built tree */
6108 break;
6109 }
6110 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006111 }
6112}
6113
6114/**
6115 * xmlNodeDump:
6116 * @buf: the XML buffer output
6117 * @doc: the document
6118 * @cur: the current node
6119 * @level: the imbrication level for indenting
6120 * @format: is formatting allowed
6121 *
6122 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006123 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6124 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006125 *
6126 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006127 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006128int
Owen Taylor3473f882001-02-23 17:55:21 +00006129xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006130 int format)
6131{
6132 unsigned int use;
6133 int ret;
6134 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006135
6136 if (cur == NULL) {
6137#ifdef DEBUG_TREE
6138 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006139 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006140#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006141 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006142 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006143 if (buf == NULL) {
6144#ifdef DEBUG_TREE
6145 xmlGenericError(xmlGenericErrorContext,
6146 "xmlNodeDump : buf == NULL\n");
6147#endif
6148 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006149 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006150 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6151 if (outbuf == NULL) {
6152 xmlGenericError(xmlGenericErrorContext,
6153 "xmlNodeDump: out of memory!\n");
6154 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006155 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006156 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6157 outbuf->buffer = buf;
6158 outbuf->encoder = NULL;
6159 outbuf->writecallback = NULL;
6160 outbuf->closecallback = NULL;
6161 outbuf->context = NULL;
6162 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006163
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006164 use = buf->use;
6165 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6166 xmlFree(outbuf);
6167 ret = buf->use - use;
6168 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006169}
6170
6171/**
6172 * xmlElemDump:
6173 * @f: the FILE * for the output
6174 * @doc: the document
6175 * @cur: the current node
6176 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006177 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006178 */
6179void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006180xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6181{
6182 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006183
6184 if (cur == NULL) {
6185#ifdef DEBUG_TREE
6186 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006187 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006188#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006189 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006190 }
Owen Taylor3473f882001-02-23 17:55:21 +00006191#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006192 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006193 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006194 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006195 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006196#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006197
6198 outbuf = xmlOutputBufferCreateFile(f, NULL);
6199 if (outbuf == NULL)
6200 return;
6201 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006202#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006203 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6204#else
6205 xmlGenericError(xmlGenericErrorContext,
6206 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006207#endif /* LIBXML_HTML_ENABLED */
6208 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006209 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6210 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006211}
6212
6213/************************************************************************
6214 * *
6215 * Dumping XML tree content to an I/O output buffer *
6216 * *
6217 ************************************************************************/
6218
Owen Taylor3473f882001-02-23 17:55:21 +00006219static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006220xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6221 int level, int format, const char *encoding);
6222static void
Owen Taylor3473f882001-02-23 17:55:21 +00006223xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6224 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006225static void
6226xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6227 xmlNodePtr cur, int level, int format, const char *encoding);
6228
Owen Taylor3473f882001-02-23 17:55:21 +00006229/**
6230 * xmlNsDumpOutput:
6231 * @buf: the XML buffer output
6232 * @cur: a namespace
6233 *
6234 * Dump a local Namespace definition.
6235 * Should be called in the context of attributes dumps.
6236 */
6237static void
6238xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6239 if (cur == NULL) {
6240#ifdef DEBUG_TREE
6241 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006242 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006243#endif
6244 return;
6245 }
6246 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006247 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6248 return;
6249
Owen Taylor3473f882001-02-23 17:55:21 +00006250 /* Within the context of an element attributes */
6251 if (cur->prefix != NULL) {
6252 xmlOutputBufferWriteString(buf, " xmlns:");
6253 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6254 } else
6255 xmlOutputBufferWriteString(buf, " xmlns");
6256 xmlOutputBufferWriteString(buf, "=");
6257 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6258 }
6259}
6260
6261/**
6262 * xmlNsListDumpOutput:
6263 * @buf: the XML buffer output
6264 * @cur: the first namespace
6265 *
6266 * Dump a list of local Namespace definitions.
6267 * Should be called in the context of attributes dumps.
6268 */
6269static void
6270xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6271 while (cur != NULL) {
6272 xmlNsDumpOutput(buf, cur);
6273 cur = cur->next;
6274 }
6275}
6276
6277/**
6278 * xmlDtdDumpOutput:
6279 * @buf: the XML buffer output
6280 * @doc: the document
6281 * @encoding: an optional encoding string
6282 *
6283 * Dump the XML document DTD, if any.
6284 */
6285static void
6286xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6287 if (dtd == NULL) {
6288#ifdef DEBUG_TREE
6289 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006290 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006291#endif
6292 return;
6293 }
6294 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6295 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6296 if (dtd->ExternalID != NULL) {
6297 xmlOutputBufferWriteString(buf, " PUBLIC ");
6298 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6299 xmlOutputBufferWriteString(buf, " ");
6300 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6301 } else if (dtd->SystemID != NULL) {
6302 xmlOutputBufferWriteString(buf, " SYSTEM ");
6303 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6304 }
6305 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6306 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6307 xmlOutputBufferWriteString(buf, ">");
6308 return;
6309 }
6310 xmlOutputBufferWriteString(buf, " [\n");
6311 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6312 xmlOutputBufferWriteString(buf, "]>");
6313}
6314
6315/**
6316 * xmlAttrDumpOutput:
6317 * @buf: the XML buffer output
6318 * @doc: the document
6319 * @cur: the attribute pointer
6320 * @encoding: an optional encoding string
6321 *
6322 * Dump an XML attribute
6323 */
6324static void
6325xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006326 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006327 if (cur == NULL) {
6328#ifdef DEBUG_TREE
6329 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006330 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006331#endif
6332 return;
6333 }
6334 xmlOutputBufferWriteString(buf, " ");
6335 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6336 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6337 xmlOutputBufferWriteString(buf, ":");
6338 }
6339 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006340 xmlOutputBufferWriteString(buf, "=\"");
6341 xmlAttrSerializeContent(buf->buffer, doc, cur);
6342 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006343}
6344
6345/**
6346 * xmlAttrListDumpOutput:
6347 * @buf: the XML buffer output
6348 * @doc: the document
6349 * @cur: the first attribute pointer
6350 * @encoding: an optional encoding string
6351 *
6352 * Dump a list of XML attributes
6353 */
6354static void
6355xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6356 xmlAttrPtr cur, const char *encoding) {
6357 if (cur == NULL) {
6358#ifdef DEBUG_TREE
6359 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006360 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006361#endif
6362 return;
6363 }
6364 while (cur != NULL) {
6365 xmlAttrDumpOutput(buf, doc, cur, encoding);
6366 cur = cur->next;
6367 }
6368}
6369
6370
6371
6372/**
6373 * xmlNodeListDumpOutput:
6374 * @buf: the XML buffer output
6375 * @doc: the document
6376 * @cur: the first node
6377 * @level: the imbrication level for indenting
6378 * @format: is formatting allowed
6379 * @encoding: an optional encoding string
6380 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006381 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006382 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6383 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006384 */
6385static void
6386xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6387 xmlNodePtr cur, int level, int format, const char *encoding) {
6388 int i;
6389
6390 if (cur == NULL) {
6391#ifdef DEBUG_TREE
6392 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006393 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006394#endif
6395 return;
6396 }
6397 while (cur != NULL) {
6398 if ((format) && (xmlIndentTreeOutput) &&
6399 (cur->type == XML_ELEMENT_NODE))
6400 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006401 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006402 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006403 if (format) {
6404 xmlOutputBufferWriteString(buf, "\n");
6405 }
6406 cur = cur->next;
6407 }
6408}
6409
6410/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006411 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006412 * @buf: the XML buffer output
6413 * @doc: the document
6414 * @cur: the current node
6415 * @level: the imbrication level for indenting
6416 * @format: is formatting allowed
6417 * @encoding: an optional encoding string
6418 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006419 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006420 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6421 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006422 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006423static void
6424xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6425 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006426 int i;
6427 xmlNodePtr tmp;
6428
6429 if (cur == NULL) {
6430#ifdef DEBUG_TREE
6431 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006432 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006433#endif
6434 return;
6435 }
6436 if (cur->type == XML_XINCLUDE_START)
6437 return;
6438 if (cur->type == XML_XINCLUDE_END)
6439 return;
6440 if (cur->type == XML_DTD_NODE) {
6441 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6442 return;
6443 }
6444 if (cur->type == XML_ELEMENT_DECL) {
6445 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6446 return;
6447 }
6448 if (cur->type == XML_ATTRIBUTE_DECL) {
6449 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6450 return;
6451 }
6452 if (cur->type == XML_ENTITY_DECL) {
6453 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6454 return;
6455 }
6456 if (cur->type == XML_TEXT_NODE) {
6457 if (cur->content != NULL) {
6458 if ((cur->name == xmlStringText) ||
6459 (cur->name != xmlStringTextNoenc)) {
6460 xmlChar *buffer;
6461
Owen Taylor3473f882001-02-23 17:55:21 +00006462 if (encoding == NULL)
6463 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6464 else
6465 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006466 if (buffer != NULL) {
6467 xmlOutputBufferWriteString(buf, (const char *)buffer);
6468 xmlFree(buffer);
6469 }
6470 } else {
6471 /*
6472 * Disable escaping, needed for XSLT
6473 */
Owen Taylor3473f882001-02-23 17:55:21 +00006474 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006475 }
6476 }
6477
6478 return;
6479 }
6480 if (cur->type == XML_PI_NODE) {
6481 if (cur->content != NULL) {
6482 xmlOutputBufferWriteString(buf, "<?");
6483 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6484 if (cur->content != NULL) {
6485 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006486 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006487 }
6488 xmlOutputBufferWriteString(buf, "?>");
6489 } else {
6490 xmlOutputBufferWriteString(buf, "<?");
6491 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6492 xmlOutputBufferWriteString(buf, "?>");
6493 }
6494 return;
6495 }
6496 if (cur->type == XML_COMMENT_NODE) {
6497 if (cur->content != NULL) {
6498 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006499 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006500 xmlOutputBufferWriteString(buf, "-->");
6501 }
6502 return;
6503 }
6504 if (cur->type == XML_ENTITY_REF_NODE) {
6505 xmlOutputBufferWriteString(buf, "&");
6506 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6507 xmlOutputBufferWriteString(buf, ";");
6508 return;
6509 }
6510 if (cur->type == XML_CDATA_SECTION_NODE) {
6511 xmlOutputBufferWriteString(buf, "<![CDATA[");
6512 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006513 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006514 xmlOutputBufferWriteString(buf, "]]>");
6515 return;
6516 }
6517
6518 if (format == 1) {
6519 tmp = cur->children;
6520 while (tmp != NULL) {
6521 if ((tmp->type == XML_TEXT_NODE) ||
6522 (tmp->type == XML_ENTITY_REF_NODE)) {
6523 format = 0;
6524 break;
6525 }
6526 tmp = tmp->next;
6527 }
6528 }
6529 xmlOutputBufferWriteString(buf, "<");
6530 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6531 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6532 xmlOutputBufferWriteString(buf, ":");
6533 }
6534
6535 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6536 if (cur->nsDef)
6537 xmlNsListDumpOutput(buf, cur->nsDef);
6538 if (cur->properties != NULL)
6539 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6540
Daniel Veillard7db37732001-07-12 01:20:08 +00006541 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6542 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006543 xmlOutputBufferWriteString(buf, "/>");
6544 return;
6545 }
6546 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006547 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006548 xmlChar *buffer;
6549
Owen Taylor3473f882001-02-23 17:55:21 +00006550 if (encoding == NULL)
6551 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6552 else
6553 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006554 if (buffer != NULL) {
6555 xmlOutputBufferWriteString(buf, (const char *)buffer);
6556 xmlFree(buffer);
6557 }
6558 }
6559 if (cur->children != NULL) {
6560 if (format) xmlOutputBufferWriteString(buf, "\n");
6561 xmlNodeListDumpOutput(buf, doc, cur->children,
6562 (level >= 0?level+1:-1), format, encoding);
6563 if ((xmlIndentTreeOutput) && (format))
6564 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006565 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006566 }
6567 xmlOutputBufferWriteString(buf, "</");
6568 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6569 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6570 xmlOutputBufferWriteString(buf, ":");
6571 }
6572
6573 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6574 xmlOutputBufferWriteString(buf, ">");
6575}
6576
6577/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006578 * xmlNodeDumpOutput:
6579 * @buf: the XML buffer output
6580 * @doc: the document
6581 * @cur: the current node
6582 * @level: the imbrication level for indenting
6583 * @format: is formatting allowed
6584 * @encoding: an optional encoding string
6585 *
6586 * Dump an XML node, recursive behaviour, children are printed too.
6587 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6588 * or xmlKeepBlanksDefault(0) was called
6589 */
6590void
6591xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006592 int level, int format, const char *encoding)
6593{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006594#ifdef LIBXML_HTML_ENABLED
6595 xmlDtdPtr dtd;
6596 int is_xhtml = 0;
6597
6598 dtd = xmlGetIntSubset(doc);
6599 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006600 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6601 if (is_xhtml < 0)
6602 is_xhtml = 0;
6603 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
6604 (cur->type == XML_ELEMENT_NODE) &&
6605 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
6606 if (encoding != NULL)
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00006607 htmlSetMetaEncoding((htmlDocPtr) doc,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006608 (const xmlChar *) encoding);
6609 else
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00006610 htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006611 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006612 }
6613
6614 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006615 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006616 else
6617#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006618 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006619}
6620
6621/**
Owen Taylor3473f882001-02-23 17:55:21 +00006622 * xmlDocContentDumpOutput:
6623 * @buf: the XML buffer output
6624 * @cur: the document
6625 * @encoding: an optional encoding string
6626 * @format: should formatting spaces been added
6627 *
6628 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006629 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6630 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006631 */
6632static void
6633xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6634 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006635#ifdef LIBXML_HTML_ENABLED
6636 xmlDtdPtr dtd;
6637 int is_xhtml = 0;
6638#endif
6639
Owen Taylor3473f882001-02-23 17:55:21 +00006640 xmlOutputBufferWriteString(buf, "<?xml version=");
6641 if (cur->version != NULL)
6642 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6643 else
6644 xmlOutputBufferWriteString(buf, "\"1.0\"");
6645 if (encoding == NULL) {
6646 if (cur->encoding != NULL)
6647 encoding = (const char *) cur->encoding;
6648 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6649 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6650 }
6651 if (encoding != NULL) {
6652 xmlOutputBufferWriteString(buf, " encoding=");
6653 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6654 }
6655 switch (cur->standalone) {
6656 case 0:
6657 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6658 break;
6659 case 1:
6660 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6661 break;
6662 }
6663 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006664
6665#ifdef LIBXML_HTML_ENABLED
6666 dtd = xmlGetIntSubset(cur);
6667 if (dtd != NULL) {
6668 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6669 if (is_xhtml < 0) is_xhtml = 0;
6670 }
6671 if (is_xhtml) {
6672 if (encoding != NULL)
6673 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
6674 else
6675 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
6676 }
6677#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006678 if (cur->children != NULL) {
6679 xmlNodePtr child = cur->children;
6680
6681 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006682#ifdef LIBXML_HTML_ENABLED
6683 if (is_xhtml)
6684 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6685 else
6686#endif
6687 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006688 xmlOutputBufferWriteString(buf, "\n");
6689 child = child->next;
6690 }
6691 }
6692}
6693
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006694#ifdef LIBXML_HTML_ENABLED
6695/************************************************************************
6696 * *
6697 * Functions specific to XHTML serialization *
6698 * *
6699 ************************************************************************/
6700
6701#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
6702 "-//W3C//DTD XHTML 1.0 Strict//EN"
6703#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
6704 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
6705#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
6706 "-//W3C//DTD XHTML 1.0 Frameset//EN"
6707#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
6708 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
6709#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
6710 "-//W3C//DTD XHTML 1.0 Transitional//EN"
6711#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
6712 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
6713
6714#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
6715/**
6716 * xmlIsXHTML:
6717 * @systemID: the system identifier
6718 * @publicID: the public identifier
6719 *
6720 * Try to find if the document correspond to an XHTML DTD
6721 *
6722 * Returns 1 if true, 0 if not and -1 in case of error
6723 */
6724int
6725xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
6726 if ((systemID == NULL) && (publicID == NULL))
6727 return(-1);
6728 if (publicID != NULL) {
6729 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
6730 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
6731 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
6732 }
6733 if (systemID != NULL) {
6734 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
6735 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
6736 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
6737 }
6738 return(0);
6739}
6740
6741/**
6742 * xhtmlIsEmpty:
6743 * @node: the node
6744 *
6745 * Check if a node is an empty xhtml node
6746 *
6747 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
6748 */
6749static int
6750xhtmlIsEmpty(xmlNodePtr node) {
6751 if (node == NULL)
6752 return(-1);
6753 if (node->type != XML_ELEMENT_NODE)
6754 return(0);
6755 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
6756 return(0);
6757 if (node->children != NULL)
6758 return(0);
6759 switch (node->name[0]) {
6760 case 'a':
6761 if (xmlStrEqual(node->name, BAD_CAST "area"))
6762 return(1);
6763 return(0);
6764 case 'b':
6765 if (xmlStrEqual(node->name, BAD_CAST "br"))
6766 return(1);
6767 if (xmlStrEqual(node->name, BAD_CAST "base"))
6768 return(1);
6769 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
6770 return(1);
6771 return(0);
6772 case 'c':
6773 if (xmlStrEqual(node->name, BAD_CAST "col"))
6774 return(1);
6775 return(0);
6776 case 'f':
6777 if (xmlStrEqual(node->name, BAD_CAST "frame"))
6778 return(1);
6779 return(0);
6780 case 'h':
6781 if (xmlStrEqual(node->name, BAD_CAST "hr"))
6782 return(1);
6783 return(0);
6784 case 'i':
6785 if (xmlStrEqual(node->name, BAD_CAST "img"))
6786 return(1);
6787 if (xmlStrEqual(node->name, BAD_CAST "input"))
6788 return(1);
6789 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
6790 return(1);
6791 return(0);
6792 case 'l':
6793 if (xmlStrEqual(node->name, BAD_CAST "link"))
6794 return(1);
6795 return(0);
6796 case 'm':
6797 if (xmlStrEqual(node->name, BAD_CAST "meta"))
6798 return(1);
6799 return(0);
6800 case 'p':
6801 if (xmlStrEqual(node->name, BAD_CAST "param"))
6802 return(1);
6803 return(0);
6804 }
6805 return(0);
6806}
6807
6808/**
6809 * xhtmlAttrListDumpOutput:
6810 * @buf: the XML buffer output
6811 * @doc: the document
6812 * @cur: the first attribute pointer
6813 * @encoding: an optional encoding string
6814 *
6815 * Dump a list of XML attributes
6816 */
6817static void
6818xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6819 xmlAttrPtr cur, const char *encoding) {
6820 xmlAttrPtr xml_lang = NULL;
6821 xmlAttrPtr lang = NULL;
6822 xmlAttrPtr name = NULL;
6823 xmlAttrPtr id = NULL;
6824
6825 if (cur == NULL) {
6826#ifdef DEBUG_TREE
6827 xmlGenericError(xmlGenericErrorContext,
6828 "xmlAttrListDumpOutput : property == NULL\n");
6829#endif
6830 return;
6831 }
6832 while (cur != NULL) {
6833 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
6834 id = cur;
6835 else
6836 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
6837 name = cur;
6838 else
6839 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
6840 lang = cur;
6841 else
6842 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
6843 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
6844 xml_lang = cur;
6845 else if ((cur->ns == NULL) &&
6846 ((cur->children == NULL) ||
6847 (cur->children->content == NULL) ||
6848 (cur->children->content[0] == 0)) &&
6849 (htmlIsBooleanAttr(cur->name))) {
6850 if (cur->children != NULL)
6851 xmlFreeNode(cur->children);
6852 cur->children = xmlNewText(cur->name);
6853 if (cur->children != NULL)
6854 cur->children->parent = (xmlNodePtr) cur;
6855 }
6856 xmlAttrDumpOutput(buf, doc, cur, encoding);
6857 cur = cur->next;
6858 }
6859 /*
6860 * C.8
6861 */
6862 if ((name != NULL) && (id == NULL)) {
6863 xmlOutputBufferWriteString(buf, " id=\"");
6864 xmlAttrSerializeContent(buf->buffer, doc, name);
6865 xmlOutputBufferWriteString(buf, "\"");
6866 }
6867 /*
6868 * C.7.
6869 */
6870 if ((lang != NULL) && (xml_lang == NULL)) {
6871 xmlOutputBufferWriteString(buf, " xml:lang=\"");
6872 xmlAttrSerializeContent(buf->buffer, doc, lang);
6873 xmlOutputBufferWriteString(buf, "\"");
6874 } else
6875 if ((xml_lang != NULL) && (lang == NULL)) {
6876 xmlOutputBufferWriteString(buf, " lang=\"");
6877 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
6878 xmlOutputBufferWriteString(buf, "\"");
6879 }
6880}
6881
6882/**
6883 * xhtmlNodeListDumpOutput:
6884 * @buf: the XML buffer output
6885 * @doc: the XHTML document
6886 * @cur: the first node
6887 * @level: the imbrication level for indenting
6888 * @format: is formatting allowed
6889 * @encoding: an optional encoding string
6890 *
6891 * Dump an XML node list, recursive behaviour, children are printed too.
6892 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6893 * or xmlKeepBlanksDefault(0) was called
6894 */
6895static void
6896xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6897 xmlNodePtr cur, int level, int format, const char *encoding) {
6898 int i;
6899
6900 if (cur == NULL) {
6901#ifdef DEBUG_TREE
6902 xmlGenericError(xmlGenericErrorContext,
6903 "xhtmlNodeListDumpOutput : node == NULL\n");
6904#endif
6905 return;
6906 }
6907 while (cur != NULL) {
6908 if ((format) && (xmlIndentTreeOutput) &&
6909 (cur->type == XML_ELEMENT_NODE))
6910 for (i = 0;i < level;i++)
6911 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
6912 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6913 if (format) {
6914 xmlOutputBufferWriteString(buf, "\n");
6915 }
6916 cur = cur->next;
6917 }
6918}
6919
6920/**
6921 * xhtmlNodeDumpOutput:
6922 * @buf: the XML buffer output
6923 * @doc: the XHTML document
6924 * @cur: the current node
6925 * @level: the imbrication level for indenting
6926 * @format: is formatting allowed
6927 * @encoding: an optional encoding string
6928 *
6929 * Dump an XHTML node, recursive behaviour, children are printed too.
6930 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6931 * or xmlKeepBlanksDefault(0) was called
6932 */
6933static void
6934xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6935 int level, int format, const char *encoding) {
6936 int i;
6937 xmlNodePtr tmp;
6938
6939 if (cur == NULL) {
6940#ifdef DEBUG_TREE
6941 xmlGenericError(xmlGenericErrorContext,
6942 "xmlNodeDumpOutput : node == NULL\n");
6943#endif
6944 return;
6945 }
6946 if (cur->type == XML_XINCLUDE_START)
6947 return;
6948 if (cur->type == XML_XINCLUDE_END)
6949 return;
6950 if (cur->type == XML_DTD_NODE) {
6951 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6952 return;
6953 }
6954 if (cur->type == XML_ELEMENT_DECL) {
6955 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6956 return;
6957 }
6958 if (cur->type == XML_ATTRIBUTE_DECL) {
6959 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6960 return;
6961 }
6962 if (cur->type == XML_ENTITY_DECL) {
6963 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6964 return;
6965 }
6966 if (cur->type == XML_TEXT_NODE) {
6967 if (cur->content != NULL) {
6968 if ((cur->name == xmlStringText) ||
6969 (cur->name != xmlStringTextNoenc)) {
6970 xmlChar *buffer;
6971
6972 if (encoding == NULL)
6973 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6974 else
6975 buffer = xmlEncodeSpecialChars(doc, cur->content);
6976 if (buffer != NULL) {
6977 xmlOutputBufferWriteString(buf, (const char *)buffer);
6978 xmlFree(buffer);
6979 }
6980 } else {
6981 /*
6982 * Disable escaping, needed for XSLT
6983 */
6984 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6985 }
6986 }
6987
6988 return;
6989 }
6990 if (cur->type == XML_PI_NODE) {
6991 if (cur->content != NULL) {
6992 xmlOutputBufferWriteString(buf, "<?");
6993 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6994 if (cur->content != NULL) {
6995 xmlOutputBufferWriteString(buf, " ");
6996 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6997 }
6998 xmlOutputBufferWriteString(buf, "?>");
6999 } else {
7000 xmlOutputBufferWriteString(buf, "<?");
7001 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7002 xmlOutputBufferWriteString(buf, "?>");
7003 }
7004 return;
7005 }
7006 if (cur->type == XML_COMMENT_NODE) {
7007 if (cur->content != NULL) {
7008 xmlOutputBufferWriteString(buf, "<!--");
7009 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7010 xmlOutputBufferWriteString(buf, "-->");
7011 }
7012 return;
7013 }
7014 if (cur->type == XML_ENTITY_REF_NODE) {
7015 xmlOutputBufferWriteString(buf, "&");
7016 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7017 xmlOutputBufferWriteString(buf, ";");
7018 return;
7019 }
7020 if (cur->type == XML_CDATA_SECTION_NODE) {
7021 xmlOutputBufferWriteString(buf, "<![CDATA[");
7022 if (cur->content != NULL)
7023 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7024 xmlOutputBufferWriteString(buf, "]]>");
7025 return;
7026 }
7027
7028 if (format == 1) {
7029 tmp = cur->children;
7030 while (tmp != NULL) {
7031 if ((tmp->type == XML_TEXT_NODE) ||
7032 (tmp->type == XML_ENTITY_REF_NODE)) {
7033 format = 0;
7034 break;
7035 }
7036 tmp = tmp->next;
7037 }
7038 }
7039 xmlOutputBufferWriteString(buf, "<");
7040 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7041 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7042 xmlOutputBufferWriteString(buf, ":");
7043 }
7044
7045 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7046 if (cur->nsDef)
7047 xmlNsListDumpOutput(buf, cur->nsDef);
7048 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7049 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7050 /*
7051 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7052 */
7053 xmlOutputBufferWriteString(buf,
7054 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7055 }
7056 if (cur->properties != NULL)
7057 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7058
7059 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7060 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7061 (xhtmlIsEmpty(cur) == 1)) {
7062 /*
7063 * C.2. Empty Elements
7064 */
7065 xmlOutputBufferWriteString(buf, " />");
7066 } else {
7067 /*
7068 * C.3. Element Minimization and Empty Element Content
7069 */
7070 xmlOutputBufferWriteString(buf, "></");
7071 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7072 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7073 xmlOutputBufferWriteString(buf, ":");
7074 }
7075 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7076 xmlOutputBufferWriteString(buf, ">");
7077 }
7078 return;
7079 }
7080 xmlOutputBufferWriteString(buf, ">");
7081 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7082 xmlChar *buffer;
7083
7084 if (encoding == NULL)
7085 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7086 else
7087 buffer = xmlEncodeSpecialChars(doc, cur->content);
7088 if (buffer != NULL) {
7089 xmlOutputBufferWriteString(buf, (const char *)buffer);
7090 xmlFree(buffer);
7091 }
7092 }
7093
7094 /*
7095 * 4.8. Script and Style elements
7096 */
7097 if ((cur->type == XML_ELEMENT_NODE) &&
7098 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7099 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7100 ((cur->ns == NULL) ||
7101 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7102 xmlNodePtr child = cur->children;
7103
7104 while (child != NULL) {
7105 if ((child->type == XML_TEXT_NODE) ||
7106 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007107 /*
7108 * Apparently CDATA escaping for style just break on IE,
7109 * mozilla and galeon, so ...
7110 */
7111 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7112 (xmlStrchr(child->content, '<') == NULL) &&
7113 (xmlStrchr(child->content, '>') == NULL) &&
7114 (xmlStrchr(child->content, '&') == NULL)) {
7115 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7116 } else {
7117 xmlOutputBufferWriteString(buf, "<![CDATA[");
7118 if (child->content != NULL)
7119 xmlOutputBufferWriteString(buf,
7120 (const char *)child->content);
7121 xmlOutputBufferWriteString(buf, "]]>");
7122 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007123 } else {
7124 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7125 }
7126 child = child->next;
7127 }
7128 } else if (cur->children != NULL) {
7129 if (format) xmlOutputBufferWriteString(buf, "\n");
7130 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7131 (level >= 0?level+1:-1), format, encoding);
7132 if ((xmlIndentTreeOutput) && (format))
7133 for (i = 0;i < level;i++)
7134 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7135 }
7136 xmlOutputBufferWriteString(buf, "</");
7137 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7138 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7139 xmlOutputBufferWriteString(buf, ":");
7140 }
7141
7142 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7143 xmlOutputBufferWriteString(buf, ">");
7144}
7145#endif
7146
Owen Taylor3473f882001-02-23 17:55:21 +00007147/************************************************************************
7148 * *
7149 * Saving functions front-ends *
7150 * *
7151 ************************************************************************/
7152
7153/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007154 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007155 * @out_doc: Document to generate XML text from
7156 * @doc_txt_ptr: Memory pointer for allocated XML text
7157 * @doc_txt_len: Length of the generated XML text
7158 * @txt_encoding: Character encoding to use when generating XML text
7159 * @format: should formatting spaces been added
7160 *
7161 * Dump the current DOM tree into memory using the character encoding specified
7162 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007163 * allocated memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007164 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7165 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007166 */
7167
7168void
7169xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007170 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007171 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007172 int dummy = 0;
7173
7174 xmlCharEncoding doc_charset;
7175 xmlOutputBufferPtr out_buff = NULL;
7176 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7177
7178 if (doc_txt_len == NULL) {
7179 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7180 }
7181
7182 if (doc_txt_ptr == NULL) {
7183 *doc_txt_len = 0;
7184 xmlGenericError(xmlGenericErrorContext,
7185 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7186 return;
7187 }
7188
7189 *doc_txt_ptr = NULL;
7190 *doc_txt_len = 0;
7191
7192 if (out_doc == NULL) {
7193 /* No document, no output */
7194 xmlGenericError(xmlGenericErrorContext,
7195 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7196 return;
7197 }
7198
7199 /*
7200 * Validate the encoding value, if provided.
7201 * This logic is copied from xmlSaveFileEnc.
7202 */
7203
7204 if (txt_encoding == NULL)
7205 txt_encoding = (const char *) out_doc->encoding;
7206 if (txt_encoding != NULL) {
7207 doc_charset = xmlParseCharEncoding(txt_encoding);
7208
7209 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7210 xmlGenericError(xmlGenericErrorContext,
7211 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7212 return;
7213
7214 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7215 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7216 if ( conv_hdlr == NULL ) {
7217 xmlGenericError(xmlGenericErrorContext,
7218 "%s: %s %s '%s'\n",
7219 "xmlDocDumpFormatMemoryEnc",
7220 "Failed to identify encoding handler for",
7221 "character set",
7222 txt_encoding);
7223 return;
7224 }
7225 }
7226 }
7227
7228 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7229 xmlGenericError(xmlGenericErrorContext,
7230 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7231 return;
7232 }
7233
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007234 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007235 xmlOutputBufferFlush(out_buff);
7236 if (out_buff->conv != NULL) {
7237 *doc_txt_len = out_buff->conv->use;
7238 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7239 } else {
7240 *doc_txt_len = out_buff->buffer->use;
7241 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7242 }
7243 (void)xmlOutputBufferClose(out_buff);
7244
7245 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7246 *doc_txt_len = 0;
7247 xmlGenericError(xmlGenericErrorContext,
7248 "xmlDocDumpFormatMemoryEnc: %s\n",
7249 "Failed to allocate memory for document text representation.");
7250 }
7251
7252 return;
7253}
7254
7255/**
7256 * xmlDocDumpMemory:
7257 * @cur: the document
7258 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007259 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007260 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007261 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007262 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007263 */
7264void
7265xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7266 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7267}
7268
7269/**
7270 * xmlDocDumpFormatMemory:
7271 * @cur: the document
7272 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007273 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007274 * @format: should formatting spaces been added
7275 *
7276 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007277 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007278 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007279 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7280 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007281 */
7282void
7283xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7284 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7285}
7286
7287/**
7288 * xmlDocDumpMemoryEnc:
7289 * @out_doc: Document to generate XML text from
7290 * @doc_txt_ptr: Memory pointer for allocated XML text
7291 * @doc_txt_len: Length of the generated XML text
7292 * @txt_encoding: Character encoding to use when generating XML text
7293 *
7294 * Dump the current DOM tree into memory using the character encoding specified
7295 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007296 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007297 */
7298
7299void
7300xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7301 int * doc_txt_len, const char * txt_encoding) {
7302 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007303 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007304}
7305
7306/**
7307 * xmlGetDocCompressMode:
7308 * @doc: the document
7309 *
7310 * get the compression ratio for a document, ZLIB based
7311 * Returns 0 (uncompressed) to 9 (max compression)
7312 */
7313int
7314xmlGetDocCompressMode (xmlDocPtr doc) {
7315 if (doc == NULL) return(-1);
7316 return(doc->compression);
7317}
7318
7319/**
7320 * xmlSetDocCompressMode:
7321 * @doc: the document
7322 * @mode: the compression ratio
7323 *
7324 * set the compression ratio for a document, ZLIB based
7325 * Correct values: 0 (uncompressed) to 9 (max compression)
7326 */
7327void
7328xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7329 if (doc == NULL) return;
7330 if (mode < 0) doc->compression = 0;
7331 else if (mode > 9) doc->compression = 9;
7332 else doc->compression = mode;
7333}
7334
7335/**
7336 * xmlGetCompressMode:
7337 *
7338 * get the default compression mode used, ZLIB based.
7339 * Returns 0 (uncompressed) to 9 (max compression)
7340 */
7341int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007342xmlGetCompressMode(void)
7343{
7344 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007345}
7346
7347/**
7348 * xmlSetCompressMode:
7349 * @mode: the compression ratio
7350 *
7351 * set the default compression mode used, ZLIB based
7352 * Correct values: 0 (uncompressed) to 9 (max compression)
7353 */
7354void
7355xmlSetCompressMode(int mode) {
7356 if (mode < 0) xmlCompressMode = 0;
7357 else if (mode > 9) xmlCompressMode = 9;
7358 else xmlCompressMode = mode;
7359}
7360
7361/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007362 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007363 * @f: the FILE*
7364 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007365 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007366 *
7367 * Dump an XML document to an open FILE.
7368 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007369 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007370 */
7371int
Daniel Veillard9e412302002-06-10 15:59:44 +00007372xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007373 xmlOutputBufferPtr buf;
7374 const char * encoding;
7375 xmlCharEncodingHandlerPtr handler = NULL;
7376 int ret;
7377
7378 if (cur == NULL) {
7379#ifdef DEBUG_TREE
7380 xmlGenericError(xmlGenericErrorContext,
7381 "xmlDocDump : document == NULL\n");
7382#endif
7383 return(-1);
7384 }
7385 encoding = (const char *) cur->encoding;
7386
7387 if (encoding != NULL) {
7388 xmlCharEncoding enc;
7389
7390 enc = xmlParseCharEncoding(encoding);
7391
7392 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7393 xmlGenericError(xmlGenericErrorContext,
7394 "xmlDocDump: document not in UTF8\n");
7395 return(-1);
7396 }
7397 if (enc != XML_CHAR_ENCODING_UTF8) {
7398 handler = xmlFindCharEncodingHandler(encoding);
7399 if (handler == NULL) {
7400 xmlFree((char *) cur->encoding);
7401 cur->encoding = NULL;
7402 }
7403 }
7404 }
7405 buf = xmlOutputBufferCreateFile(f, handler);
7406 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007407 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007408
7409 ret = xmlOutputBufferClose(buf);
7410 return(ret);
7411}
7412
7413/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007414 * xmlDocDump:
7415 * @f: the FILE*
7416 * @cur: the document
7417 *
7418 * Dump an XML document to an open FILE.
7419 *
7420 * returns: the number of bytes written or -1 in case of failure.
7421 */
7422int
7423xmlDocDump(FILE *f, xmlDocPtr cur) {
7424 return(xmlDocFormatDump (f, cur, 0));
7425}
7426
7427/**
Owen Taylor3473f882001-02-23 17:55:21 +00007428 * xmlSaveFileTo:
7429 * @buf: an output I/O buffer
7430 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007431 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007432 *
7433 * Dump an XML document to an I/O buffer.
7434 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007435 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007436 */
7437int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007438xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007439 int ret;
7440
7441 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007442 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007443 ret = xmlOutputBufferClose(buf);
7444 return(ret);
7445}
7446
7447/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007448 * xmlSaveFormatFileTo:
7449 * @buf: an output I/O buffer
7450 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007451 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007452 * @format: should formatting spaces been added
7453 *
7454 * Dump an XML document to an I/O buffer.
7455 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007456 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007457 */
7458int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007459xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007460 int ret;
7461
7462 if (buf == NULL) return(0);
7463 xmlDocContentDumpOutput(buf, cur, encoding, format);
7464 ret = xmlOutputBufferClose(buf);
7465 return(ret);
7466}
7467
7468/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00007469 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00007470 * @filename: the filename or URL to output
7471 * @cur: the document being saved
7472 * @encoding: the name of the encoding to use or NULL.
7473 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007474 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00007475 * Dump an XML document to a file or an URL.
7476 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007477 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007478 */
7479int
Daniel Veillardf012a642001-07-23 19:10:52 +00007480xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7481 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007482 xmlOutputBufferPtr buf;
7483 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007484 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007485 int ret;
7486
Daniel Veillardfb25a512002-01-13 20:32:08 +00007487 if (encoding == NULL)
7488 encoding = (const char *) cur->encoding;
7489
Owen Taylor3473f882001-02-23 17:55:21 +00007490 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007491
7492 enc = xmlParseCharEncoding(encoding);
7493 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7494 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007495 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007496 return(-1);
7497 }
7498 if (enc != XML_CHAR_ENCODING_UTF8) {
7499 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007500 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007501 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007502 }
7503 }
7504
Daniel Veillardf012a642001-07-23 19:10:52 +00007505#ifdef HAVE_ZLIB_H
7506 if (cur->compression < 0) cur->compression = xmlCompressMode;
7507#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007508 /*
7509 * save the content to a temp buffer.
7510 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007511 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007512 if (buf == NULL) return(-1);
7513
Daniel Veillardf012a642001-07-23 19:10:52 +00007514 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007515
7516 ret = xmlOutputBufferClose(buf);
7517 return(ret);
7518}
7519
Daniel Veillardf012a642001-07-23 19:10:52 +00007520
7521/**
7522 * xmlSaveFileEnc:
7523 * @filename: the filename (or URL)
7524 * @cur: the document
7525 * @encoding: the name of an encoding (or NULL)
7526 *
7527 * Dump an XML document, converting it to the given encoding
7528 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007529 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007530 */
7531int
7532xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7533 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7534}
7535
Owen Taylor3473f882001-02-23 17:55:21 +00007536/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007537 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007538 * @filename: the filename (or URL)
7539 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007540 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007541 *
7542 * Dump an XML document to a file. Will use compression if
7543 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007544 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007545 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007546 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007547 */
7548int
Daniel Veillard67fee942001-04-26 18:59:03 +00007549xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007550 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007551}
7552
Daniel Veillard67fee942001-04-26 18:59:03 +00007553/**
7554 * xmlSaveFile:
7555 * @filename: the filename (or URL)
7556 * @cur: the document
7557 *
7558 * Dump an XML document to a file. Will use compression if
7559 * compiled in and enabled. If @filename is "-" the stdout file is
7560 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007561 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007562 */
7563int
7564xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007565 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007566}
7567