blob: 60ae931127ef523ac3554ea5cc555dc948aaaaeb [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);
840 temp = ent->children;
841 while (temp) {
842 temp->parent = (xmlNodePtr)ent;
843 temp = temp->next;
844 }
845 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000846 if (last == NULL) {
847 last = ret = node;
848 } else {
849 last = xmlAddNextSibling(last, node);
850 }
851 }
852 xmlFree(val);
853 }
854 cur++;
855 q = cur;
856 }
857 if (charval != 0) {
858 xmlChar buf[10];
859 int len;
860
861 len = xmlCopyCharMultiByte(buf, charval);
862 buf[len] = 0;
863 node = xmlNewDocText(doc, buf);
864 if (node != NULL) {
865 if (last == NULL) {
866 last = ret = node;
867 } else {
868 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000869 }
870 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000871
872 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000873 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000874 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000875 cur++;
876 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000877 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000878 /*
879 * Handle the last piece of text.
880 */
881 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
882 xmlNodeAddContentLen(last, q, cur - q);
883 } else {
884 node = xmlNewDocTextLen(doc, q, cur - q);
885 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000886 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000887 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000888 } else {
889 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000890 }
891 }
892 }
893 return(ret);
894}
895
896/**
897 * xmlNodeListGetString:
898 * @doc: the document
899 * @list: a Node list
900 * @inLine: should we replace entity contents or show their external form
901 *
902 * Returns the string equivalent to the text contained in the Node list
903 * made of TEXTs and ENTITY_REFs
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000904 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000905 */
906xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000907xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
908{
Owen Taylor3473f882001-02-23 17:55:21 +0000909 xmlNodePtr node = list;
910 xmlChar *ret = NULL;
911 xmlEntityPtr ent;
912
Daniel Veillard7646b182002-04-20 06:41:40 +0000913 if (list == NULL)
914 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000915
916 while (node != NULL) {
917 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000918 (node->type == XML_CDATA_SECTION_NODE)) {
919 if (inLine) {
920 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000921 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000922 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000923
Daniel Veillard7646b182002-04-20 06:41:40 +0000924 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
925 if (buffer != NULL) {
926 ret = xmlStrcat(ret, buffer);
927 xmlFree(buffer);
928 }
929 }
930 } else if (node->type == XML_ENTITY_REF_NODE) {
931 if (inLine) {
932 ent = xmlGetDocEntity(doc, node->name);
933 if (ent != NULL) {
934 xmlChar *buffer;
935
936 /* an entity content can be any "well balanced chunk",
937 * i.e. the result of the content [43] production:
938 * http://www.w3.org/TR/REC-xml#NT-content.
939 * So it can contain text, CDATA section or nested
940 * entity reference nodes (among others).
941 * -> we recursive call xmlNodeListGetString()
942 * which handles these types */
943 buffer = xmlNodeListGetString(doc, ent->children, 1);
944 if (buffer != NULL) {
945 ret = xmlStrcat(ret, buffer);
946 xmlFree(buffer);
947 }
948 } else {
949 ret = xmlStrcat(ret, node->content);
950 }
951 } else {
952 xmlChar buf[2];
953
954 buf[0] = '&';
955 buf[1] = 0;
956 ret = xmlStrncat(ret, buf, 1);
957 ret = xmlStrcat(ret, node->name);
958 buf[0] = ';';
959 buf[1] = 0;
960 ret = xmlStrncat(ret, buf, 1);
961 }
962 }
963#if 0
964 else {
965 xmlGenericError(xmlGenericErrorContext,
966 "xmlGetNodeListString : invalid node type %d\n",
967 node->type);
968 }
969#endif
970 node = node->next;
971 }
972 return (ret);
973}
Owen Taylor3473f882001-02-23 17:55:21 +0000974/**
975 * xmlNodeListGetRawString:
976 * @doc: the document
977 * @list: a Node list
978 * @inLine: should we replace entity contents or show their external form
979 *
980 * Returns the string equivalent to the text contained in the Node list
981 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
982 * this function doesn't do any character encoding handling.
983 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000984 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000985 */
986xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000987xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
988{
Owen Taylor3473f882001-02-23 17:55:21 +0000989 xmlNodePtr node = list;
990 xmlChar *ret = NULL;
991 xmlEntityPtr ent;
992
Daniel Veillard7646b182002-04-20 06:41:40 +0000993 if (list == NULL)
994 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000995
996 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000997 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000998 (node->type == XML_CDATA_SECTION_NODE)) {
999 if (inLine) {
1000 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001001 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001002 xmlChar *buffer;
1003
1004 buffer = xmlEncodeSpecialChars(doc, node->content);
1005 if (buffer != NULL) {
1006 ret = xmlStrcat(ret, buffer);
1007 xmlFree(buffer);
1008 }
1009 }
1010 } else if (node->type == XML_ENTITY_REF_NODE) {
1011 if (inLine) {
1012 ent = xmlGetDocEntity(doc, node->name);
1013 if (ent != NULL) {
1014 xmlChar *buffer;
1015
1016 /* an entity content can be any "well balanced chunk",
1017 * i.e. the result of the content [43] production:
1018 * http://www.w3.org/TR/REC-xml#NT-content.
1019 * So it can contain text, CDATA section or nested
1020 * entity reference nodes (among others).
1021 * -> we recursive call xmlNodeListGetRawString()
1022 * which handles these types */
1023 buffer =
1024 xmlNodeListGetRawString(doc, ent->children, 1);
1025 if (buffer != NULL) {
1026 ret = xmlStrcat(ret, buffer);
1027 xmlFree(buffer);
1028 }
1029 } else {
1030 ret = xmlStrcat(ret, node->content);
1031 }
1032 } else {
1033 xmlChar buf[2];
1034
1035 buf[0] = '&';
1036 buf[1] = 0;
1037 ret = xmlStrncat(ret, buf, 1);
1038 ret = xmlStrcat(ret, node->name);
1039 buf[0] = ';';
1040 buf[1] = 0;
1041 ret = xmlStrncat(ret, buf, 1);
1042 }
1043 }
Owen Taylor3473f882001-02-23 17:55:21 +00001044#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001045 else {
1046 xmlGenericError(xmlGenericErrorContext,
1047 "xmlGetNodeListString : invalid node type %d\n",
1048 node->type);
1049 }
Owen Taylor3473f882001-02-23 17:55:21 +00001050#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001051 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001052 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001053 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001054}
1055
1056/**
1057 * xmlNewProp:
1058 * @node: the holding node
1059 * @name: the name of the attribute
1060 * @value: the value of the attribute
1061 *
1062 * Create a new property carried by a node.
1063 * Returns a pointer to the attribute
1064 */
1065xmlAttrPtr
1066xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1067 xmlAttrPtr cur;
1068 xmlDocPtr doc = NULL;
1069
1070 if (name == NULL) {
1071#ifdef DEBUG_TREE
1072 xmlGenericError(xmlGenericErrorContext,
1073 "xmlNewProp : name == NULL\n");
1074#endif
1075 return(NULL);
1076 }
1077
1078 /*
1079 * Allocate a new property and fill the fields.
1080 */
1081 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1082 if (cur == NULL) {
1083 xmlGenericError(xmlGenericErrorContext,
1084 "xmlNewProp : malloc failed\n");
1085 return(NULL);
1086 }
1087 memset(cur, 0, sizeof(xmlAttr));
1088 cur->type = XML_ATTRIBUTE_NODE;
1089
1090 cur->parent = node;
1091 if (node != NULL) {
1092 doc = node->doc;
1093 cur->doc = doc;
1094 }
1095 cur->name = xmlStrdup(name);
1096 if (value != NULL) {
1097 xmlChar *buffer;
1098 xmlNodePtr tmp;
1099
1100 buffer = xmlEncodeEntitiesReentrant(doc, value);
1101 cur->children = xmlStringGetNodeList(doc, buffer);
1102 cur->last = NULL;
1103 tmp = cur->children;
1104 while (tmp != NULL) {
1105 tmp->parent = (xmlNodePtr) cur;
1106 tmp->doc = doc;
1107 if (tmp->next == NULL)
1108 cur->last = tmp;
1109 tmp = tmp->next;
1110 }
1111 xmlFree(buffer);
1112 }
1113
1114 /*
1115 * Add it at the end to preserve parsing order ...
1116 */
1117 if (node != NULL) {
1118 if (node->properties == NULL) {
1119 node->properties = cur;
1120 } else {
1121 xmlAttrPtr prev = node->properties;
1122
1123 while (prev->next != NULL) prev = prev->next;
1124 prev->next = cur;
1125 cur->prev = prev;
1126 }
1127 }
1128 return(cur);
1129}
1130
1131/**
1132 * xmlNewNsProp:
1133 * @node: the holding node
1134 * @ns: the namespace
1135 * @name: the name of the attribute
1136 * @value: the value of the attribute
1137 *
1138 * Create a new property tagged with a namespace and carried by a node.
1139 * Returns a pointer to the attribute
1140 */
1141xmlAttrPtr
1142xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1143 const xmlChar *value) {
1144 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001145 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001146
1147 if (name == NULL) {
1148#ifdef DEBUG_TREE
1149 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001150 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001151#endif
1152 return(NULL);
1153 }
1154
1155 /*
1156 * Allocate a new property and fill the fields.
1157 */
1158 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1159 if (cur == NULL) {
1160 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001161 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001162 return(NULL);
1163 }
1164 memset(cur, 0, sizeof(xmlAttr));
1165 cur->type = XML_ATTRIBUTE_NODE;
1166
1167 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001168 if (node != NULL) {
1169 doc = node->doc;
1170 cur->doc = doc;
1171 }
Owen Taylor3473f882001-02-23 17:55:21 +00001172 cur->ns = ns;
1173 cur->name = xmlStrdup(name);
1174 if (value != NULL) {
1175 xmlChar *buffer;
1176 xmlNodePtr tmp;
1177
Daniel Veillarda682b212001-06-07 19:59:42 +00001178 buffer = xmlEncodeEntitiesReentrant(doc, value);
1179 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001180 cur->last = NULL;
1181 tmp = cur->children;
1182 while (tmp != NULL) {
1183 tmp->parent = (xmlNodePtr) cur;
1184 if (tmp->next == NULL)
1185 cur->last = tmp;
1186 tmp = tmp->next;
1187 }
1188 xmlFree(buffer);
1189 }
1190
1191 /*
1192 * Add it at the end to preserve parsing order ...
1193 */
1194 if (node != NULL) {
1195 if (node->properties == NULL) {
1196 node->properties = cur;
1197 } else {
1198 xmlAttrPtr prev = node->properties;
1199
1200 while (prev->next != NULL) prev = prev->next;
1201 prev->next = cur;
1202 cur->prev = prev;
1203 }
1204 }
1205 return(cur);
1206}
1207
1208/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001209 * xmlNewNsPropEatName:
1210 * @node: the holding node
1211 * @ns: the namespace
1212 * @name: the name of the attribute
1213 * @value: the value of the attribute
1214 *
1215 * Create a new property tagged with a namespace and carried by a node.
1216 * Returns a pointer to the attribute
1217 */
1218xmlAttrPtr
1219xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1220 const xmlChar *value) {
1221 xmlAttrPtr cur;
1222 xmlDocPtr doc = NULL;
1223
1224 if (name == NULL) {
1225#ifdef DEBUG_TREE
1226 xmlGenericError(xmlGenericErrorContext,
1227 "xmlNewNsPropEatName : name == NULL\n");
1228#endif
1229 return(NULL);
1230 }
1231
1232 /*
1233 * Allocate a new property and fill the fields.
1234 */
1235 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1236 if (cur == NULL) {
1237 xmlGenericError(xmlGenericErrorContext,
1238 "xmlNewNsPropEatName : malloc failed\n");
1239 return(NULL);
1240 }
1241 memset(cur, 0, sizeof(xmlAttr));
1242 cur->type = XML_ATTRIBUTE_NODE;
1243
1244 cur->parent = node;
1245 if (node != NULL) {
1246 doc = node->doc;
1247 cur->doc = doc;
1248 }
1249 cur->ns = ns;
1250 cur->name = name;
1251 if (value != NULL) {
1252 xmlChar *buffer;
1253 xmlNodePtr tmp;
1254
1255 buffer = xmlEncodeEntitiesReentrant(doc, value);
1256 cur->children = xmlStringGetNodeList(doc, buffer);
1257 cur->last = NULL;
1258 tmp = cur->children;
1259 while (tmp != NULL) {
1260 tmp->parent = (xmlNodePtr) cur;
1261 if (tmp->next == NULL)
1262 cur->last = tmp;
1263 tmp = tmp->next;
1264 }
1265 xmlFree(buffer);
1266 }
1267
1268 /*
1269 * Add it at the end to preserve parsing order ...
1270 */
1271 if (node != NULL) {
1272 if (node->properties == NULL) {
1273 node->properties = cur;
1274 } else {
1275 xmlAttrPtr prev = node->properties;
1276
1277 while (prev->next != NULL) prev = prev->next;
1278 prev->next = cur;
1279 cur->prev = prev;
1280 }
1281 }
1282 return(cur);
1283}
1284
1285/**
Owen Taylor3473f882001-02-23 17:55:21 +00001286 * xmlNewDocProp:
1287 * @doc: the document
1288 * @name: the name of the attribute
1289 * @value: the value of the attribute
1290 *
1291 * Create a new property carried by a document.
1292 * Returns a pointer to the attribute
1293 */
1294xmlAttrPtr
1295xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1296 xmlAttrPtr cur;
1297
1298 if (name == NULL) {
1299#ifdef DEBUG_TREE
1300 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001301 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001302#endif
1303 return(NULL);
1304 }
1305
1306 /*
1307 * Allocate a new property and fill the fields.
1308 */
1309 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1310 if (cur == NULL) {
1311 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001312 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001313 return(NULL);
1314 }
1315 memset(cur, 0, sizeof(xmlAttr));
1316 cur->type = XML_ATTRIBUTE_NODE;
1317
1318 cur->name = xmlStrdup(name);
1319 cur->doc = doc;
1320 if (value != NULL) {
1321 xmlNodePtr tmp;
1322
1323 cur->children = xmlStringGetNodeList(doc, value);
1324 cur->last = NULL;
1325
1326 tmp = cur->children;
1327 while (tmp != NULL) {
1328 tmp->parent = (xmlNodePtr) cur;
1329 if (tmp->next == NULL)
1330 cur->last = tmp;
1331 tmp = tmp->next;
1332 }
1333 }
1334 return(cur);
1335}
1336
1337/**
1338 * xmlFreePropList:
1339 * @cur: the first property in the list
1340 *
1341 * Free a property and all its siblings, all the children are freed too.
1342 */
1343void
1344xmlFreePropList(xmlAttrPtr cur) {
1345 xmlAttrPtr next;
1346 if (cur == NULL) {
1347#ifdef DEBUG_TREE
1348 xmlGenericError(xmlGenericErrorContext,
1349 "xmlFreePropList : property == NULL\n");
1350#endif
1351 return;
1352 }
1353 while (cur != NULL) {
1354 next = cur->next;
1355 xmlFreeProp(cur);
1356 cur = next;
1357 }
1358}
1359
1360/**
1361 * xmlFreeProp:
1362 * @cur: an attribute
1363 *
1364 * Free one attribute, all the content is freed too
1365 */
1366void
1367xmlFreeProp(xmlAttrPtr cur) {
1368 if (cur == NULL) {
1369#ifdef DEBUG_TREE
1370 xmlGenericError(xmlGenericErrorContext,
1371 "xmlFreeProp : property == NULL\n");
1372#endif
1373 return;
1374 }
1375 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001376 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1377 ((cur->parent->doc->intSubset != NULL) ||
1378 (cur->parent->doc->extSubset != NULL))) {
1379 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1380 xmlRemoveID(cur->parent->doc, cur);
1381 }
Owen Taylor3473f882001-02-23 17:55:21 +00001382 if (cur->name != NULL) xmlFree((char *) cur->name);
1383 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001384 xmlFree(cur);
1385}
1386
1387/**
1388 * xmlRemoveProp:
1389 * @cur: an attribute
1390 *
1391 * Unlink and free one attribute, all the content is freed too
1392 * Note this doesn't work for namespace definition attributes
1393 *
1394 * Returns 0 if success and -1 in case of error.
1395 */
1396int
1397xmlRemoveProp(xmlAttrPtr cur) {
1398 xmlAttrPtr tmp;
1399 if (cur == NULL) {
1400#ifdef DEBUG_TREE
1401 xmlGenericError(xmlGenericErrorContext,
1402 "xmlRemoveProp : cur == NULL\n");
1403#endif
1404 return(-1);
1405 }
1406 if (cur->parent == NULL) {
1407#ifdef DEBUG_TREE
1408 xmlGenericError(xmlGenericErrorContext,
1409 "xmlRemoveProp : cur->parent == NULL\n");
1410#endif
1411 return(-1);
1412 }
1413 tmp = cur->parent->properties;
1414 if (tmp == cur) {
1415 cur->parent->properties = cur->next;
1416 xmlFreeProp(cur);
1417 return(0);
1418 }
1419 while (tmp != NULL) {
1420 if (tmp->next == cur) {
1421 tmp->next = cur->next;
1422 if (tmp->next != NULL)
1423 tmp->next->prev = tmp;
1424 xmlFreeProp(cur);
1425 return(0);
1426 }
1427 tmp = tmp->next;
1428 }
1429#ifdef DEBUG_TREE
1430 xmlGenericError(xmlGenericErrorContext,
1431 "xmlRemoveProp : attribute not owned by its node\n");
1432#endif
1433 return(-1);
1434}
1435
1436/**
1437 * xmlNewPI:
1438 * @name: the processing instruction name
1439 * @content: the PI content
1440 *
1441 * Creation of a processing instruction element.
1442 * Returns a pointer to the new node object.
1443 */
1444xmlNodePtr
1445xmlNewPI(const xmlChar *name, const xmlChar *content) {
1446 xmlNodePtr cur;
1447
1448 if (name == NULL) {
1449#ifdef DEBUG_TREE
1450 xmlGenericError(xmlGenericErrorContext,
1451 "xmlNewPI : name == NULL\n");
1452#endif
1453 return(NULL);
1454 }
1455
1456 /*
1457 * Allocate a new node and fill the fields.
1458 */
1459 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1460 if (cur == NULL) {
1461 xmlGenericError(xmlGenericErrorContext,
1462 "xmlNewPI : malloc failed\n");
1463 return(NULL);
1464 }
1465 memset(cur, 0, sizeof(xmlNode));
1466 cur->type = XML_PI_NODE;
1467
1468 cur->name = xmlStrdup(name);
1469 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001470 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001471 }
1472 return(cur);
1473}
1474
1475/**
1476 * xmlNewNode:
1477 * @ns: namespace if any
1478 * @name: the node name
1479 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001480 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001481 *
1482 * Returns a pointer to the new node object.
1483 */
1484xmlNodePtr
1485xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1486 xmlNodePtr cur;
1487
1488 if (name == NULL) {
1489#ifdef DEBUG_TREE
1490 xmlGenericError(xmlGenericErrorContext,
1491 "xmlNewNode : name == NULL\n");
1492#endif
1493 return(NULL);
1494 }
1495
1496 /*
1497 * Allocate a new node and fill the fields.
1498 */
1499 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1500 if (cur == NULL) {
1501 xmlGenericError(xmlGenericErrorContext,
1502 "xmlNewNode : malloc failed\n");
1503 return(NULL);
1504 }
1505 memset(cur, 0, sizeof(xmlNode));
1506 cur->type = XML_ELEMENT_NODE;
1507
1508 cur->name = xmlStrdup(name);
1509 cur->ns = ns;
1510 return(cur);
1511}
1512
1513/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001514 * xmlNewNodeEatName:
1515 * @ns: namespace if any
1516 * @name: the node name
1517 *
1518 * Creation of a new node element. @ns is optional (NULL).
1519 *
1520 * Returns a pointer to the new node object.
1521 */
1522xmlNodePtr
1523xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1524 xmlNodePtr cur;
1525
1526 if (name == NULL) {
1527#ifdef DEBUG_TREE
1528 xmlGenericError(xmlGenericErrorContext,
1529 "xmlNewNode : name == NULL\n");
1530#endif
1531 return(NULL);
1532 }
1533
1534 /*
1535 * Allocate a new node and fill the fields.
1536 */
1537 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1538 if (cur == NULL) {
1539 xmlGenericError(xmlGenericErrorContext,
1540 "xmlNewNode : malloc failed\n");
1541 return(NULL);
1542 }
1543 memset(cur, 0, sizeof(xmlNode));
1544 cur->type = XML_ELEMENT_NODE;
1545
1546 cur->name = name;
1547 cur->ns = ns;
1548 return(cur);
1549}
1550
1551/**
Owen Taylor3473f882001-02-23 17:55:21 +00001552 * xmlNewDocNode:
1553 * @doc: the document
1554 * @ns: namespace if any
1555 * @name: the node name
1556 * @content: the XML text content if any
1557 *
1558 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001559 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001560 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1561 * references, but XML special chars need to be escaped first by using
1562 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1563 * need entities support.
1564 *
1565 * Returns a pointer to the new node object.
1566 */
1567xmlNodePtr
1568xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1569 const xmlChar *name, const xmlChar *content) {
1570 xmlNodePtr cur;
1571
1572 cur = xmlNewNode(ns, name);
1573 if (cur != NULL) {
1574 cur->doc = doc;
1575 if (content != NULL) {
1576 cur->children = xmlStringGetNodeList(doc, content);
1577 UPDATE_LAST_CHILD_AND_PARENT(cur)
1578 }
1579 }
1580 return(cur);
1581}
1582
Daniel Veillard46de64e2002-05-29 08:21:33 +00001583/**
1584 * xmlNewDocNodeEatName:
1585 * @doc: the document
1586 * @ns: namespace if any
1587 * @name: the node name
1588 * @content: the XML text content if any
1589 *
1590 * Creation of a new node element within a document. @ns and @content
1591 * are optional (NULL).
1592 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1593 * references, but XML special chars need to be escaped first by using
1594 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1595 * need entities support.
1596 *
1597 * Returns a pointer to the new node object.
1598 */
1599xmlNodePtr
1600xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1601 xmlChar *name, const xmlChar *content) {
1602 xmlNodePtr cur;
1603
1604 cur = xmlNewNodeEatName(ns, name);
1605 if (cur != NULL) {
1606 cur->doc = doc;
1607 if (content != NULL) {
1608 cur->children = xmlStringGetNodeList(doc, content);
1609 UPDATE_LAST_CHILD_AND_PARENT(cur)
1610 }
1611 }
1612 return(cur);
1613}
1614
Owen Taylor3473f882001-02-23 17:55:21 +00001615
1616/**
1617 * xmlNewDocRawNode:
1618 * @doc: the document
1619 * @ns: namespace if any
1620 * @name: the node name
1621 * @content: the text content if any
1622 *
1623 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001624 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001625 *
1626 * Returns a pointer to the new node object.
1627 */
1628xmlNodePtr
1629xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1630 const xmlChar *name, const xmlChar *content) {
1631 xmlNodePtr cur;
1632
1633 cur = xmlNewNode(ns, name);
1634 if (cur != NULL) {
1635 cur->doc = doc;
1636 if (content != NULL) {
1637 cur->children = xmlNewDocText(doc, content);
1638 UPDATE_LAST_CHILD_AND_PARENT(cur)
1639 }
1640 }
1641 return(cur);
1642}
1643
1644/**
1645 * xmlNewDocFragment:
1646 * @doc: the document owning the fragment
1647 *
1648 * Creation of a new Fragment node.
1649 * Returns a pointer to the new node object.
1650 */
1651xmlNodePtr
1652xmlNewDocFragment(xmlDocPtr doc) {
1653 xmlNodePtr cur;
1654
1655 /*
1656 * Allocate a new DocumentFragment node and fill the fields.
1657 */
1658 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1659 if (cur == NULL) {
1660 xmlGenericError(xmlGenericErrorContext,
1661 "xmlNewDocFragment : malloc failed\n");
1662 return(NULL);
1663 }
1664 memset(cur, 0, sizeof(xmlNode));
1665 cur->type = XML_DOCUMENT_FRAG_NODE;
1666
1667 cur->doc = doc;
1668 return(cur);
1669}
1670
1671/**
1672 * xmlNewText:
1673 * @content: the text content
1674 *
1675 * Creation of a new text node.
1676 * Returns a pointer to the new node object.
1677 */
1678xmlNodePtr
1679xmlNewText(const xmlChar *content) {
1680 xmlNodePtr cur;
1681
1682 /*
1683 * Allocate a new node and fill the fields.
1684 */
1685 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1686 if (cur == NULL) {
1687 xmlGenericError(xmlGenericErrorContext,
1688 "xmlNewText : malloc failed\n");
1689 return(NULL);
1690 }
1691 memset(cur, 0, sizeof(xmlNode));
1692 cur->type = XML_TEXT_NODE;
1693
1694 cur->name = xmlStringText;
1695 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001696 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001697 }
1698 return(cur);
1699}
1700
1701/**
1702 * xmlNewTextChild:
1703 * @parent: the parent node
1704 * @ns: a namespace if any
1705 * @name: the name of the child
1706 * @content: the text content of the child if any.
1707 *
1708 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001709 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001710 * a child TEXT node will be created containing the string content.
1711 *
1712 * Returns a pointer to the new node object.
1713 */
1714xmlNodePtr
1715xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1716 const xmlChar *name, const xmlChar *content) {
1717 xmlNodePtr cur, prev;
1718
1719 if (parent == NULL) {
1720#ifdef DEBUG_TREE
1721 xmlGenericError(xmlGenericErrorContext,
1722 "xmlNewTextChild : parent == NULL\n");
1723#endif
1724 return(NULL);
1725 }
1726
1727 if (name == NULL) {
1728#ifdef DEBUG_TREE
1729 xmlGenericError(xmlGenericErrorContext,
1730 "xmlNewTextChild : name == NULL\n");
1731#endif
1732 return(NULL);
1733 }
1734
1735 /*
1736 * Allocate a new node
1737 */
1738 if (ns == NULL)
1739 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1740 else
1741 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1742 if (cur == NULL) return(NULL);
1743
1744 /*
1745 * add the new element at the end of the children list.
1746 */
1747 cur->type = XML_ELEMENT_NODE;
1748 cur->parent = parent;
1749 cur->doc = parent->doc;
1750 if (parent->children == NULL) {
1751 parent->children = cur;
1752 parent->last = cur;
1753 } else {
1754 prev = parent->last;
1755 prev->next = cur;
1756 cur->prev = prev;
1757 parent->last = cur;
1758 }
1759
1760 return(cur);
1761}
1762
1763/**
1764 * xmlNewCharRef:
1765 * @doc: the document
1766 * @name: the char ref string, starting with # or "&# ... ;"
1767 *
1768 * Creation of a new character reference node.
1769 * Returns a pointer to the new node object.
1770 */
1771xmlNodePtr
1772xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1773 xmlNodePtr cur;
1774
1775 /*
1776 * Allocate a new node and fill the fields.
1777 */
1778 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1779 if (cur == NULL) {
1780 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001781 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001782 return(NULL);
1783 }
1784 memset(cur, 0, sizeof(xmlNode));
1785 cur->type = XML_ENTITY_REF_NODE;
1786
1787 cur->doc = doc;
1788 if (name[0] == '&') {
1789 int len;
1790 name++;
1791 len = xmlStrlen(name);
1792 if (name[len - 1] == ';')
1793 cur->name = xmlStrndup(name, len - 1);
1794 else
1795 cur->name = xmlStrndup(name, len);
1796 } else
1797 cur->name = xmlStrdup(name);
1798 return(cur);
1799}
1800
1801/**
1802 * xmlNewReference:
1803 * @doc: the document
1804 * @name: the reference name, or the reference string with & and ;
1805 *
1806 * Creation of a new reference node.
1807 * Returns a pointer to the new node object.
1808 */
1809xmlNodePtr
1810xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1811 xmlNodePtr cur;
1812 xmlEntityPtr ent;
1813
1814 /*
1815 * Allocate a new node and fill the fields.
1816 */
1817 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1818 if (cur == NULL) {
1819 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001820 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001821 return(NULL);
1822 }
1823 memset(cur, 0, sizeof(xmlNode));
1824 cur->type = XML_ENTITY_REF_NODE;
1825
1826 cur->doc = doc;
1827 if (name[0] == '&') {
1828 int len;
1829 name++;
1830 len = xmlStrlen(name);
1831 if (name[len - 1] == ';')
1832 cur->name = xmlStrndup(name, len - 1);
1833 else
1834 cur->name = xmlStrndup(name, len);
1835 } else
1836 cur->name = xmlStrdup(name);
1837
1838 ent = xmlGetDocEntity(doc, cur->name);
1839 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001840 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001841 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001842 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001843 * updated. Not sure if this is 100% correct.
1844 * -George
1845 */
1846 cur->children = (xmlNodePtr) ent;
1847 cur->last = (xmlNodePtr) ent;
1848 }
1849 return(cur);
1850}
1851
1852/**
1853 * xmlNewDocText:
1854 * @doc: the document
1855 * @content: the text content
1856 *
1857 * Creation of a new text node within a document.
1858 * Returns a pointer to the new node object.
1859 */
1860xmlNodePtr
1861xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1862 xmlNodePtr cur;
1863
1864 cur = xmlNewText(content);
1865 if (cur != NULL) cur->doc = doc;
1866 return(cur);
1867}
1868
1869/**
1870 * xmlNewTextLen:
1871 * @content: the text content
1872 * @len: the text len.
1873 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001874 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001875 * Returns a pointer to the new node object.
1876 */
1877xmlNodePtr
1878xmlNewTextLen(const xmlChar *content, int len) {
1879 xmlNodePtr cur;
1880
1881 /*
1882 * Allocate a new node and fill the fields.
1883 */
1884 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1885 if (cur == NULL) {
1886 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001887 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001888 return(NULL);
1889 }
1890 memset(cur, 0, sizeof(xmlNode));
1891 cur->type = XML_TEXT_NODE;
1892
1893 cur->name = xmlStringText;
1894 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001895 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001896 }
1897 return(cur);
1898}
1899
1900/**
1901 * xmlNewDocTextLen:
1902 * @doc: the document
1903 * @content: the text content
1904 * @len: the text len.
1905 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001906 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001907 * text node pertain to a given document.
1908 * Returns a pointer to the new node object.
1909 */
1910xmlNodePtr
1911xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1912 xmlNodePtr cur;
1913
1914 cur = xmlNewTextLen(content, len);
1915 if (cur != NULL) cur->doc = doc;
1916 return(cur);
1917}
1918
1919/**
1920 * xmlNewComment:
1921 * @content: the comment content
1922 *
1923 * Creation of a new node containing a comment.
1924 * Returns a pointer to the new node object.
1925 */
1926xmlNodePtr
1927xmlNewComment(const xmlChar *content) {
1928 xmlNodePtr cur;
1929
1930 /*
1931 * Allocate a new node and fill the fields.
1932 */
1933 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1934 if (cur == NULL) {
1935 xmlGenericError(xmlGenericErrorContext,
1936 "xmlNewComment : malloc failed\n");
1937 return(NULL);
1938 }
1939 memset(cur, 0, sizeof(xmlNode));
1940 cur->type = XML_COMMENT_NODE;
1941
1942 cur->name = xmlStringComment;
1943 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001944 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001945 }
1946 return(cur);
1947}
1948
1949/**
1950 * xmlNewCDataBlock:
1951 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001952 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001953 * @len: the length of the block
1954 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001955 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001956 * Returns a pointer to the new node object.
1957 */
1958xmlNodePtr
1959xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1960 xmlNodePtr cur;
1961
1962 /*
1963 * Allocate a new node and fill the fields.
1964 */
1965 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1966 if (cur == NULL) {
1967 xmlGenericError(xmlGenericErrorContext,
1968 "xmlNewCDataBlock : malloc failed\n");
1969 return(NULL);
1970 }
1971 memset(cur, 0, sizeof(xmlNode));
1972 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001973 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001974
1975 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001976 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001977 }
1978 return(cur);
1979}
1980
1981/**
1982 * xmlNewDocComment:
1983 * @doc: the document
1984 * @content: the comment content
1985 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001986 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001987 * Returns a pointer to the new node object.
1988 */
1989xmlNodePtr
1990xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1991 xmlNodePtr cur;
1992
1993 cur = xmlNewComment(content);
1994 if (cur != NULL) cur->doc = doc;
1995 return(cur);
1996}
1997
1998/**
1999 * xmlSetTreeDoc:
2000 * @tree: the top element
2001 * @doc: the document
2002 *
2003 * update all nodes under the tree to point to the right document
2004 */
2005void
2006xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002007 xmlAttrPtr prop;
2008
Owen Taylor3473f882001-02-23 17:55:21 +00002009 if (tree == NULL)
2010 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002011 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002012 if(tree->type == XML_ELEMENT_NODE) {
2013 prop = tree->properties;
2014 while (prop != NULL) {
2015 prop->doc = doc;
2016 xmlSetListDoc(prop->children, doc);
2017 prop = prop->next;
2018 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002019 }
Owen Taylor3473f882001-02-23 17:55:21 +00002020 if (tree->children != NULL)
2021 xmlSetListDoc(tree->children, doc);
2022 tree->doc = doc;
2023 }
2024}
2025
2026/**
2027 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002028 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002029 * @doc: the document
2030 *
2031 * update all nodes in the list to point to the right document
2032 */
2033void
2034xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2035 xmlNodePtr cur;
2036
2037 if (list == NULL)
2038 return;
2039 cur = list;
2040 while (cur != NULL) {
2041 if (cur->doc != doc)
2042 xmlSetTreeDoc(cur, doc);
2043 cur = cur->next;
2044 }
2045}
2046
2047
2048/**
2049 * xmlNewChild:
2050 * @parent: the parent node
2051 * @ns: a namespace if any
2052 * @name: the name of the child
2053 * @content: the XML content of the child if any.
2054 *
2055 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002056 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002057 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2058 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2059 * references, but XML special chars need to be escaped first by using
2060 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2061 * support is not needed.
2062 *
2063 * Returns a pointer to the new node object.
2064 */
2065xmlNodePtr
2066xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2067 const xmlChar *name, const xmlChar *content) {
2068 xmlNodePtr cur, prev;
2069
2070 if (parent == NULL) {
2071#ifdef DEBUG_TREE
2072 xmlGenericError(xmlGenericErrorContext,
2073 "xmlNewChild : parent == NULL\n");
2074#endif
2075 return(NULL);
2076 }
2077
2078 if (name == NULL) {
2079#ifdef DEBUG_TREE
2080 xmlGenericError(xmlGenericErrorContext,
2081 "xmlNewChild : name == NULL\n");
2082#endif
2083 return(NULL);
2084 }
2085
2086 /*
2087 * Allocate a new node
2088 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002089 if (parent->type == XML_ELEMENT_NODE) {
2090 if (ns == NULL)
2091 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2092 else
2093 cur = xmlNewDocNode(parent->doc, ns, name, content);
2094 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2095 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2096 if (ns == NULL)
2097 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2098 else
2099 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002100 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2101 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002102 } else {
2103 return(NULL);
2104 }
Owen Taylor3473f882001-02-23 17:55:21 +00002105 if (cur == NULL) return(NULL);
2106
2107 /*
2108 * add the new element at the end of the children list.
2109 */
2110 cur->type = XML_ELEMENT_NODE;
2111 cur->parent = parent;
2112 cur->doc = parent->doc;
2113 if (parent->children == NULL) {
2114 parent->children = cur;
2115 parent->last = cur;
2116 } else {
2117 prev = parent->last;
2118 prev->next = cur;
2119 cur->prev = prev;
2120 parent->last = cur;
2121 }
2122
2123 return(cur);
2124}
2125
2126/**
2127 * xmlAddNextSibling:
2128 * @cur: the child node
2129 * @elem: the new node
2130 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002131 * Add a new node @elem as the next sibling of @cur
2132 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002133 * first unlinked from its existing context.
2134 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002135 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2136 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002137 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002138 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002139 */
2140xmlNodePtr
2141xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2142 if (cur == NULL) {
2143#ifdef DEBUG_TREE
2144 xmlGenericError(xmlGenericErrorContext,
2145 "xmlAddNextSibling : cur == NULL\n");
2146#endif
2147 return(NULL);
2148 }
2149 if (elem == NULL) {
2150#ifdef DEBUG_TREE
2151 xmlGenericError(xmlGenericErrorContext,
2152 "xmlAddNextSibling : elem == NULL\n");
2153#endif
2154 return(NULL);
2155 }
2156
2157 xmlUnlinkNode(elem);
2158
2159 if (elem->type == XML_TEXT_NODE) {
2160 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002161 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002162 xmlFreeNode(elem);
2163 return(cur);
2164 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002165 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2166 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002167 xmlChar *tmp;
2168
2169 tmp = xmlStrdup(elem->content);
2170 tmp = xmlStrcat(tmp, cur->next->content);
2171 xmlNodeSetContent(cur->next, tmp);
2172 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002173 xmlFreeNode(elem);
2174 return(cur->next);
2175 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002176 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2177 /* check if an attribute with the same name exists */
2178 xmlAttrPtr attr;
2179
2180 if (elem->ns == NULL)
2181 attr = xmlHasProp(cur->parent, elem->name);
2182 else
2183 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2184 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2185 /* different instance, destroy it (attributes must be unique) */
2186 xmlFreeProp(attr);
2187 }
Owen Taylor3473f882001-02-23 17:55:21 +00002188 }
2189
2190 if (elem->doc != cur->doc) {
2191 xmlSetTreeDoc(elem, cur->doc);
2192 }
2193 elem->parent = cur->parent;
2194 elem->prev = cur;
2195 elem->next = cur->next;
2196 cur->next = elem;
2197 if (elem->next != NULL)
2198 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002199 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002200 elem->parent->last = elem;
2201 return(elem);
2202}
2203
2204/**
2205 * xmlAddPrevSibling:
2206 * @cur: the child node
2207 * @elem: the new node
2208 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002209 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002210 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002211 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002212 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002213 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2214 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002215 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002216 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002217 */
2218xmlNodePtr
2219xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2220 if (cur == NULL) {
2221#ifdef DEBUG_TREE
2222 xmlGenericError(xmlGenericErrorContext,
2223 "xmlAddPrevSibling : cur == NULL\n");
2224#endif
2225 return(NULL);
2226 }
2227 if (elem == NULL) {
2228#ifdef DEBUG_TREE
2229 xmlGenericError(xmlGenericErrorContext,
2230 "xmlAddPrevSibling : elem == NULL\n");
2231#endif
2232 return(NULL);
2233 }
2234
2235 xmlUnlinkNode(elem);
2236
2237 if (elem->type == XML_TEXT_NODE) {
2238 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002239 xmlChar *tmp;
2240
2241 tmp = xmlStrdup(elem->content);
2242 tmp = xmlStrcat(tmp, cur->content);
2243 xmlNodeSetContent(cur, tmp);
2244 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002245 xmlFreeNode(elem);
2246 return(cur);
2247 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002248 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2249 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002250 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002251 xmlFreeNode(elem);
2252 return(cur->prev);
2253 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002254 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2255 /* check if an attribute with the same name exists */
2256 xmlAttrPtr attr;
2257
2258 if (elem->ns == NULL)
2259 attr = xmlHasProp(cur->parent, elem->name);
2260 else
2261 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2262 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2263 /* different instance, destroy it (attributes must be unique) */
2264 xmlFreeProp(attr);
2265 }
Owen Taylor3473f882001-02-23 17:55:21 +00002266 }
2267
2268 if (elem->doc != cur->doc) {
2269 xmlSetTreeDoc(elem, cur->doc);
2270 }
2271 elem->parent = cur->parent;
2272 elem->next = cur;
2273 elem->prev = cur->prev;
2274 cur->prev = elem;
2275 if (elem->prev != NULL)
2276 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002277 if (elem->parent != NULL) {
2278 if (elem->type == XML_ATTRIBUTE_NODE) {
2279 if (elem->parent->properties == (xmlAttrPtr) cur) {
2280 elem->parent->properties = (xmlAttrPtr) elem;
2281 }
2282 } else {
2283 if (elem->parent->children == cur) {
2284 elem->parent->children = elem;
2285 }
2286 }
2287 }
Owen Taylor3473f882001-02-23 17:55:21 +00002288 return(elem);
2289}
2290
2291/**
2292 * xmlAddSibling:
2293 * @cur: the child node
2294 * @elem: the new node
2295 *
2296 * Add a new element @elem to the list of siblings of @cur
2297 * merging adjacent TEXT nodes (@elem may be freed)
2298 * If the new element was already inserted in a document it is
2299 * first unlinked from its existing context.
2300 *
2301 * Returns the new element or NULL in case of error.
2302 */
2303xmlNodePtr
2304xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2305 xmlNodePtr parent;
2306
2307 if (cur == NULL) {
2308#ifdef DEBUG_TREE
2309 xmlGenericError(xmlGenericErrorContext,
2310 "xmlAddSibling : cur == NULL\n");
2311#endif
2312 return(NULL);
2313 }
2314
2315 if (elem == NULL) {
2316#ifdef DEBUG_TREE
2317 xmlGenericError(xmlGenericErrorContext,
2318 "xmlAddSibling : elem == NULL\n");
2319#endif
2320 return(NULL);
2321 }
2322
2323 /*
2324 * Constant time is we can rely on the ->parent->last to find
2325 * the last sibling.
2326 */
2327 if ((cur->parent != NULL) &&
2328 (cur->parent->children != NULL) &&
2329 (cur->parent->last != NULL) &&
2330 (cur->parent->last->next == NULL)) {
2331 cur = cur->parent->last;
2332 } else {
2333 while (cur->next != NULL) cur = cur->next;
2334 }
2335
2336 xmlUnlinkNode(elem);
2337
2338 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002339 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002340 xmlFreeNode(elem);
2341 return(cur);
2342 }
2343
2344 if (elem->doc != cur->doc) {
2345 xmlSetTreeDoc(elem, cur->doc);
2346 }
2347 parent = cur->parent;
2348 elem->prev = cur;
2349 elem->next = NULL;
2350 elem->parent = parent;
2351 cur->next = elem;
2352 if (parent != NULL)
2353 parent->last = elem;
2354
2355 return(elem);
2356}
2357
2358/**
2359 * xmlAddChildList:
2360 * @parent: the parent node
2361 * @cur: the first node in the list
2362 *
2363 * Add a list of node at the end of the child list of the parent
2364 * merging adjacent TEXT nodes (@cur may be freed)
2365 *
2366 * Returns the last child or NULL in case of error.
2367 */
2368xmlNodePtr
2369xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2370 xmlNodePtr prev;
2371
2372 if (parent == NULL) {
2373#ifdef DEBUG_TREE
2374 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002375 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002376#endif
2377 return(NULL);
2378 }
2379
2380 if (cur == NULL) {
2381#ifdef DEBUG_TREE
2382 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002383 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002384#endif
2385 return(NULL);
2386 }
2387
2388 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2389 (cur->doc != parent->doc)) {
2390#ifdef DEBUG_TREE
2391 xmlGenericError(xmlGenericErrorContext,
2392 "Elements moved to a different document\n");
2393#endif
2394 }
2395
2396 /*
2397 * add the first element at the end of the children list.
2398 */
2399 if (parent->children == NULL) {
2400 parent->children = cur;
2401 } else {
2402 /*
2403 * If cur and parent->last both are TEXT nodes, then merge them.
2404 */
2405 if ((cur->type == XML_TEXT_NODE) &&
2406 (parent->last->type == XML_TEXT_NODE) &&
2407 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002408 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002409 /*
2410 * if it's the only child, nothing more to be done.
2411 */
2412 if (cur->next == NULL) {
2413 xmlFreeNode(cur);
2414 return(parent->last);
2415 }
2416 prev = cur;
2417 cur = cur->next;
2418 xmlFreeNode(prev);
2419 }
2420 prev = parent->last;
2421 prev->next = cur;
2422 cur->prev = prev;
2423 }
2424 while (cur->next != NULL) {
2425 cur->parent = parent;
2426 if (cur->doc != parent->doc) {
2427 xmlSetTreeDoc(cur, parent->doc);
2428 }
2429 cur = cur->next;
2430 }
2431 cur->parent = parent;
2432 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2433 parent->last = cur;
2434
2435 return(cur);
2436}
2437
2438/**
2439 * xmlAddChild:
2440 * @parent: the parent node
2441 * @cur: the child node
2442 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002443 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002444 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002445 * If the new node was already inserted in a document it is
2446 * first unlinked from its existing context.
2447 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2448 * If there is an attribute with equal name, it is first destroyed.
2449 *
Owen Taylor3473f882001-02-23 17:55:21 +00002450 * Returns the child or NULL in case of error.
2451 */
2452xmlNodePtr
2453xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2454 xmlNodePtr prev;
2455
2456 if (parent == NULL) {
2457#ifdef DEBUG_TREE
2458 xmlGenericError(xmlGenericErrorContext,
2459 "xmlAddChild : parent == NULL\n");
2460#endif
2461 return(NULL);
2462 }
2463
2464 if (cur == NULL) {
2465#ifdef DEBUG_TREE
2466 xmlGenericError(xmlGenericErrorContext,
2467 "xmlAddChild : child == NULL\n");
2468#endif
2469 return(NULL);
2470 }
2471
Owen Taylor3473f882001-02-23 17:55:21 +00002472 /*
2473 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002474 * cur is then freed.
2475 */
2476 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002477 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002478 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002479 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002480 xmlFreeNode(cur);
2481 return(parent);
2482 }
2483 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2484 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002485 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002486 xmlFreeNode(cur);
2487 return(parent->last);
2488 }
2489 }
2490
2491 /*
2492 * add the new element at the end of the children list.
2493 */
2494 cur->parent = parent;
2495 if (cur->doc != parent->doc) {
2496 xmlSetTreeDoc(cur, parent->doc);
2497 }
2498
2499 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002500 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002501 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002502 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002503 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002504 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002505 xmlFreeNode(cur);
2506 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002507 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002508 if (cur->type == XML_ATTRIBUTE_NODE) {
2509 if (parent->properties == NULL) {
2510 parent->properties = (xmlAttrPtr) cur;
2511 } else {
2512 /* check if an attribute with the same name exists */
2513 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002514
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002515 if (cur->ns == NULL)
2516 lastattr = xmlHasProp(parent, cur->name);
2517 else
2518 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2519 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2520 /* different instance, destroy it (attributes must be unique) */
2521 xmlFreeProp(lastattr);
2522 }
2523 /* find the end */
2524 lastattr = parent->properties;
2525 while (lastattr->next != NULL) {
2526 lastattr = lastattr->next;
2527 }
2528 lastattr->next = (xmlAttrPtr) cur;
2529 ((xmlAttrPtr) cur)->prev = lastattr;
2530 }
2531 } else {
2532 if (parent->children == NULL) {
2533 parent->children = cur;
2534 parent->last = cur;
2535 } else {
2536 prev = parent->last;
2537 prev->next = cur;
2538 cur->prev = prev;
2539 parent->last = cur;
2540 }
2541 }
Owen Taylor3473f882001-02-23 17:55:21 +00002542 return(cur);
2543}
2544
2545/**
2546 * xmlGetLastChild:
2547 * @parent: the parent node
2548 *
2549 * Search the last child of a node.
2550 * Returns the last child or NULL if none.
2551 */
2552xmlNodePtr
2553xmlGetLastChild(xmlNodePtr parent) {
2554 if (parent == NULL) {
2555#ifdef DEBUG_TREE
2556 xmlGenericError(xmlGenericErrorContext,
2557 "xmlGetLastChild : parent == NULL\n");
2558#endif
2559 return(NULL);
2560 }
2561 return(parent->last);
2562}
2563
2564/**
2565 * xmlFreeNodeList:
2566 * @cur: the first node in the list
2567 *
2568 * Free a node and all its siblings, this is a recursive behaviour, all
2569 * the children are freed too.
2570 */
2571void
2572xmlFreeNodeList(xmlNodePtr cur) {
2573 xmlNodePtr next;
2574 if (cur == NULL) {
2575#ifdef DEBUG_TREE
2576 xmlGenericError(xmlGenericErrorContext,
2577 "xmlFreeNodeList : node == NULL\n");
2578#endif
2579 return;
2580 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002581 if (cur->type == XML_NAMESPACE_DECL) {
2582 xmlFreeNsList((xmlNsPtr) cur);
2583 return;
2584 }
Owen Taylor3473f882001-02-23 17:55:21 +00002585 while (cur != NULL) {
2586 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002587 /* unroll to speed up freeing the document */
2588 if (cur->type != XML_DTD_NODE) {
2589 if ((cur->children != NULL) &&
2590 (cur->type != XML_ENTITY_REF_NODE))
2591 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002592 if (((cur->type == XML_ELEMENT_NODE) ||
2593 (cur->type == XML_XINCLUDE_START) ||
2594 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002595 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002596 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002597 if ((cur->type != XML_ELEMENT_NODE) &&
2598 (cur->type != XML_XINCLUDE_START) &&
2599 (cur->type != XML_XINCLUDE_END) &&
2600 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002601 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002602 }
2603 if (((cur->type == XML_ELEMENT_NODE) ||
2604 (cur->type == XML_XINCLUDE_START) ||
2605 (cur->type == XML_XINCLUDE_END)) &&
2606 (cur->nsDef != NULL))
2607 xmlFreeNsList(cur->nsDef);
2608
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002609 /*
2610 * When a node is a text node or a comment, it uses a global static
2611 * variable for the name of the node.
2612 *
2613 * The xmlStrEqual comparisons need to be done when (happened with
2614 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002615 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002616 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002617 * the string addresses compare are not sufficient.
2618 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002619 if ((cur->name != NULL) &&
2620 (cur->name != xmlStringText) &&
2621 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002622 (cur->name != xmlStringComment)) {
2623 if (cur->type == XML_TEXT_NODE) {
2624 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2625 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2626 xmlFree((char *) cur->name);
2627 } else if (cur->type == XML_COMMENT_NODE) {
2628 if (!xmlStrEqual(cur->name, xmlStringComment))
2629 xmlFree((char *) cur->name);
2630 } else
2631 xmlFree((char *) cur->name);
2632 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002633 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002634 xmlFree(cur);
2635 }
Owen Taylor3473f882001-02-23 17:55:21 +00002636 cur = next;
2637 }
2638}
2639
2640/**
2641 * xmlFreeNode:
2642 * @cur: the node
2643 *
2644 * Free a node, this is a recursive behaviour, all the children are freed too.
2645 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2646 */
2647void
2648xmlFreeNode(xmlNodePtr cur) {
2649 if (cur == NULL) {
2650#ifdef DEBUG_TREE
2651 xmlGenericError(xmlGenericErrorContext,
2652 "xmlFreeNode : node == NULL\n");
2653#endif
2654 return;
2655 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002656 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002657 if (cur->type == XML_DTD_NODE) {
2658 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002659 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002660 }
2661 if (cur->type == XML_NAMESPACE_DECL) {
2662 xmlFreeNs((xmlNsPtr) cur);
2663 return;
2664 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00002665 if (cur->type == XML_ATTRIBUTE_NODE) {
2666 xmlFreeProp((xmlAttrPtr) cur);
2667 return;
2668 }
Owen Taylor3473f882001-02-23 17:55:21 +00002669 if ((cur->children != NULL) &&
2670 (cur->type != XML_ENTITY_REF_NODE))
2671 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002672 if (((cur->type == XML_ELEMENT_NODE) ||
2673 (cur->type == XML_XINCLUDE_START) ||
2674 (cur->type == XML_XINCLUDE_END)) &&
2675 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002676 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002677 if ((cur->type != XML_ELEMENT_NODE) &&
2678 (cur->content != NULL) &&
2679 (cur->type != XML_ENTITY_REF_NODE) &&
2680 (cur->type != XML_XINCLUDE_END) &&
2681 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002682 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002683 }
2684
Daniel Veillardacd370f2001-06-09 17:17:51 +00002685 /*
2686 * When a node is a text node or a comment, it uses a global static
2687 * variable for the name of the node.
2688 *
2689 * The xmlStrEqual comparisons need to be done when (happened with
2690 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002691 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002692 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002693 * are not sufficient.
2694 */
Owen Taylor3473f882001-02-23 17:55:21 +00002695 if ((cur->name != NULL) &&
2696 (cur->name != xmlStringText) &&
2697 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002698 (cur->name != xmlStringComment)) {
2699 if (cur->type == XML_TEXT_NODE) {
2700 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2701 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2702 xmlFree((char *) cur->name);
2703 } else if (cur->type == XML_COMMENT_NODE) {
2704 if (!xmlStrEqual(cur->name, xmlStringComment))
2705 xmlFree((char *) cur->name);
2706 } else
2707 xmlFree((char *) cur->name);
2708 }
2709
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002710 if (((cur->type == XML_ELEMENT_NODE) ||
2711 (cur->type == XML_XINCLUDE_START) ||
2712 (cur->type == XML_XINCLUDE_END)) &&
2713 (cur->nsDef != NULL))
2714 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002715 xmlFree(cur);
2716}
2717
2718/**
2719 * xmlUnlinkNode:
2720 * @cur: the node
2721 *
2722 * Unlink a node from it's current context, the node is not freed
2723 */
2724void
2725xmlUnlinkNode(xmlNodePtr cur) {
2726 if (cur == NULL) {
2727#ifdef DEBUG_TREE
2728 xmlGenericError(xmlGenericErrorContext,
2729 "xmlUnlinkNode : node == NULL\n");
2730#endif
2731 return;
2732 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002733 if (cur->type == XML_DTD_NODE) {
2734 xmlDocPtr doc;
2735 doc = cur->doc;
2736 if (doc->intSubset == (xmlDtdPtr) cur)
2737 doc->intSubset = NULL;
2738 if (doc->extSubset == (xmlDtdPtr) cur)
2739 doc->extSubset = NULL;
2740 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002741 if (cur->parent != NULL) {
2742 xmlNodePtr parent;
2743 parent = cur->parent;
2744 if (cur->type == XML_ATTRIBUTE_NODE) {
2745 if (parent->properties == (xmlAttrPtr) cur)
2746 parent->properties = ((xmlAttrPtr) cur)->next;
2747 } else {
2748 if (parent->children == cur)
2749 parent->children = cur->next;
2750 if (parent->last == cur)
2751 parent->last = cur->prev;
2752 }
2753 cur->parent = NULL;
2754 }
Owen Taylor3473f882001-02-23 17:55:21 +00002755 if (cur->next != NULL)
2756 cur->next->prev = cur->prev;
2757 if (cur->prev != NULL)
2758 cur->prev->next = cur->next;
2759 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002760}
2761
2762/**
2763 * xmlReplaceNode:
2764 * @old: the old node
2765 * @cur: the node
2766 *
2767 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002768 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002769 * first unlinked from its existing context.
2770 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002771 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002772 */
2773xmlNodePtr
2774xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2775 if (old == NULL) {
2776#ifdef DEBUG_TREE
2777 xmlGenericError(xmlGenericErrorContext,
2778 "xmlReplaceNode : old == NULL\n");
2779#endif
2780 return(NULL);
2781 }
2782 if (cur == NULL) {
2783 xmlUnlinkNode(old);
2784 return(old);
2785 }
2786 if (cur == old) {
2787 return(old);
2788 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002789 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2790#ifdef DEBUG_TREE
2791 xmlGenericError(xmlGenericErrorContext,
2792 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2793#endif
2794 return(old);
2795 }
2796 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2797#ifdef DEBUG_TREE
2798 xmlGenericError(xmlGenericErrorContext,
2799 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2800#endif
2801 return(old);
2802 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002803 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2804#ifdef DEBUG_TREE
2805 xmlGenericError(xmlGenericErrorContext,
2806 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2807#endif
2808 return(old);
2809 }
2810 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2811#ifdef DEBUG_TREE
2812 xmlGenericError(xmlGenericErrorContext,
2813 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2814#endif
2815 return(old);
2816 }
Owen Taylor3473f882001-02-23 17:55:21 +00002817 xmlUnlinkNode(cur);
2818 cur->doc = old->doc;
2819 cur->parent = old->parent;
2820 cur->next = old->next;
2821 if (cur->next != NULL)
2822 cur->next->prev = cur;
2823 cur->prev = old->prev;
2824 if (cur->prev != NULL)
2825 cur->prev->next = cur;
2826 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002827 if (cur->type == XML_ATTRIBUTE_NODE) {
2828 if (cur->parent->properties == (xmlAttrPtr)old)
2829 cur->parent->properties = ((xmlAttrPtr) cur);
2830 } else {
2831 if (cur->parent->children == old)
2832 cur->parent->children = cur;
2833 if (cur->parent->last == old)
2834 cur->parent->last = cur;
2835 }
Owen Taylor3473f882001-02-23 17:55:21 +00002836 }
2837 old->next = old->prev = NULL;
2838 old->parent = NULL;
2839 return(old);
2840}
2841
2842/************************************************************************
2843 * *
2844 * Copy operations *
2845 * *
2846 ************************************************************************/
2847
2848/**
2849 * xmlCopyNamespace:
2850 * @cur: the namespace
2851 *
2852 * Do a copy of the namespace.
2853 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002854 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002855 */
2856xmlNsPtr
2857xmlCopyNamespace(xmlNsPtr cur) {
2858 xmlNsPtr ret;
2859
2860 if (cur == NULL) return(NULL);
2861 switch (cur->type) {
2862 case XML_LOCAL_NAMESPACE:
2863 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2864 break;
2865 default:
2866#ifdef DEBUG_TREE
2867 xmlGenericError(xmlGenericErrorContext,
2868 "xmlCopyNamespace: invalid type %d\n", cur->type);
2869#endif
2870 return(NULL);
2871 }
2872 return(ret);
2873}
2874
2875/**
2876 * xmlCopyNamespaceList:
2877 * @cur: the first namespace
2878 *
2879 * Do a copy of an namespace list.
2880 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002881 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002882 */
2883xmlNsPtr
2884xmlCopyNamespaceList(xmlNsPtr cur) {
2885 xmlNsPtr ret = NULL;
2886 xmlNsPtr p = NULL,q;
2887
2888 while (cur != NULL) {
2889 q = xmlCopyNamespace(cur);
2890 if (p == NULL) {
2891 ret = p = q;
2892 } else {
2893 p->next = q;
2894 p = q;
2895 }
2896 cur = cur->next;
2897 }
2898 return(ret);
2899}
2900
2901static xmlNodePtr
2902xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2903/**
2904 * xmlCopyProp:
2905 * @target: the element where the attribute will be grafted
2906 * @cur: the attribute
2907 *
2908 * Do a copy of the attribute.
2909 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002910 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002911 */
2912xmlAttrPtr
2913xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2914 xmlAttrPtr ret;
2915
2916 if (cur == NULL) return(NULL);
2917 if (target != NULL)
2918 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2919 else if (cur->parent != NULL)
2920 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2921 else if (cur->children != NULL)
2922 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2923 else
2924 ret = xmlNewDocProp(NULL, cur->name, NULL);
2925 if (ret == NULL) return(NULL);
2926 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002927
Owen Taylor3473f882001-02-23 17:55:21 +00002928 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002929 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002930/*
2931 * if (target->doc)
2932 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2933 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2934 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2935 * else
2936 * ns = NULL;
2937 * ret->ns = ns;
2938 */
2939 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2940 if (ns == NULL) {
2941 /*
2942 * Humm, we are copying an element whose namespace is defined
2943 * out of the new tree scope. Search it in the original tree
2944 * and add it at the top of the new tree
2945 */
2946 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2947 if (ns != NULL) {
2948 xmlNodePtr root = target;
2949 xmlNodePtr pred = NULL;
2950
2951 while (root->parent != NULL) {
2952 pred = root;
2953 root = root->parent;
2954 }
2955 if (root == (xmlNodePtr) target->doc) {
2956 /* correct possibly cycling above the document elt */
2957 root = pred;
2958 }
2959 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2960 }
2961 } else {
2962 /*
2963 * we have to find something appropriate here since
2964 * we cant be sure, that the namespce we found is identified
2965 * by the prefix
2966 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002967 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002968 /* this is the nice case */
2969 ret->ns = ns;
2970 } else {
2971 /*
2972 * we are in trouble: we need a new reconcilied namespace.
2973 * This is expensive
2974 */
2975 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2976 }
2977 }
2978
Owen Taylor3473f882001-02-23 17:55:21 +00002979 } else
2980 ret->ns = NULL;
2981
2982 if (cur->children != NULL) {
2983 xmlNodePtr tmp;
2984
2985 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2986 ret->last = NULL;
2987 tmp = ret->children;
2988 while (tmp != NULL) {
2989 /* tmp->parent = (xmlNodePtr)ret; */
2990 if (tmp->next == NULL)
2991 ret->last = tmp;
2992 tmp = tmp->next;
2993 }
2994 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002995 /*
2996 * Try to handle IDs
2997 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002998 if ((target!= NULL) && (cur!= NULL) &&
2999 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003000 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3001 if (xmlIsID(cur->doc, cur->parent, cur)) {
3002 xmlChar *id;
3003
3004 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3005 if (id != NULL) {
3006 xmlAddID(NULL, target->doc, id, ret);
3007 xmlFree(id);
3008 }
3009 }
3010 }
Owen Taylor3473f882001-02-23 17:55:21 +00003011 return(ret);
3012}
3013
3014/**
3015 * xmlCopyPropList:
3016 * @target: the element where the attributes will be grafted
3017 * @cur: the first attribute
3018 *
3019 * Do a copy of an attribute list.
3020 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003021 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003022 */
3023xmlAttrPtr
3024xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3025 xmlAttrPtr ret = NULL;
3026 xmlAttrPtr p = NULL,q;
3027
3028 while (cur != NULL) {
3029 q = xmlCopyProp(target, cur);
3030 if (p == NULL) {
3031 ret = p = q;
3032 } else {
3033 p->next = q;
3034 q->prev = p;
3035 p = q;
3036 }
3037 cur = cur->next;
3038 }
3039 return(ret);
3040}
3041
3042/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003043 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003044 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003045 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003046 * tricky reason: namespaces. Doing a direct copy of a node
3047 * say RPM:Copyright without changing the namespace pointer to
3048 * something else can produce stale links. One way to do it is
3049 * to keep a reference counter but this doesn't work as soon
3050 * as one move the element or the subtree out of the scope of
3051 * the existing namespace. The actual solution seems to add
3052 * a copy of the namespace at the top of the copied tree if
3053 * not available in the subtree.
3054 * Hence two functions, the public front-end call the inner ones
3055 */
3056
3057static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003058xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003059 int recursive) {
3060 xmlNodePtr ret;
3061
3062 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003063 switch (node->type) {
3064 case XML_TEXT_NODE:
3065 case XML_CDATA_SECTION_NODE:
3066 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003067 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003068 case XML_ENTITY_REF_NODE:
3069 case XML_ENTITY_NODE:
3070 case XML_PI_NODE:
3071 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003072 case XML_XINCLUDE_START:
3073 case XML_XINCLUDE_END:
3074 break;
3075 case XML_ATTRIBUTE_NODE:
3076 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3077 case XML_NAMESPACE_DECL:
3078 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3079
Daniel Veillard39196eb2001-06-19 18:09:42 +00003080 case XML_DOCUMENT_NODE:
3081 case XML_HTML_DOCUMENT_NODE:
3082#ifdef LIBXML_DOCB_ENABLED
3083 case XML_DOCB_DOCUMENT_NODE:
3084#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003085 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003086 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003087 case XML_NOTATION_NODE:
3088 case XML_DTD_NODE:
3089 case XML_ELEMENT_DECL:
3090 case XML_ATTRIBUTE_DECL:
3091 case XML_ENTITY_DECL:
3092 return(NULL);
3093 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003094
Owen Taylor3473f882001-02-23 17:55:21 +00003095 /*
3096 * Allocate a new node and fill the fields.
3097 */
3098 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3099 if (ret == NULL) {
3100 xmlGenericError(xmlGenericErrorContext,
3101 "xmlStaticCopyNode : malloc failed\n");
3102 return(NULL);
3103 }
3104 memset(ret, 0, sizeof(xmlNode));
3105 ret->type = node->type;
3106
3107 ret->doc = doc;
3108 ret->parent = parent;
3109 if (node->name == xmlStringText)
3110 ret->name = xmlStringText;
3111 else if (node->name == xmlStringTextNoenc)
3112 ret->name = xmlStringTextNoenc;
3113 else if (node->name == xmlStringComment)
3114 ret->name = xmlStringComment;
3115 else if (node->name != NULL)
3116 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003117 if ((node->type != XML_ELEMENT_NODE) &&
3118 (node->content != NULL) &&
3119 (node->type != XML_ENTITY_REF_NODE) &&
3120 (node->type != XML_XINCLUDE_END) &&
3121 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003122 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003123 }else{
3124 if (node->type == XML_ELEMENT_NODE)
3125 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003126 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003127 if (parent != NULL) {
3128 xmlNodePtr tmp;
3129
3130 tmp = xmlAddChild(parent, ret);
3131 /* node could have coalesced */
3132 if (tmp != ret)
3133 return(tmp);
3134 }
Owen Taylor3473f882001-02-23 17:55:21 +00003135
3136 if (!recursive) return(ret);
3137 if (node->nsDef != NULL)
3138 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3139
3140 if (node->ns != NULL) {
3141 xmlNsPtr ns;
3142
3143 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3144 if (ns == NULL) {
3145 /*
3146 * Humm, we are copying an element whose namespace is defined
3147 * out of the new tree scope. Search it in the original tree
3148 * and add it at the top of the new tree
3149 */
3150 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3151 if (ns != NULL) {
3152 xmlNodePtr root = ret;
3153
3154 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003155 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003156 }
3157 } else {
3158 /*
3159 * reference the existing namespace definition in our own tree.
3160 */
3161 ret->ns = ns;
3162 }
3163 }
3164 if (node->properties != NULL)
3165 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003166 if (node->type == XML_ENTITY_REF_NODE) {
3167 if ((doc == NULL) || (node->doc != doc)) {
3168 /*
3169 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003170 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003171 * we cannot keep the reference. Try to find it in the
3172 * target document.
3173 */
3174 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3175 } else {
3176 ret->children = node->children;
3177 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003178 ret->last = ret->children;
3179 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003180 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003181 UPDATE_LAST_CHILD_AND_PARENT(ret)
3182 }
Owen Taylor3473f882001-02-23 17:55:21 +00003183 return(ret);
3184}
3185
3186static xmlNodePtr
3187xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3188 xmlNodePtr ret = NULL;
3189 xmlNodePtr p = NULL,q;
3190
3191 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003192 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003193 if (doc == NULL) {
3194 node = node->next;
3195 continue;
3196 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003197 if (doc->intSubset == NULL) {
3198 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3199 q->doc = doc;
3200 q->parent = parent;
3201 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003202 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003203 } else {
3204 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003205 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003206 }
3207 } else
3208 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003209 if (ret == NULL) {
3210 q->prev = NULL;
3211 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003212 } else if (p != q) {
3213 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003214 p->next = q;
3215 q->prev = p;
3216 p = q;
3217 }
3218 node = node->next;
3219 }
3220 return(ret);
3221}
3222
3223/**
3224 * xmlCopyNode:
3225 * @node: the node
3226 * @recursive: if 1 do a recursive copy.
3227 *
3228 * Do a copy of the node.
3229 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003230 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003231 */
3232xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003233xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003234 xmlNodePtr ret;
3235
3236 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3237 return(ret);
3238}
3239
3240/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003241 * xmlDocCopyNode:
3242 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003243 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003244 * @recursive: if 1 do a recursive copy.
3245 *
3246 * Do a copy of the node to a given document.
3247 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003248 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003249 */
3250xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003251xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003252 xmlNodePtr ret;
3253
3254 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3255 return(ret);
3256}
3257
3258/**
Owen Taylor3473f882001-02-23 17:55:21 +00003259 * xmlCopyNodeList:
3260 * @node: the first node in the list.
3261 *
3262 * Do a recursive copy of the node list.
3263 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003264 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003265 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003266xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003267 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3268 return(ret);
3269}
3270
3271/**
Owen Taylor3473f882001-02-23 17:55:21 +00003272 * xmlCopyDtd:
3273 * @dtd: the dtd
3274 *
3275 * Do a copy of the dtd.
3276 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003277 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003278 */
3279xmlDtdPtr
3280xmlCopyDtd(xmlDtdPtr dtd) {
3281 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003282 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003283
3284 if (dtd == NULL) return(NULL);
3285 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3286 if (ret == NULL) return(NULL);
3287 if (dtd->entities != NULL)
3288 ret->entities = (void *) xmlCopyEntitiesTable(
3289 (xmlEntitiesTablePtr) dtd->entities);
3290 if (dtd->notations != NULL)
3291 ret->notations = (void *) xmlCopyNotationTable(
3292 (xmlNotationTablePtr) dtd->notations);
3293 if (dtd->elements != NULL)
3294 ret->elements = (void *) xmlCopyElementTable(
3295 (xmlElementTablePtr) dtd->elements);
3296 if (dtd->attributes != NULL)
3297 ret->attributes = (void *) xmlCopyAttributeTable(
3298 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003299 if (dtd->pentities != NULL)
3300 ret->pentities = (void *) xmlCopyEntitiesTable(
3301 (xmlEntitiesTablePtr) dtd->pentities);
3302
3303 cur = dtd->children;
3304 while (cur != NULL) {
3305 q = NULL;
3306
3307 if (cur->type == XML_ENTITY_DECL) {
3308 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3309 switch (tmp->etype) {
3310 case XML_INTERNAL_GENERAL_ENTITY:
3311 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3312 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3313 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3314 break;
3315 case XML_INTERNAL_PARAMETER_ENTITY:
3316 case XML_EXTERNAL_PARAMETER_ENTITY:
3317 q = (xmlNodePtr)
3318 xmlGetParameterEntityFromDtd(ret, tmp->name);
3319 break;
3320 case XML_INTERNAL_PREDEFINED_ENTITY:
3321 break;
3322 }
3323 } else if (cur->type == XML_ELEMENT_DECL) {
3324 xmlElementPtr tmp = (xmlElementPtr) cur;
3325 q = (xmlNodePtr)
3326 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3327 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3328 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3329 q = (xmlNodePtr)
3330 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3331 } else if (cur->type == XML_COMMENT_NODE) {
3332 q = xmlCopyNode(cur, 0);
3333 }
3334
3335 if (q == NULL) {
3336 cur = cur->next;
3337 continue;
3338 }
3339
3340 if (p == NULL)
3341 ret->children = q;
3342 else
3343 p->next = q;
3344
3345 q->prev = p;
3346 q->parent = (xmlNodePtr) ret;
3347 q->next = NULL;
3348 ret->last = q;
3349 p = q;
3350 cur = cur->next;
3351 }
3352
Owen Taylor3473f882001-02-23 17:55:21 +00003353 return(ret);
3354}
3355
3356/**
3357 * xmlCopyDoc:
3358 * @doc: the document
3359 * @recursive: if 1 do a recursive copy.
3360 *
3361 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003362 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003363 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003364 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003365 */
3366xmlDocPtr
3367xmlCopyDoc(xmlDocPtr doc, int recursive) {
3368 xmlDocPtr ret;
3369
3370 if (doc == NULL) return(NULL);
3371 ret = xmlNewDoc(doc->version);
3372 if (ret == NULL) return(NULL);
3373 if (doc->name != NULL)
3374 ret->name = xmlMemStrdup(doc->name);
3375 if (doc->encoding != NULL)
3376 ret->encoding = xmlStrdup(doc->encoding);
3377 ret->charset = doc->charset;
3378 ret->compression = doc->compression;
3379 ret->standalone = doc->standalone;
3380 if (!recursive) return(ret);
3381
Daniel Veillardb33c2012001-04-25 12:59:04 +00003382 ret->last = NULL;
3383 ret->children = NULL;
3384 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003385 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003386 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003387 ret->intSubset->parent = ret;
3388 }
Owen Taylor3473f882001-02-23 17:55:21 +00003389 if (doc->oldNs != NULL)
3390 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3391 if (doc->children != NULL) {
3392 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003393
3394 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3395 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003396 ret->last = NULL;
3397 tmp = ret->children;
3398 while (tmp != NULL) {
3399 if (tmp->next == NULL)
3400 ret->last = tmp;
3401 tmp = tmp->next;
3402 }
3403 }
3404 return(ret);
3405}
3406
3407/************************************************************************
3408 * *
3409 * Content access functions *
3410 * *
3411 ************************************************************************/
3412
3413/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003414 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003415 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003416 *
3417 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003418 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003419 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003420 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003421 */
3422long
3423xmlGetLineNo(xmlNodePtr node)
3424{
3425 long result = -1;
3426
3427 if (!node)
3428 return result;
3429 if (node->type == XML_ELEMENT_NODE)
3430 result = (long) node->content;
3431 else if ((node->prev != NULL) &&
3432 ((node->prev->type == XML_ELEMENT_NODE) ||
3433 (node->prev->type == XML_TEXT_NODE)))
3434 result = xmlGetLineNo(node->prev);
3435 else if ((node->parent != NULL) &&
3436 ((node->parent->type == XML_ELEMENT_NODE) ||
3437 (node->parent->type == XML_TEXT_NODE)))
3438 result = xmlGetLineNo(node->parent);
3439
3440 return result;
3441}
3442
3443/**
3444 * xmlGetNodePath:
3445 * @node: a node
3446 *
3447 * Build a structure based Path for the given node
3448 *
3449 * Returns the new path or NULL in case of error. The caller must free
3450 * the returned string
3451 */
3452xmlChar *
3453xmlGetNodePath(xmlNodePtr node)
3454{
3455 xmlNodePtr cur, tmp, next;
3456 xmlChar *buffer = NULL, *temp;
3457 size_t buf_len;
3458 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003459 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003460 const char *name;
3461 char nametemp[100];
3462 int occur = 0;
3463
3464 if (node == NULL)
3465 return (NULL);
3466
3467 buf_len = 500;
3468 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3469 if (buffer == NULL)
3470 return (NULL);
3471 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3472 if (buf == NULL) {
3473 xmlFree(buffer);
3474 return (NULL);
3475 }
3476
3477 buffer[0] = 0;
3478 cur = node;
3479 do {
3480 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003481 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003482 occur = 0;
3483 if ((cur->type == XML_DOCUMENT_NODE) ||
3484 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3485 if (buffer[0] == '/')
3486 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003487 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003488 next = NULL;
3489 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003490 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003491 name = (const char *) cur->name;
3492 if (cur->ns) {
3493 snprintf(nametemp, sizeof(nametemp) - 1,
3494 "%s:%s", cur->ns->prefix, cur->name);
3495 nametemp[sizeof(nametemp) - 1] = 0;
3496 name = nametemp;
3497 }
3498 next = cur->parent;
3499
3500 /*
3501 * Thumbler index computation
3502 */
3503 tmp = cur->prev;
3504 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003505 if ((tmp->type == XML_ELEMENT_NODE) &&
3506 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003507 occur++;
3508 tmp = tmp->prev;
3509 }
3510 if (occur == 0) {
3511 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003512 while (tmp != NULL && occur == 0) {
3513 if ((tmp->type == XML_ELEMENT_NODE) &&
3514 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003515 occur++;
3516 tmp = tmp->next;
3517 }
3518 if (occur != 0)
3519 occur = 1;
3520 } else
3521 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003522 } else if (cur->type == XML_COMMENT_NODE) {
3523 sep = "/";
3524 name = "comment()";
3525 next = cur->parent;
3526
3527 /*
3528 * Thumbler index computation
3529 */
3530 tmp = cur->prev;
3531 while (tmp != NULL) {
3532 if (tmp->type == XML_COMMENT_NODE)
3533 occur++;
3534 tmp = tmp->prev;
3535 }
3536 if (occur == 0) {
3537 tmp = cur->next;
3538 while (tmp != NULL && occur == 0) {
3539 if (tmp->type == XML_COMMENT_NODE)
3540 occur++;
3541 tmp = tmp->next;
3542 }
3543 if (occur != 0)
3544 occur = 1;
3545 } else
3546 occur++;
3547 } else if ((cur->type == XML_TEXT_NODE) ||
3548 (cur->type == XML_CDATA_SECTION_NODE)) {
3549 sep = "/";
3550 name = "text()";
3551 next = cur->parent;
3552
3553 /*
3554 * Thumbler index computation
3555 */
3556 tmp = cur->prev;
3557 while (tmp != NULL) {
3558 if ((cur->type == XML_TEXT_NODE) ||
3559 (cur->type == XML_CDATA_SECTION_NODE))
3560 occur++;
3561 tmp = tmp->prev;
3562 }
3563 if (occur == 0) {
3564 tmp = cur->next;
3565 while (tmp != NULL && occur == 0) {
3566 if ((cur->type == XML_TEXT_NODE) ||
3567 (cur->type == XML_CDATA_SECTION_NODE))
3568 occur++;
3569 tmp = tmp->next;
3570 }
3571 if (occur != 0)
3572 occur = 1;
3573 } else
3574 occur++;
3575 } else if (cur->type == XML_PI_NODE) {
3576 sep = "/";
3577 snprintf(nametemp, sizeof(nametemp) - 1,
3578 "processing-instruction('%s')", cur->name);
3579 nametemp[sizeof(nametemp) - 1] = 0;
3580 name = nametemp;
3581
3582 next = cur->parent;
3583
3584 /*
3585 * Thumbler index computation
3586 */
3587 tmp = cur->prev;
3588 while (tmp != NULL) {
3589 if ((tmp->type == XML_PI_NODE) &&
3590 (xmlStrEqual(cur->name, tmp->name)))
3591 occur++;
3592 tmp = tmp->prev;
3593 }
3594 if (occur == 0) {
3595 tmp = cur->next;
3596 while (tmp != NULL && occur == 0) {
3597 if ((tmp->type == XML_PI_NODE) &&
3598 (xmlStrEqual(cur->name, tmp->name)))
3599 occur++;
3600 tmp = tmp->next;
3601 }
3602 if (occur != 0)
3603 occur = 1;
3604 } else
3605 occur++;
3606
Daniel Veillard8faa7832001-11-26 15:58:08 +00003607 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003608 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003609 name = (const char *) (((xmlAttrPtr) cur)->name);
3610 next = ((xmlAttrPtr) cur)->parent;
3611 } else {
3612 next = cur->parent;
3613 }
3614
3615 /*
3616 * Make sure there is enough room
3617 */
3618 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3619 buf_len =
3620 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3621 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3622 if (temp == NULL) {
3623 xmlFree(buf);
3624 xmlFree(buffer);
3625 return (NULL);
3626 }
3627 buffer = temp;
3628 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3629 if (temp == NULL) {
3630 xmlFree(buf);
3631 xmlFree(buffer);
3632 return (NULL);
3633 }
3634 buf = temp;
3635 }
3636 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003637 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003638 sep, name, (char *) buffer);
3639 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003640 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003641 sep, name, occur, (char *) buffer);
3642 snprintf((char *) buffer, buf_len, "%s", buf);
3643 cur = next;
3644 } while (cur != NULL);
3645 xmlFree(buf);
3646 return (buffer);
3647}
3648
3649/**
Owen Taylor3473f882001-02-23 17:55:21 +00003650 * xmlDocGetRootElement:
3651 * @doc: the document
3652 *
3653 * Get the root element of the document (doc->children is a list
3654 * containing possibly comments, PIs, etc ...).
3655 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003656 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003657 */
3658xmlNodePtr
3659xmlDocGetRootElement(xmlDocPtr doc) {
3660 xmlNodePtr ret;
3661
3662 if (doc == NULL) return(NULL);
3663 ret = doc->children;
3664 while (ret != NULL) {
3665 if (ret->type == XML_ELEMENT_NODE)
3666 return(ret);
3667 ret = ret->next;
3668 }
3669 return(ret);
3670}
3671
3672/**
3673 * xmlDocSetRootElement:
3674 * @doc: the document
3675 * @root: the new document root element
3676 *
3677 * Set the root element of the document (doc->children is a list
3678 * containing possibly comments, PIs, etc ...).
3679 *
3680 * Returns the old root element if any was found
3681 */
3682xmlNodePtr
3683xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3684 xmlNodePtr old = NULL;
3685
3686 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003687 if (root == NULL)
3688 return(NULL);
3689 xmlUnlinkNode(root);
3690 root->doc = doc;
3691 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003692 old = doc->children;
3693 while (old != NULL) {
3694 if (old->type == XML_ELEMENT_NODE)
3695 break;
3696 old = old->next;
3697 }
3698 if (old == NULL) {
3699 if (doc->children == NULL) {
3700 doc->children = root;
3701 doc->last = root;
3702 } else {
3703 xmlAddSibling(doc->children, root);
3704 }
3705 } else {
3706 xmlReplaceNode(old, root);
3707 }
3708 return(old);
3709}
3710
3711/**
3712 * xmlNodeSetLang:
3713 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003714 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003715 *
3716 * Set the language of a node, i.e. the values of the xml:lang
3717 * attribute.
3718 */
3719void
3720xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003721 xmlNsPtr ns;
3722
Owen Taylor3473f882001-02-23 17:55:21 +00003723 if (cur == NULL) return;
3724 switch(cur->type) {
3725 case XML_TEXT_NODE:
3726 case XML_CDATA_SECTION_NODE:
3727 case XML_COMMENT_NODE:
3728 case XML_DOCUMENT_NODE:
3729 case XML_DOCUMENT_TYPE_NODE:
3730 case XML_DOCUMENT_FRAG_NODE:
3731 case XML_NOTATION_NODE:
3732 case XML_HTML_DOCUMENT_NODE:
3733 case XML_DTD_NODE:
3734 case XML_ELEMENT_DECL:
3735 case XML_ATTRIBUTE_DECL:
3736 case XML_ENTITY_DECL:
3737 case XML_PI_NODE:
3738 case XML_ENTITY_REF_NODE:
3739 case XML_ENTITY_NODE:
3740 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003741#ifdef LIBXML_DOCB_ENABLED
3742 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003743#endif
3744 case XML_XINCLUDE_START:
3745 case XML_XINCLUDE_END:
3746 return;
3747 case XML_ELEMENT_NODE:
3748 case XML_ATTRIBUTE_NODE:
3749 break;
3750 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003751 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3752 if (ns == NULL)
3753 return;
3754 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003755}
3756
3757/**
3758 * xmlNodeGetLang:
3759 * @cur: the node being checked
3760 *
3761 * Searches the language of a node, i.e. the values of the xml:lang
3762 * attribute or the one carried by the nearest ancestor.
3763 *
3764 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003765 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003766 */
3767xmlChar *
3768xmlNodeGetLang(xmlNodePtr cur) {
3769 xmlChar *lang;
3770
3771 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003772 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003773 if (lang != NULL)
3774 return(lang);
3775 cur = cur->parent;
3776 }
3777 return(NULL);
3778}
3779
3780
3781/**
3782 * xmlNodeSetSpacePreserve:
3783 * @cur: the node being changed
3784 * @val: the xml:space value ("0": default, 1: "preserve")
3785 *
3786 * Set (or reset) the space preserving behaviour of a node, i.e. the
3787 * value of the xml:space attribute.
3788 */
3789void
3790xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003791 xmlNsPtr ns;
3792
Owen Taylor3473f882001-02-23 17:55:21 +00003793 if (cur == NULL) return;
3794 switch(cur->type) {
3795 case XML_TEXT_NODE:
3796 case XML_CDATA_SECTION_NODE:
3797 case XML_COMMENT_NODE:
3798 case XML_DOCUMENT_NODE:
3799 case XML_DOCUMENT_TYPE_NODE:
3800 case XML_DOCUMENT_FRAG_NODE:
3801 case XML_NOTATION_NODE:
3802 case XML_HTML_DOCUMENT_NODE:
3803 case XML_DTD_NODE:
3804 case XML_ELEMENT_DECL:
3805 case XML_ATTRIBUTE_DECL:
3806 case XML_ENTITY_DECL:
3807 case XML_PI_NODE:
3808 case XML_ENTITY_REF_NODE:
3809 case XML_ENTITY_NODE:
3810 case XML_NAMESPACE_DECL:
3811 case XML_XINCLUDE_START:
3812 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003813#ifdef LIBXML_DOCB_ENABLED
3814 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003815#endif
3816 return;
3817 case XML_ELEMENT_NODE:
3818 case XML_ATTRIBUTE_NODE:
3819 break;
3820 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003821 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3822 if (ns == NULL)
3823 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003824 switch (val) {
3825 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003826 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003827 break;
3828 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003829 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003830 break;
3831 }
3832}
3833
3834/**
3835 * xmlNodeGetSpacePreserve:
3836 * @cur: the node being checked
3837 *
3838 * Searches the space preserving behaviour of a node, i.e. the values
3839 * of the xml:space attribute or the one carried by the nearest
3840 * ancestor.
3841 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003842 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003843 */
3844int
3845xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3846 xmlChar *space;
3847
3848 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003849 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003850 if (space != NULL) {
3851 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3852 xmlFree(space);
3853 return(1);
3854 }
3855 if (xmlStrEqual(space, BAD_CAST "default")) {
3856 xmlFree(space);
3857 return(0);
3858 }
3859 xmlFree(space);
3860 }
3861 cur = cur->parent;
3862 }
3863 return(-1);
3864}
3865
3866/**
3867 * xmlNodeSetName:
3868 * @cur: the node being changed
3869 * @name: the new tag name
3870 *
3871 * Set (or reset) the name of a node.
3872 */
3873void
3874xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3875 if (cur == NULL) return;
3876 if (name == NULL) return;
3877 switch(cur->type) {
3878 case XML_TEXT_NODE:
3879 case XML_CDATA_SECTION_NODE:
3880 case XML_COMMENT_NODE:
3881 case XML_DOCUMENT_TYPE_NODE:
3882 case XML_DOCUMENT_FRAG_NODE:
3883 case XML_NOTATION_NODE:
3884 case XML_HTML_DOCUMENT_NODE:
3885 case XML_NAMESPACE_DECL:
3886 case XML_XINCLUDE_START:
3887 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003888#ifdef LIBXML_DOCB_ENABLED
3889 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003890#endif
3891 return;
3892 case XML_ELEMENT_NODE:
3893 case XML_ATTRIBUTE_NODE:
3894 case XML_PI_NODE:
3895 case XML_ENTITY_REF_NODE:
3896 case XML_ENTITY_NODE:
3897 case XML_DTD_NODE:
3898 case XML_DOCUMENT_NODE:
3899 case XML_ELEMENT_DECL:
3900 case XML_ATTRIBUTE_DECL:
3901 case XML_ENTITY_DECL:
3902 break;
3903 }
3904 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3905 cur->name = xmlStrdup(name);
3906}
3907
3908/**
3909 * xmlNodeSetBase:
3910 * @cur: the node being changed
3911 * @uri: the new base URI
3912 *
3913 * Set (or reset) the base URI of a node, i.e. the value of the
3914 * xml:base attribute.
3915 */
3916void
3917xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003918 xmlNsPtr ns;
3919
Owen Taylor3473f882001-02-23 17:55:21 +00003920 if (cur == NULL) return;
3921 switch(cur->type) {
3922 case XML_TEXT_NODE:
3923 case XML_CDATA_SECTION_NODE:
3924 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003925 case XML_DOCUMENT_TYPE_NODE:
3926 case XML_DOCUMENT_FRAG_NODE:
3927 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003928 case XML_DTD_NODE:
3929 case XML_ELEMENT_DECL:
3930 case XML_ATTRIBUTE_DECL:
3931 case XML_ENTITY_DECL:
3932 case XML_PI_NODE:
3933 case XML_ENTITY_REF_NODE:
3934 case XML_ENTITY_NODE:
3935 case XML_NAMESPACE_DECL:
3936 case XML_XINCLUDE_START:
3937 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003938 return;
3939 case XML_ELEMENT_NODE:
3940 case XML_ATTRIBUTE_NODE:
3941 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003942 case XML_DOCUMENT_NODE:
3943#ifdef LIBXML_DOCB_ENABLED
3944 case XML_DOCB_DOCUMENT_NODE:
3945#endif
3946 case XML_HTML_DOCUMENT_NODE: {
3947 xmlDocPtr doc = (xmlDocPtr) cur;
3948
3949 if (doc->URL != NULL)
3950 xmlFree((xmlChar *) doc->URL);
3951 if (uri == NULL)
3952 doc->URL = NULL;
3953 else
3954 doc->URL = xmlStrdup(uri);
3955 return;
3956 }
Owen Taylor3473f882001-02-23 17:55:21 +00003957 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003958
3959 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3960 if (ns == NULL)
3961 return;
3962 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003963}
3964
3965/**
Owen Taylor3473f882001-02-23 17:55:21 +00003966 * xmlNodeGetBase:
3967 * @doc: the document the node pertains to
3968 * @cur: the node being checked
3969 *
3970 * Searches for the BASE URL. The code should work on both XML
3971 * and HTML document even if base mechanisms are completely different.
3972 * It returns the base as defined in RFC 2396 sections
3973 * 5.1.1. Base URI within Document Content
3974 * and
3975 * 5.1.2. Base URI from the Encapsulating Entity
3976 * However it does not return the document base (5.1.3), use
3977 * xmlDocumentGetBase() for this
3978 *
3979 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003980 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003981 */
3982xmlChar *
3983xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003984 xmlChar *oldbase = NULL;
3985 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003986
3987 if ((cur == NULL) && (doc == NULL))
3988 return(NULL);
3989 if (doc == NULL) doc = cur->doc;
3990 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3991 cur = doc->children;
3992 while ((cur != NULL) && (cur->name != NULL)) {
3993 if (cur->type != XML_ELEMENT_NODE) {
3994 cur = cur->next;
3995 continue;
3996 }
3997 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3998 cur = cur->children;
3999 continue;
4000 }
4001 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4002 cur = cur->children;
4003 continue;
4004 }
4005 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4006 return(xmlGetProp(cur, BAD_CAST "href"));
4007 }
4008 cur = cur->next;
4009 }
4010 return(NULL);
4011 }
4012 while (cur != NULL) {
4013 if (cur->type == XML_ENTITY_DECL) {
4014 xmlEntityPtr ent = (xmlEntityPtr) cur;
4015 return(xmlStrdup(ent->URI));
4016 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004017 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004018 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004019 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004020 if (oldbase != NULL) {
4021 newbase = xmlBuildURI(oldbase, base);
4022 if (newbase != NULL) {
4023 xmlFree(oldbase);
4024 xmlFree(base);
4025 oldbase = newbase;
4026 } else {
4027 xmlFree(oldbase);
4028 xmlFree(base);
4029 return(NULL);
4030 }
4031 } else {
4032 oldbase = base;
4033 }
4034 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4035 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4036 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4037 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004038 }
4039 }
Owen Taylor3473f882001-02-23 17:55:21 +00004040 cur = cur->parent;
4041 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004042 if ((doc != NULL) && (doc->URL != NULL)) {
4043 if (oldbase == NULL)
4044 return(xmlStrdup(doc->URL));
4045 newbase = xmlBuildURI(oldbase, doc->URL);
4046 xmlFree(oldbase);
4047 return(newbase);
4048 }
4049 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004050}
4051
4052/**
4053 * xmlNodeGetContent:
4054 * @cur: the node being read
4055 *
4056 * Read the value of a node, this can be either the text carried
4057 * directly by this node if it's a TEXT node or the aggregate string
4058 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004059 * Entity references are substituted.
4060 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004061 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004062 */
4063xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004064xmlNodeGetContent(xmlNodePtr cur)
4065{
4066 if (cur == NULL)
4067 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004068 switch (cur->type) {
4069 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004070 case XML_ELEMENT_NODE:{
4071 xmlNodePtr tmp = cur;
4072 xmlBufferPtr buffer;
4073 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004074
Daniel Veillard7646b182002-04-20 06:41:40 +00004075 buffer = xmlBufferCreate();
4076 if (buffer == NULL)
4077 return (NULL);
4078 while (tmp != NULL) {
4079 switch (tmp->type) {
4080 case XML_CDATA_SECTION_NODE:
4081 case XML_TEXT_NODE:
4082 if (tmp->content != NULL)
4083 xmlBufferCat(buffer, tmp->content);
4084 break;
4085 case XML_ENTITY_REF_NODE:{
4086 /* recursive substitution of entity references */
4087 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004088
Daniel Veillard7646b182002-04-20 06:41:40 +00004089 if (cont) {
4090 xmlBufferCat(buffer,
4091 (const xmlChar *) cont);
4092 xmlFree(cont);
4093 }
4094 break;
4095 }
4096 default:
4097 break;
4098 }
4099 /*
4100 * Skip to next node
4101 */
4102 if (tmp->children != NULL) {
4103 if (tmp->children->type != XML_ENTITY_DECL) {
4104 tmp = tmp->children;
4105 continue;
4106 }
4107 }
4108 if (tmp == cur)
4109 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004110
Daniel Veillard7646b182002-04-20 06:41:40 +00004111 if (tmp->next != NULL) {
4112 tmp = tmp->next;
4113 continue;
4114 }
4115
4116 do {
4117 tmp = tmp->parent;
4118 if (tmp == NULL)
4119 break;
4120 if (tmp == cur) {
4121 tmp = NULL;
4122 break;
4123 }
4124 if (tmp->next != NULL) {
4125 tmp = tmp->next;
4126 break;
4127 }
4128 } while (tmp != NULL);
4129 }
4130 ret = buffer->content;
4131 buffer->content = NULL;
4132 xmlBufferFree(buffer);
4133 return (ret);
4134 }
4135 case XML_ATTRIBUTE_NODE:{
4136 xmlAttrPtr attr = (xmlAttrPtr) cur;
4137
4138 if (attr->parent != NULL)
4139 return (xmlNodeListGetString
4140 (attr->parent->doc, attr->children, 1));
4141 else
4142 return (xmlNodeListGetString(NULL, attr->children, 1));
4143 break;
4144 }
Owen Taylor3473f882001-02-23 17:55:21 +00004145 case XML_COMMENT_NODE:
4146 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004147 if (cur->content != NULL)
4148 return (xmlStrdup(cur->content));
4149 return (NULL);
4150 case XML_ENTITY_REF_NODE:{
4151 xmlEntityPtr ent;
4152 xmlNodePtr tmp;
4153 xmlBufferPtr buffer;
4154 xmlChar *ret;
4155
4156 /* lookup entity declaration */
4157 ent = xmlGetDocEntity(cur->doc, cur->name);
4158 if (ent == NULL)
4159 return (NULL);
4160
4161 buffer = xmlBufferCreate();
4162 if (buffer == NULL)
4163 return (NULL);
4164
4165 /* an entity content can be any "well balanced chunk",
4166 * i.e. the result of the content [43] production:
4167 * http://www.w3.org/TR/REC-xml#NT-content
4168 * -> we iterate through child nodes and recursive call
4169 * xmlNodeGetContent() which handles all possible node types */
4170 tmp = ent->children;
4171 while (tmp) {
4172 xmlChar *cont = xmlNodeGetContent(tmp);
4173
4174 if (cont) {
4175 xmlBufferCat(buffer, (const xmlChar *) cont);
4176 xmlFree(cont);
4177 }
4178 tmp = tmp->next;
4179 }
4180
4181 ret = buffer->content;
4182 buffer->content = NULL;
4183 xmlBufferFree(buffer);
4184 return (ret);
4185 }
Owen Taylor3473f882001-02-23 17:55:21 +00004186 case XML_ENTITY_NODE:
4187 case XML_DOCUMENT_NODE:
4188 case XML_HTML_DOCUMENT_NODE:
4189 case XML_DOCUMENT_TYPE_NODE:
4190 case XML_NOTATION_NODE:
4191 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004192 case XML_XINCLUDE_START:
4193 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004194#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004195 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004196#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004197 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004198 case XML_NAMESPACE_DECL: {
4199 xmlChar *tmp;
4200
4201 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4202 return (tmp);
4203 }
Owen Taylor3473f882001-02-23 17:55:21 +00004204 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004205 /* TODO !!! */
4206 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004207 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004208 /* TODO !!! */
4209 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004210 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004211 /* TODO !!! */
4212 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004213 case XML_CDATA_SECTION_NODE:
4214 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004215 if (cur->content != NULL)
4216 return (xmlStrdup(cur->content));
4217 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004218 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004219 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004220}
Owen Taylor3473f882001-02-23 17:55:21 +00004221/**
4222 * xmlNodeSetContent:
4223 * @cur: the node being modified
4224 * @content: the new value of the content
4225 *
4226 * Replace the content of a node.
4227 */
4228void
4229xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4230 if (cur == NULL) {
4231#ifdef DEBUG_TREE
4232 xmlGenericError(xmlGenericErrorContext,
4233 "xmlNodeSetContent : node == NULL\n");
4234#endif
4235 return;
4236 }
4237 switch (cur->type) {
4238 case XML_DOCUMENT_FRAG_NODE:
4239 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004240 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004241 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4242 cur->children = xmlStringGetNodeList(cur->doc, content);
4243 UPDATE_LAST_CHILD_AND_PARENT(cur)
4244 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004245 case XML_TEXT_NODE:
4246 case XML_CDATA_SECTION_NODE:
4247 case XML_ENTITY_REF_NODE:
4248 case XML_ENTITY_NODE:
4249 case XML_PI_NODE:
4250 case XML_COMMENT_NODE:
4251 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004252 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004253 }
4254 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4255 cur->last = cur->children = NULL;
4256 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004257 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004258 } else
4259 cur->content = NULL;
4260 break;
4261 case XML_DOCUMENT_NODE:
4262 case XML_HTML_DOCUMENT_NODE:
4263 case XML_DOCUMENT_TYPE_NODE:
4264 case XML_XINCLUDE_START:
4265 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004266#ifdef LIBXML_DOCB_ENABLED
4267 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004268#endif
4269 break;
4270 case XML_NOTATION_NODE:
4271 break;
4272 case XML_DTD_NODE:
4273 break;
4274 case XML_NAMESPACE_DECL:
4275 break;
4276 case XML_ELEMENT_DECL:
4277 /* TODO !!! */
4278 break;
4279 case XML_ATTRIBUTE_DECL:
4280 /* TODO !!! */
4281 break;
4282 case XML_ENTITY_DECL:
4283 /* TODO !!! */
4284 break;
4285 }
4286}
4287
4288/**
4289 * xmlNodeSetContentLen:
4290 * @cur: the node being modified
4291 * @content: the new value of the content
4292 * @len: the size of @content
4293 *
4294 * Replace the content of a node.
4295 */
4296void
4297xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4298 if (cur == NULL) {
4299#ifdef DEBUG_TREE
4300 xmlGenericError(xmlGenericErrorContext,
4301 "xmlNodeSetContentLen : node == NULL\n");
4302#endif
4303 return;
4304 }
4305 switch (cur->type) {
4306 case XML_DOCUMENT_FRAG_NODE:
4307 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004308 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004309 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4310 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4311 UPDATE_LAST_CHILD_AND_PARENT(cur)
4312 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004313 case XML_TEXT_NODE:
4314 case XML_CDATA_SECTION_NODE:
4315 case XML_ENTITY_REF_NODE:
4316 case XML_ENTITY_NODE:
4317 case XML_PI_NODE:
4318 case XML_COMMENT_NODE:
4319 case XML_NOTATION_NODE:
4320 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004321 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004322 }
4323 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4324 cur->children = cur->last = NULL;
4325 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004326 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004327 } else
4328 cur->content = NULL;
4329 break;
4330 case XML_DOCUMENT_NODE:
4331 case XML_DTD_NODE:
4332 case XML_HTML_DOCUMENT_NODE:
4333 case XML_DOCUMENT_TYPE_NODE:
4334 case XML_NAMESPACE_DECL:
4335 case XML_XINCLUDE_START:
4336 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004337#ifdef LIBXML_DOCB_ENABLED
4338 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004339#endif
4340 break;
4341 case XML_ELEMENT_DECL:
4342 /* TODO !!! */
4343 break;
4344 case XML_ATTRIBUTE_DECL:
4345 /* TODO !!! */
4346 break;
4347 case XML_ENTITY_DECL:
4348 /* TODO !!! */
4349 break;
4350 }
4351}
4352
4353/**
4354 * xmlNodeAddContentLen:
4355 * @cur: the node being modified
4356 * @content: extra content
4357 * @len: the size of @content
4358 *
4359 * Append the extra substring to the node content.
4360 */
4361void
4362xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4363 if (cur == NULL) {
4364#ifdef DEBUG_TREE
4365 xmlGenericError(xmlGenericErrorContext,
4366 "xmlNodeAddContentLen : node == NULL\n");
4367#endif
4368 return;
4369 }
4370 if (len <= 0) return;
4371 switch (cur->type) {
4372 case XML_DOCUMENT_FRAG_NODE:
4373 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004374 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004375
Daniel Veillard7db37732001-07-12 01:20:08 +00004376 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004377 newNode = xmlNewTextLen(content, len);
4378 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004379 tmp = xmlAddChild(cur, newNode);
4380 if (tmp != newNode)
4381 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004382 if ((last != NULL) && (last->next == newNode)) {
4383 xmlTextMerge(last, newNode);
4384 }
4385 }
4386 break;
4387 }
4388 case XML_ATTRIBUTE_NODE:
4389 break;
4390 case XML_TEXT_NODE:
4391 case XML_CDATA_SECTION_NODE:
4392 case XML_ENTITY_REF_NODE:
4393 case XML_ENTITY_NODE:
4394 case XML_PI_NODE:
4395 case XML_COMMENT_NODE:
4396 case XML_NOTATION_NODE:
4397 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004398 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004399 }
4400 case XML_DOCUMENT_NODE:
4401 case XML_DTD_NODE:
4402 case XML_HTML_DOCUMENT_NODE:
4403 case XML_DOCUMENT_TYPE_NODE:
4404 case XML_NAMESPACE_DECL:
4405 case XML_XINCLUDE_START:
4406 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004407#ifdef LIBXML_DOCB_ENABLED
4408 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004409#endif
4410 break;
4411 case XML_ELEMENT_DECL:
4412 case XML_ATTRIBUTE_DECL:
4413 case XML_ENTITY_DECL:
4414 break;
4415 }
4416}
4417
4418/**
4419 * xmlNodeAddContent:
4420 * @cur: the node being modified
4421 * @content: extra content
4422 *
4423 * Append the extra substring to the node content.
4424 */
4425void
4426xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4427 int len;
4428
4429 if (cur == NULL) {
4430#ifdef DEBUG_TREE
4431 xmlGenericError(xmlGenericErrorContext,
4432 "xmlNodeAddContent : node == NULL\n");
4433#endif
4434 return;
4435 }
4436 if (content == NULL) return;
4437 len = xmlStrlen(content);
4438 xmlNodeAddContentLen(cur, content, len);
4439}
4440
4441/**
4442 * xmlTextMerge:
4443 * @first: the first text node
4444 * @second: the second text node being merged
4445 *
4446 * Merge two text nodes into one
4447 * Returns the first text node augmented
4448 */
4449xmlNodePtr
4450xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4451 if (first == NULL) return(second);
4452 if (second == NULL) return(first);
4453 if (first->type != XML_TEXT_NODE) return(first);
4454 if (second->type != XML_TEXT_NODE) return(first);
4455 if (second->name != first->name)
4456 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004457 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004458 xmlUnlinkNode(second);
4459 xmlFreeNode(second);
4460 return(first);
4461}
4462
4463/**
4464 * xmlGetNsList:
4465 * @doc: the document
4466 * @node: the current node
4467 *
4468 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004469 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004470 * that need to be freed by the caller or NULL if no
4471 * namespace if defined
4472 */
4473xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004474xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4475{
Owen Taylor3473f882001-02-23 17:55:21 +00004476 xmlNsPtr cur;
4477 xmlNsPtr *ret = NULL;
4478 int nbns = 0;
4479 int maxns = 10;
4480 int i;
4481
4482 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004483 if (node->type == XML_ELEMENT_NODE) {
4484 cur = node->nsDef;
4485 while (cur != NULL) {
4486 if (ret == NULL) {
4487 ret =
4488 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4489 sizeof(xmlNsPtr));
4490 if (ret == NULL) {
4491 xmlGenericError(xmlGenericErrorContext,
4492 "xmlGetNsList : out of memory!\n");
4493 return (NULL);
4494 }
4495 ret[nbns] = NULL;
4496 }
4497 for (i = 0; i < nbns; i++) {
4498 if ((cur->prefix == ret[i]->prefix) ||
4499 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4500 break;
4501 }
4502 if (i >= nbns) {
4503 if (nbns >= maxns) {
4504 maxns *= 2;
4505 ret = (xmlNsPtr *) xmlRealloc(ret,
4506 (maxns +
4507 1) *
4508 sizeof(xmlNsPtr));
4509 if (ret == NULL) {
4510 xmlGenericError(xmlGenericErrorContext,
4511 "xmlGetNsList : realloc failed!\n");
4512 return (NULL);
4513 }
4514 }
4515 ret[nbns++] = cur;
4516 ret[nbns] = NULL;
4517 }
Owen Taylor3473f882001-02-23 17:55:21 +00004518
Daniel Veillard77044732001-06-29 21:31:07 +00004519 cur = cur->next;
4520 }
4521 }
4522 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004523 }
Daniel Veillard77044732001-06-29 21:31:07 +00004524 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004525}
4526
4527/**
4528 * xmlSearchNs:
4529 * @doc: the document
4530 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004531 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004532 *
4533 * Search a Ns registered under a given name space for a document.
4534 * recurse on the parents until it finds the defined namespace
4535 * or return NULL otherwise.
4536 * @nameSpace can be NULL, this is a search for the default namespace.
4537 * We don't allow to cross entities boundaries. If you don't declare
4538 * the namespace within those you will be in troubles !!! A warning
4539 * is generated to cover this case.
4540 *
4541 * Returns the namespace pointer or NULL.
4542 */
4543xmlNsPtr
4544xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4545 xmlNsPtr cur;
4546
4547 if (node == NULL) return(NULL);
4548 if ((nameSpace != NULL) &&
4549 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004550 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4551 /*
4552 * The XML-1.0 namespace is normally held on the root
4553 * element. In this case exceptionally create it on the
4554 * node element.
4555 */
4556 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4557 if (cur == NULL) {
4558 xmlGenericError(xmlGenericErrorContext,
4559 "xmlSearchNs : malloc failed\n");
4560 return(NULL);
4561 }
4562 memset(cur, 0, sizeof(xmlNs));
4563 cur->type = XML_LOCAL_NAMESPACE;
4564 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4565 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4566 cur->next = node->nsDef;
4567 node->nsDef = cur;
4568 return(cur);
4569 }
Owen Taylor3473f882001-02-23 17:55:21 +00004570 if (doc->oldNs == NULL) {
4571 /*
4572 * Allocate a new Namespace and fill the fields.
4573 */
4574 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4575 if (doc->oldNs == NULL) {
4576 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004577 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004578 return(NULL);
4579 }
4580 memset(doc->oldNs, 0, sizeof(xmlNs));
4581 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4582
4583 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4584 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4585 }
4586 return(doc->oldNs);
4587 }
4588 while (node != NULL) {
4589 if ((node->type == XML_ENTITY_REF_NODE) ||
4590 (node->type == XML_ENTITY_NODE) ||
4591 (node->type == XML_ENTITY_DECL))
4592 return(NULL);
4593 if (node->type == XML_ELEMENT_NODE) {
4594 cur = node->nsDef;
4595 while (cur != NULL) {
4596 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4597 (cur->href != NULL))
4598 return(cur);
4599 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4600 (cur->href != NULL) &&
4601 (xmlStrEqual(cur->prefix, nameSpace)))
4602 return(cur);
4603 cur = cur->next;
4604 }
4605 }
4606 node = node->parent;
4607 }
4608 return(NULL);
4609}
4610
4611/**
4612 * xmlSearchNsByHref:
4613 * @doc: the document
4614 * @node: the current node
4615 * @href: the namespace value
4616 *
4617 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4618 * the defined namespace or return NULL otherwise.
4619 * Returns the namespace pointer or NULL.
4620 */
4621xmlNsPtr
4622xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4623 xmlNsPtr cur;
4624 xmlNodePtr orig = node;
4625
4626 if ((node == NULL) || (href == NULL)) return(NULL);
4627 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004628 /*
4629 * Only the document can hold the XML spec namespace.
4630 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004631 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4632 /*
4633 * The XML-1.0 namespace is normally held on the root
4634 * element. In this case exceptionally create it on the
4635 * node element.
4636 */
4637 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4638 if (cur == NULL) {
4639 xmlGenericError(xmlGenericErrorContext,
4640 "xmlSearchNs : malloc failed\n");
4641 return(NULL);
4642 }
4643 memset(cur, 0, sizeof(xmlNs));
4644 cur->type = XML_LOCAL_NAMESPACE;
4645 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4646 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4647 cur->next = node->nsDef;
4648 node->nsDef = cur;
4649 return(cur);
4650 }
Owen Taylor3473f882001-02-23 17:55:21 +00004651 if (doc->oldNs == NULL) {
4652 /*
4653 * Allocate a new Namespace and fill the fields.
4654 */
4655 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4656 if (doc->oldNs == NULL) {
4657 xmlGenericError(xmlGenericErrorContext,
4658 "xmlSearchNsByHref : malloc failed\n");
4659 return(NULL);
4660 }
4661 memset(doc->oldNs, 0, sizeof(xmlNs));
4662 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4663
4664 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4665 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4666 }
4667 return(doc->oldNs);
4668 }
4669 while (node != NULL) {
4670 cur = node->nsDef;
4671 while (cur != NULL) {
4672 if ((cur->href != NULL) && (href != NULL) &&
4673 (xmlStrEqual(cur->href, href))) {
4674 /*
4675 * Check that the prefix is not shadowed between orig and node
4676 */
4677 xmlNodePtr check = orig;
4678 xmlNsPtr tst;
4679
4680 while (check != node) {
4681 tst = check->nsDef;
4682 while (tst != NULL) {
4683 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4684 goto shadowed;
4685 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4686 (xmlStrEqual(tst->prefix, cur->prefix)))
4687 goto shadowed;
4688 tst = tst->next;
4689 }
4690 check = check->parent;
4691 }
4692 return(cur);
4693 }
4694shadowed:
4695 cur = cur->next;
4696 }
4697 node = node->parent;
4698 }
4699 return(NULL);
4700}
4701
4702/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004703 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004704 * @doc: the document
4705 * @tree: a node expected to hold the new namespace
4706 * @ns: the original namespace
4707 *
4708 * This function tries to locate a namespace definition in a tree
4709 * ancestors, or create a new namespace definition node similar to
4710 * @ns trying to reuse the same prefix. However if the given prefix is
4711 * null (default namespace) or reused within the subtree defined by
4712 * @tree or on one of its ancestors then a new prefix is generated.
4713 * Returns the (new) namespace definition or NULL in case of error
4714 */
4715xmlNsPtr
4716xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4717 xmlNsPtr def;
4718 xmlChar prefix[50];
4719 int counter = 1;
4720
4721 if (tree == NULL) {
4722#ifdef DEBUG_TREE
4723 xmlGenericError(xmlGenericErrorContext,
4724 "xmlNewReconciliedNs : tree == NULL\n");
4725#endif
4726 return(NULL);
4727 }
4728 if (ns == NULL) {
4729#ifdef DEBUG_TREE
4730 xmlGenericError(xmlGenericErrorContext,
4731 "xmlNewReconciliedNs : ns == NULL\n");
4732#endif
4733 return(NULL);
4734 }
4735 /*
4736 * Search an existing namespace definition inherited.
4737 */
4738 def = xmlSearchNsByHref(doc, tree, ns->href);
4739 if (def != NULL)
4740 return(def);
4741
4742 /*
4743 * Find a close prefix which is not already in use.
4744 * Let's strip namespace prefixes longer than 20 chars !
4745 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004746 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004747 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004748 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004749 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004750
Owen Taylor3473f882001-02-23 17:55:21 +00004751 def = xmlSearchNs(doc, tree, prefix);
4752 while (def != NULL) {
4753 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004754 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004755 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004756 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004757 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004758 def = xmlSearchNs(doc, tree, prefix);
4759 }
4760
4761 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004762 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004763 */
4764 def = xmlNewNs(tree, ns->href, prefix);
4765 return(def);
4766}
4767
4768/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004769 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004770 * @doc: the document
4771 * @tree: a node defining the subtree to reconciliate
4772 *
4773 * This function checks that all the namespaces declared within the given
4774 * tree are properly declared. This is needed for example after Copy or Cut
4775 * and then paste operations. The subtree may still hold pointers to
4776 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004777 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004778 * the new environment. If not possible the new namespaces are redeclared
4779 * on @tree at the top of the given subtree.
4780 * Returns the number of namespace declarations created or -1 in case of error.
4781 */
4782int
4783xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4784 xmlNsPtr *oldNs = NULL;
4785 xmlNsPtr *newNs = NULL;
4786 int sizeCache = 0;
4787 int nbCache = 0;
4788
4789 xmlNsPtr n;
4790 xmlNodePtr node = tree;
4791 xmlAttrPtr attr;
4792 int ret = 0, i;
4793
4794 while (node != NULL) {
4795 /*
4796 * Reconciliate the node namespace
4797 */
4798 if (node->ns != NULL) {
4799 /*
4800 * initialize the cache if needed
4801 */
4802 if (sizeCache == 0) {
4803 sizeCache = 10;
4804 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4805 sizeof(xmlNsPtr));
4806 if (oldNs == NULL) {
4807 xmlGenericError(xmlGenericErrorContext,
4808 "xmlReconciliateNs : memory pbm\n");
4809 return(-1);
4810 }
4811 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4812 sizeof(xmlNsPtr));
4813 if (newNs == NULL) {
4814 xmlGenericError(xmlGenericErrorContext,
4815 "xmlReconciliateNs : memory pbm\n");
4816 xmlFree(oldNs);
4817 return(-1);
4818 }
4819 }
4820 for (i = 0;i < nbCache;i++) {
4821 if (oldNs[i] == node->ns) {
4822 node->ns = newNs[i];
4823 break;
4824 }
4825 }
4826 if (i == nbCache) {
4827 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004828 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004829 */
4830 n = xmlNewReconciliedNs(doc, tree, node->ns);
4831 if (n != NULL) { /* :-( what if else ??? */
4832 /*
4833 * check if we need to grow the cache buffers.
4834 */
4835 if (sizeCache <= nbCache) {
4836 sizeCache *= 2;
4837 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4838 sizeof(xmlNsPtr));
4839 if (oldNs == NULL) {
4840 xmlGenericError(xmlGenericErrorContext,
4841 "xmlReconciliateNs : memory pbm\n");
4842 xmlFree(newNs);
4843 return(-1);
4844 }
4845 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4846 sizeof(xmlNsPtr));
4847 if (newNs == NULL) {
4848 xmlGenericError(xmlGenericErrorContext,
4849 "xmlReconciliateNs : memory pbm\n");
4850 xmlFree(oldNs);
4851 return(-1);
4852 }
4853 }
4854 newNs[nbCache] = n;
4855 oldNs[nbCache++] = node->ns;
4856 node->ns = n;
4857 }
4858 }
4859 }
4860 /*
4861 * now check for namespace hold by attributes on the node.
4862 */
4863 attr = node->properties;
4864 while (attr != NULL) {
4865 if (attr->ns != NULL) {
4866 /*
4867 * initialize the cache if needed
4868 */
4869 if (sizeCache == 0) {
4870 sizeCache = 10;
4871 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4872 sizeof(xmlNsPtr));
4873 if (oldNs == NULL) {
4874 xmlGenericError(xmlGenericErrorContext,
4875 "xmlReconciliateNs : memory pbm\n");
4876 return(-1);
4877 }
4878 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4879 sizeof(xmlNsPtr));
4880 if (newNs == NULL) {
4881 xmlGenericError(xmlGenericErrorContext,
4882 "xmlReconciliateNs : memory pbm\n");
4883 xmlFree(oldNs);
4884 return(-1);
4885 }
4886 }
4887 for (i = 0;i < nbCache;i++) {
4888 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00004889 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00004890 break;
4891 }
4892 }
4893 if (i == nbCache) {
4894 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004895 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004896 */
4897 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4898 if (n != NULL) { /* :-( what if else ??? */
4899 /*
4900 * check if we need to grow the cache buffers.
4901 */
4902 if (sizeCache <= nbCache) {
4903 sizeCache *= 2;
4904 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4905 sizeof(xmlNsPtr));
4906 if (oldNs == NULL) {
4907 xmlGenericError(xmlGenericErrorContext,
4908 "xmlReconciliateNs : memory pbm\n");
4909 xmlFree(newNs);
4910 return(-1);
4911 }
4912 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4913 sizeof(xmlNsPtr));
4914 if (newNs == NULL) {
4915 xmlGenericError(xmlGenericErrorContext,
4916 "xmlReconciliateNs : memory pbm\n");
4917 xmlFree(oldNs);
4918 return(-1);
4919 }
4920 }
4921 newNs[nbCache] = n;
4922 oldNs[nbCache++] = attr->ns;
4923 attr->ns = n;
4924 }
4925 }
4926 }
4927 attr = attr->next;
4928 }
4929
4930 /*
4931 * Browse the full subtree, deep first
4932 */
4933 if (node->children != NULL) {
4934 /* deep first */
4935 node = node->children;
4936 } else if ((node != tree) && (node->next != NULL)) {
4937 /* then siblings */
4938 node = node->next;
4939 } else if (node != tree) {
4940 /* go up to parents->next if needed */
4941 while (node != tree) {
4942 if (node->parent != NULL)
4943 node = node->parent;
4944 if ((node != tree) && (node->next != NULL)) {
4945 node = node->next;
4946 break;
4947 }
4948 if (node->parent == NULL) {
4949 node = NULL;
4950 break;
4951 }
4952 }
4953 /* exit condition */
4954 if (node == tree)
4955 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004956 } else
4957 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004958 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004959 if (oldNs != NULL)
4960 xmlFree(oldNs);
4961 if (newNs != NULL)
4962 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004963 return(ret);
4964}
4965
4966/**
4967 * xmlHasProp:
4968 * @node: the node
4969 * @name: the attribute name
4970 *
4971 * Search an attribute associated to a node
4972 * This function also looks in DTD attribute declaration for #FIXED or
4973 * default declaration values unless DTD use has been turned off.
4974 *
4975 * Returns the attribute or the attribute declaration or NULL if
4976 * neither was found.
4977 */
4978xmlAttrPtr
4979xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4980 xmlAttrPtr prop;
4981 xmlDocPtr doc;
4982
4983 if ((node == NULL) || (name == NULL)) return(NULL);
4984 /*
4985 * Check on the properties attached to the node
4986 */
4987 prop = node->properties;
4988 while (prop != NULL) {
4989 if (xmlStrEqual(prop->name, name)) {
4990 return(prop);
4991 }
4992 prop = prop->next;
4993 }
4994 if (!xmlCheckDTD) return(NULL);
4995
4996 /*
4997 * Check if there is a default declaration in the internal
4998 * or external subsets
4999 */
5000 doc = node->doc;
5001 if (doc != NULL) {
5002 xmlAttributePtr attrDecl;
5003 if (doc->intSubset != NULL) {
5004 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5005 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5006 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5007 if (attrDecl != NULL)
5008 return((xmlAttrPtr) attrDecl);
5009 }
5010 }
5011 return(NULL);
5012}
5013
5014/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005015 * xmlHasNsProp:
5016 * @node: the node
5017 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005018 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005019 *
5020 * Search for an attribute associated to a node
5021 * This attribute has to be anchored in the namespace specified.
5022 * This does the entity substitution.
5023 * This function looks in DTD attribute declaration for #FIXED or
5024 * default declaration values unless DTD use has been turned off.
5025 *
5026 * Returns the attribute or the attribute declaration or NULL
5027 * if neither was found.
5028 */
5029xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005030xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005031 xmlAttrPtr prop;
5032 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005033
5034 if (node == NULL)
5035 return(NULL);
5036
5037 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005038 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005039 return(xmlHasProp(node, name));
5040 while (prop != NULL) {
5041 /*
5042 * One need to have
5043 * - same attribute names
5044 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005045 */
5046 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005047 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5048 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005049 }
5050 prop = prop->next;
5051 }
5052 if (!xmlCheckDTD) return(NULL);
5053
5054 /*
5055 * Check if there is a default declaration in the internal
5056 * or external subsets
5057 */
5058 doc = node->doc;
5059 if (doc != NULL) {
5060 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005061 xmlAttributePtr attrDecl = NULL;
5062 xmlNsPtr *nsList, *cur;
5063 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005064
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005065 nsList = xmlGetNsList(node->doc, node);
5066 if (nsList == NULL)
5067 return(NULL);
5068 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5069 ename = xmlStrdup(node->ns->prefix);
5070 ename = xmlStrcat(ename, BAD_CAST ":");
5071 ename = xmlStrcat(ename, node->name);
5072 } else {
5073 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005074 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005075 if (ename == NULL) {
5076 xmlFree(nsList);
5077 return(NULL);
5078 }
5079
5080 cur = nsList;
5081 while (*cur != NULL) {
5082 if (xmlStrEqual((*cur)->href, nameSpace)) {
5083 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5084 name, (*cur)->prefix);
5085 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5086 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5087 name, (*cur)->prefix);
5088 }
5089 cur++;
5090 }
5091 xmlFree(nsList);
5092 xmlFree(ename);
5093 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005094 }
5095 }
5096 return(NULL);
5097}
5098
5099/**
Owen Taylor3473f882001-02-23 17:55:21 +00005100 * xmlGetProp:
5101 * @node: the node
5102 * @name: the attribute name
5103 *
5104 * Search and get the value of an attribute associated to a node
5105 * This does the entity substitution.
5106 * This function looks in DTD attribute declaration for #FIXED or
5107 * default declaration values unless DTD use has been turned off.
5108 *
5109 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005110 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005111 */
5112xmlChar *
5113xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5114 xmlAttrPtr prop;
5115 xmlDocPtr doc;
5116
5117 if ((node == NULL) || (name == NULL)) return(NULL);
5118 /*
5119 * Check on the properties attached to the node
5120 */
5121 prop = node->properties;
5122 while (prop != NULL) {
5123 if (xmlStrEqual(prop->name, name)) {
5124 xmlChar *ret;
5125
5126 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5127 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5128 return(ret);
5129 }
5130 prop = prop->next;
5131 }
5132 if (!xmlCheckDTD) return(NULL);
5133
5134 /*
5135 * Check if there is a default declaration in the internal
5136 * or external subsets
5137 */
5138 doc = node->doc;
5139 if (doc != NULL) {
5140 xmlAttributePtr attrDecl;
5141 if (doc->intSubset != NULL) {
5142 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5143 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5144 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5145 if (attrDecl != NULL)
5146 return(xmlStrdup(attrDecl->defaultValue));
5147 }
5148 }
5149 return(NULL);
5150}
5151
5152/**
5153 * xmlGetNsProp:
5154 * @node: the node
5155 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005156 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005157 *
5158 * Search and get the value of an attribute associated to a node
5159 * This attribute has to be anchored in the namespace specified.
5160 * This does the entity substitution.
5161 * This function looks in DTD attribute declaration for #FIXED or
5162 * default declaration values unless DTD use has been turned off.
5163 *
5164 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005165 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005166 */
5167xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005168xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005169 xmlAttrPtr prop;
5170 xmlDocPtr doc;
5171 xmlNsPtr ns;
5172
5173 if (node == NULL)
5174 return(NULL);
5175
5176 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005177 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005178 return(xmlGetProp(node, name));
5179 while (prop != NULL) {
5180 /*
5181 * One need to have
5182 * - same attribute names
5183 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005184 */
5185 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005186 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005187 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005188 xmlChar *ret;
5189
5190 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5191 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5192 return(ret);
5193 }
5194 prop = prop->next;
5195 }
5196 if (!xmlCheckDTD) return(NULL);
5197
5198 /*
5199 * Check if there is a default declaration in the internal
5200 * or external subsets
5201 */
5202 doc = node->doc;
5203 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005204 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005205 xmlAttributePtr attrDecl;
5206
Owen Taylor3473f882001-02-23 17:55:21 +00005207 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5208 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5209 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5210
5211 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5212 /*
5213 * The DTD declaration only allows a prefix search
5214 */
5215 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005216 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005217 return(xmlStrdup(attrDecl->defaultValue));
5218 }
5219 }
5220 }
5221 return(NULL);
5222}
5223
5224/**
5225 * xmlSetProp:
5226 * @node: the node
5227 * @name: the attribute name
5228 * @value: the attribute value
5229 *
5230 * Set (or reset) an attribute carried by a node.
5231 * Returns the attribute pointer.
5232 */
5233xmlAttrPtr
5234xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005235 xmlAttrPtr prop;
5236 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005237
5238 if ((node == NULL) || (name == NULL))
5239 return(NULL);
5240 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005241 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005242 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005243 if ((xmlStrEqual(prop->name, name)) &&
5244 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005245 xmlNodePtr oldprop = prop->children;
5246
Owen Taylor3473f882001-02-23 17:55:21 +00005247 prop->children = NULL;
5248 prop->last = NULL;
5249 if (value != NULL) {
5250 xmlChar *buffer;
5251 xmlNodePtr tmp;
5252
5253 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5254 prop->children = xmlStringGetNodeList(node->doc, buffer);
5255 prop->last = NULL;
5256 prop->doc = doc;
5257 tmp = prop->children;
5258 while (tmp != NULL) {
5259 tmp->parent = (xmlNodePtr) prop;
5260 tmp->doc = doc;
5261 if (tmp->next == NULL)
5262 prop->last = tmp;
5263 tmp = tmp->next;
5264 }
5265 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005266 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005267 if (oldprop != NULL)
5268 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005269 return(prop);
5270 }
5271 prop = prop->next;
5272 }
5273 prop = xmlNewProp(node, name, value);
5274 return(prop);
5275}
5276
5277/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005278 * xmlUnsetProp:
5279 * @node: the node
5280 * @name: the attribute name
5281 *
5282 * Remove an attribute carried by a node.
5283 * Returns 0 if successful, -1 if not found
5284 */
5285int
5286xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5287 xmlAttrPtr prop = node->properties, prev = NULL;;
5288
5289 if ((node == NULL) || (name == NULL))
5290 return(-1);
5291 while (prop != NULL) {
5292 if ((xmlStrEqual(prop->name, name)) &&
5293 (prop->ns == NULL)) {
5294 if (prev == NULL)
5295 node->properties = prop->next;
5296 else
5297 prev->next = prop->next;
5298 xmlFreeProp(prop);
5299 return(0);
5300 }
5301 prev = prop;
5302 prop = prop->next;
5303 }
5304 return(-1);
5305}
5306
5307/**
Owen Taylor3473f882001-02-23 17:55:21 +00005308 * xmlSetNsProp:
5309 * @node: the node
5310 * @ns: the namespace definition
5311 * @name: the attribute name
5312 * @value: the attribute value
5313 *
5314 * Set (or reset) an attribute carried by a node.
5315 * The ns structure must be in scope, this is not checked.
5316 *
5317 * Returns the attribute pointer.
5318 */
5319xmlAttrPtr
5320xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5321 const xmlChar *value) {
5322 xmlAttrPtr prop;
5323
5324 if ((node == NULL) || (name == NULL))
5325 return(NULL);
5326
5327 if (ns == NULL)
5328 return(xmlSetProp(node, name, value));
5329 if (ns->href == NULL)
5330 return(NULL);
5331 prop = node->properties;
5332
5333 while (prop != NULL) {
5334 /*
5335 * One need to have
5336 * - same attribute names
5337 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005338 */
5339 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005340 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005341 if (prop->children != NULL)
5342 xmlFreeNodeList(prop->children);
5343 prop->children = NULL;
5344 prop->last = NULL;
5345 prop->ns = ns;
5346 if (value != NULL) {
5347 xmlChar *buffer;
5348 xmlNodePtr tmp;
5349
5350 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5351 prop->children = xmlStringGetNodeList(node->doc, buffer);
5352 prop->last = NULL;
5353 tmp = prop->children;
5354 while (tmp != NULL) {
5355 tmp->parent = (xmlNodePtr) prop;
5356 if (tmp->next == NULL)
5357 prop->last = tmp;
5358 tmp = tmp->next;
5359 }
5360 xmlFree(buffer);
5361 }
5362 return(prop);
5363 }
5364 prop = prop->next;
5365 }
5366 prop = xmlNewNsProp(node, ns, name, value);
5367 return(prop);
5368}
5369
5370/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005371 * xmlUnsetNsProp:
5372 * @node: the node
5373 * @ns: the namespace definition
5374 * @name: the attribute name
5375 *
5376 * Remove an attribute carried by a node.
5377 * Returns 0 if successful, -1 if not found
5378 */
5379int
5380xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5381 xmlAttrPtr prop = node->properties, prev = NULL;;
5382
5383 if ((node == NULL) || (name == NULL))
5384 return(-1);
5385 if (ns == NULL)
5386 return(xmlUnsetProp(node, name));
5387 if (ns->href == NULL)
5388 return(-1);
5389 while (prop != NULL) {
5390 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005391 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005392 if (prev == NULL)
5393 node->properties = prop->next;
5394 else
5395 prev->next = prop->next;
5396 xmlFreeProp(prop);
5397 return(0);
5398 }
5399 prev = prop;
5400 prop = prop->next;
5401 }
5402 return(-1);
5403}
5404
5405/**
Owen Taylor3473f882001-02-23 17:55:21 +00005406 * xmlNodeIsText:
5407 * @node: the node
5408 *
5409 * Is this node a Text node ?
5410 * Returns 1 yes, 0 no
5411 */
5412int
5413xmlNodeIsText(xmlNodePtr node) {
5414 if (node == NULL) return(0);
5415
5416 if (node->type == XML_TEXT_NODE) return(1);
5417 return(0);
5418}
5419
5420/**
5421 * xmlIsBlankNode:
5422 * @node: the node
5423 *
5424 * Checks whether this node is an empty or whitespace only
5425 * (and possibly ignorable) text-node.
5426 *
5427 * Returns 1 yes, 0 no
5428 */
5429int
5430xmlIsBlankNode(xmlNodePtr node) {
5431 const xmlChar *cur;
5432 if (node == NULL) return(0);
5433
Daniel Veillard7db37732001-07-12 01:20:08 +00005434 if ((node->type != XML_TEXT_NODE) &&
5435 (node->type != XML_CDATA_SECTION_NODE))
5436 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005437 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005438 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005439 while (*cur != 0) {
5440 if (!IS_BLANK(*cur)) return(0);
5441 cur++;
5442 }
5443
5444 return(1);
5445}
5446
5447/**
5448 * xmlTextConcat:
5449 * @node: the node
5450 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005451 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005452 *
5453 * Concat the given string at the end of the existing node content
5454 */
5455
5456void
5457xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5458 if (node == NULL) return;
5459
5460 if ((node->type != XML_TEXT_NODE) &&
5461 (node->type != XML_CDATA_SECTION_NODE)) {
5462#ifdef DEBUG_TREE
5463 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005464 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005465#endif
5466 return;
5467 }
Owen Taylor3473f882001-02-23 17:55:21 +00005468 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005469}
5470
5471/************************************************************************
5472 * *
5473 * Output : to a FILE or in memory *
5474 * *
5475 ************************************************************************/
5476
Owen Taylor3473f882001-02-23 17:55:21 +00005477/**
5478 * xmlBufferCreate:
5479 *
5480 * routine to create an XML buffer.
5481 * returns the new structure.
5482 */
5483xmlBufferPtr
5484xmlBufferCreate(void) {
5485 xmlBufferPtr ret;
5486
5487 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5488 if (ret == NULL) {
5489 xmlGenericError(xmlGenericErrorContext,
5490 "xmlBufferCreate : out of memory!\n");
5491 return(NULL);
5492 }
5493 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005494 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005495 ret->alloc = xmlBufferAllocScheme;
5496 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5497 if (ret->content == NULL) {
5498 xmlGenericError(xmlGenericErrorContext,
5499 "xmlBufferCreate : out of memory!\n");
5500 xmlFree(ret);
5501 return(NULL);
5502 }
5503 ret->content[0] = 0;
5504 return(ret);
5505}
5506
5507/**
5508 * xmlBufferCreateSize:
5509 * @size: initial size of buffer
5510 *
5511 * routine to create an XML buffer.
5512 * returns the new structure.
5513 */
5514xmlBufferPtr
5515xmlBufferCreateSize(size_t size) {
5516 xmlBufferPtr ret;
5517
5518 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5519 if (ret == NULL) {
5520 xmlGenericError(xmlGenericErrorContext,
5521 "xmlBufferCreate : out of memory!\n");
5522 return(NULL);
5523 }
5524 ret->use = 0;
5525 ret->alloc = xmlBufferAllocScheme;
5526 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5527 if (ret->size){
5528 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5529 if (ret->content == NULL) {
5530 xmlGenericError(xmlGenericErrorContext,
5531 "xmlBufferCreate : out of memory!\n");
5532 xmlFree(ret);
5533 return(NULL);
5534 }
5535 ret->content[0] = 0;
5536 } else
5537 ret->content = NULL;
5538 return(ret);
5539}
5540
5541/**
5542 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005543 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005544 * @scheme: allocation scheme to use
5545 *
5546 * Sets the allocation scheme for this buffer
5547 */
5548void
5549xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5550 xmlBufferAllocationScheme scheme) {
5551 if (buf == NULL) {
5552#ifdef DEBUG_BUFFER
5553 xmlGenericError(xmlGenericErrorContext,
5554 "xmlBufferSetAllocationScheme: buf == NULL\n");
5555#endif
5556 return;
5557 }
5558
5559 buf->alloc = scheme;
5560}
5561
5562/**
5563 * xmlBufferFree:
5564 * @buf: the buffer to free
5565 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005566 * Frees an XML buffer. It frees both the content and the structure which
5567 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005568 */
5569void
5570xmlBufferFree(xmlBufferPtr buf) {
5571 if (buf == NULL) {
5572#ifdef DEBUG_BUFFER
5573 xmlGenericError(xmlGenericErrorContext,
5574 "xmlBufferFree: buf == NULL\n");
5575#endif
5576 return;
5577 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005578 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005579 xmlFree(buf->content);
5580 }
Owen Taylor3473f882001-02-23 17:55:21 +00005581 xmlFree(buf);
5582}
5583
5584/**
5585 * xmlBufferEmpty:
5586 * @buf: the buffer
5587 *
5588 * empty a buffer.
5589 */
5590void
5591xmlBufferEmpty(xmlBufferPtr buf) {
5592 if (buf->content == NULL) return;
5593 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005594 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005595}
5596
5597/**
5598 * xmlBufferShrink:
5599 * @buf: the buffer to dump
5600 * @len: the number of xmlChar to remove
5601 *
5602 * Remove the beginning of an XML buffer.
5603 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005604 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005605 */
5606int
5607xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5608 if (len == 0) return(0);
5609 if (len > buf->use) return(-1);
5610
5611 buf->use -= len;
5612 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5613
5614 buf->content[buf->use] = 0;
5615 return(len);
5616}
5617
5618/**
5619 * xmlBufferGrow:
5620 * @buf: the buffer
5621 * @len: the minimum free size to allocate
5622 *
5623 * Grow the available space of an XML buffer.
5624 *
5625 * Returns the new available space or -1 in case of error
5626 */
5627int
5628xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5629 int size;
5630 xmlChar *newbuf;
5631
5632 if (len + buf->use < buf->size) return(0);
5633
5634 size = buf->use + len + 100;
5635
5636 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5637 if (newbuf == NULL) return(-1);
5638 buf->content = newbuf;
5639 buf->size = size;
5640 return(buf->size - buf->use);
5641}
5642
5643/**
5644 * xmlBufferDump:
5645 * @file: the file output
5646 * @buf: the buffer to dump
5647 *
5648 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005649 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005650 */
5651int
5652xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5653 int ret;
5654
5655 if (buf == NULL) {
5656#ifdef DEBUG_BUFFER
5657 xmlGenericError(xmlGenericErrorContext,
5658 "xmlBufferDump: buf == NULL\n");
5659#endif
5660 return(0);
5661 }
5662 if (buf->content == NULL) {
5663#ifdef DEBUG_BUFFER
5664 xmlGenericError(xmlGenericErrorContext,
5665 "xmlBufferDump: buf->content == NULL\n");
5666#endif
5667 return(0);
5668 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005669 if (file == NULL)
5670 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005671 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5672 return(ret);
5673}
5674
5675/**
5676 * xmlBufferContent:
5677 * @buf: the buffer
5678 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005679 * Function to extract the content of a buffer
5680 *
Owen Taylor3473f882001-02-23 17:55:21 +00005681 * Returns the internal content
5682 */
5683
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005684const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005685xmlBufferContent(const xmlBufferPtr buf)
5686{
5687 if(!buf)
5688 return NULL;
5689
5690 return buf->content;
5691}
5692
5693/**
5694 * xmlBufferLength:
5695 * @buf: the buffer
5696 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005697 * Function to get the length of a buffer
5698 *
Owen Taylor3473f882001-02-23 17:55:21 +00005699 * Returns the length of data in the internal content
5700 */
5701
5702int
5703xmlBufferLength(const xmlBufferPtr buf)
5704{
5705 if(!buf)
5706 return 0;
5707
5708 return buf->use;
5709}
5710
5711/**
5712 * xmlBufferResize:
5713 * @buf: the buffer to resize
5714 * @size: the desired size
5715 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005716 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005717 *
5718 * Returns 0 in case of problems, 1 otherwise
5719 */
5720int
5721xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5722{
5723 unsigned int newSize;
5724 xmlChar* rebuf = NULL;
5725
5726 /*take care of empty case*/
5727 newSize = (buf->size ? buf->size*2 : size);
5728
5729 /* Don't resize if we don't have to */
5730 if (size < buf->size)
5731 return 1;
5732
5733 /* figure out new size */
5734 switch (buf->alloc){
5735 case XML_BUFFER_ALLOC_DOUBLEIT:
5736 while (size > newSize) newSize *= 2;
5737 break;
5738 case XML_BUFFER_ALLOC_EXACT:
5739 newSize = size+10;
5740 break;
5741 default:
5742 newSize = size+10;
5743 break;
5744 }
5745
5746 if (buf->content == NULL)
5747 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5748 else
5749 rebuf = (xmlChar *) xmlRealloc(buf->content,
5750 newSize * sizeof(xmlChar));
5751 if (rebuf == NULL) {
5752 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005753 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005754 return 0;
5755 }
5756 buf->content = rebuf;
5757 buf->size = newSize;
5758
5759 return 1;
5760}
5761
5762/**
5763 * xmlBufferAdd:
5764 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005765 * @str: the #xmlChar string
5766 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005767 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005768 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005769 * str is recomputed.
5770 */
5771void
5772xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5773 unsigned int needSize;
5774
5775 if (str == NULL) {
5776#ifdef DEBUG_BUFFER
5777 xmlGenericError(xmlGenericErrorContext,
5778 "xmlBufferAdd: str == NULL\n");
5779#endif
5780 return;
5781 }
5782 if (len < -1) {
5783#ifdef DEBUG_BUFFER
5784 xmlGenericError(xmlGenericErrorContext,
5785 "xmlBufferAdd: len < 0\n");
5786#endif
5787 return;
5788 }
5789 if (len == 0) return;
5790
5791 if (len < 0)
5792 len = xmlStrlen(str);
5793
5794 if (len <= 0) return;
5795
5796 needSize = buf->use + len + 2;
5797 if (needSize > buf->size){
5798 if (!xmlBufferResize(buf, needSize)){
5799 xmlGenericError(xmlGenericErrorContext,
5800 "xmlBufferAdd : out of memory!\n");
5801 return;
5802 }
5803 }
5804
5805 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5806 buf->use += len;
5807 buf->content[buf->use] = 0;
5808}
5809
5810/**
5811 * xmlBufferAddHead:
5812 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005813 * @str: the #xmlChar string
5814 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005815 *
5816 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005817 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005818 */
5819void
5820xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5821 unsigned int needSize;
5822
5823 if (str == NULL) {
5824#ifdef DEBUG_BUFFER
5825 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005826 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005827#endif
5828 return;
5829 }
5830 if (len < -1) {
5831#ifdef DEBUG_BUFFER
5832 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005833 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005834#endif
5835 return;
5836 }
5837 if (len == 0) return;
5838
5839 if (len < 0)
5840 len = xmlStrlen(str);
5841
5842 if (len <= 0) return;
5843
5844 needSize = buf->use + len + 2;
5845 if (needSize > buf->size){
5846 if (!xmlBufferResize(buf, needSize)){
5847 xmlGenericError(xmlGenericErrorContext,
5848 "xmlBufferAddHead : out of memory!\n");
5849 return;
5850 }
5851 }
5852
5853 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5854 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5855 buf->use += len;
5856 buf->content[buf->use] = 0;
5857}
5858
5859/**
5860 * xmlBufferCat:
5861 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005862 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005863 *
5864 * Append a zero terminated string to an XML buffer.
5865 */
5866void
5867xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5868 if (str != NULL)
5869 xmlBufferAdd(buf, str, -1);
5870}
5871
5872/**
5873 * xmlBufferCCat:
5874 * @buf: the buffer to dump
5875 * @str: the C char string
5876 *
5877 * Append a zero terminated C string to an XML buffer.
5878 */
5879void
5880xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5881 const char *cur;
5882
5883 if (str == NULL) {
5884#ifdef DEBUG_BUFFER
5885 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005886 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005887#endif
5888 return;
5889 }
5890 for (cur = str;*cur != 0;cur++) {
5891 if (buf->use + 10 >= buf->size) {
5892 if (!xmlBufferResize(buf, buf->use+10)){
5893 xmlGenericError(xmlGenericErrorContext,
5894 "xmlBufferCCat : out of memory!\n");
5895 return;
5896 }
5897 }
5898 buf->content[buf->use++] = *cur;
5899 }
5900 buf->content[buf->use] = 0;
5901}
5902
5903/**
5904 * xmlBufferWriteCHAR:
5905 * @buf: the XML buffer
5906 * @string: the string to add
5907 *
5908 * routine which manages and grows an output buffer. This one adds
5909 * xmlChars at the end of the buffer.
5910 */
5911void
Owen Taylor3473f882001-02-23 17:55:21 +00005912xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00005913(xmlBufferPtr buf, const xmlChar *string) {
5914 xmlBufferCat(buf, string);
5915}
5916
5917/**
5918 * xmlBufferWriteChar:
5919 * @buf: the XML buffer output
5920 * @string: the string to add
5921 *
5922 * routine which manage and grows an output buffer. This one add
5923 * C chars at the end of the array.
5924 */
5925void
5926xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5927 xmlBufferCCat(buf, string);
5928}
5929
5930
5931/**
5932 * xmlBufferWriteQuotedString:
5933 * @buf: the XML buffer output
5934 * @string: the string to add
5935 *
5936 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005937 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005938 * quote or double-quotes internally
5939 */
5940void
5941xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5942 if (xmlStrchr(string, '"')) {
5943 if (xmlStrchr(string, '\'')) {
5944#ifdef DEBUG_BUFFER
5945 xmlGenericError(xmlGenericErrorContext,
5946 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5947#endif
5948 }
5949 xmlBufferCCat(buf, "'");
5950 xmlBufferCat(buf, string);
5951 xmlBufferCCat(buf, "'");
5952 } else {
5953 xmlBufferCCat(buf, "\"");
5954 xmlBufferCat(buf, string);
5955 xmlBufferCCat(buf, "\"");
5956 }
5957}
5958
5959
5960/************************************************************************
5961 * *
5962 * Dumping XML tree content to a simple buffer *
5963 * *
5964 ************************************************************************/
5965
Owen Taylor3473f882001-02-23 17:55:21 +00005966/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005967 * xmlAttrSerializeContent:
5968 * @buf: the XML buffer output
5969 * @doc: the document
5970 * @attr: the attribute pointer
5971 *
5972 * Serialize the attribute in the buffer
5973 */
5974static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00005975xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
5976{
Daniel Veillarda6d05382002-02-13 13:07:41 +00005977 const xmlChar *cur, *base;
5978 xmlNodePtr children;
5979
5980 children = attr->children;
5981 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00005982 switch (children->type) {
5983 case XML_TEXT_NODE:
5984 base = cur = children->content;
5985 while (*cur != 0) {
5986 if (*cur == '\n') {
5987 if (base != cur)
5988 xmlBufferAdd(buf, base, cur - base);
5989 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5990 cur++;
5991 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00005992#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00005993 } else if (*cur == '\'') {
5994 if (base != cur)
5995 xmlBufferAdd(buf, base, cur - base);
5996 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5997 cur++;
5998 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00005999#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006000 } else if (*cur == '"') {
6001 if (base != cur)
6002 xmlBufferAdd(buf, base, cur - base);
6003 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6004 cur++;
6005 base = cur;
6006 } else if (*cur == '<') {
6007 if (base != cur)
6008 xmlBufferAdd(buf, base, cur - base);
6009 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6010 cur++;
6011 base = cur;
6012 } else if (*cur == '>') {
6013 if (base != cur)
6014 xmlBufferAdd(buf, base, cur - base);
6015 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6016 cur++;
6017 base = cur;
6018 } else if (*cur == '&') {
6019 if (base != cur)
6020 xmlBufferAdd(buf, base, cur - base);
6021 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6022 cur++;
6023 base = cur;
6024 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6025 (doc->encoding ==
6026 NULL))) {
6027 /*
6028 * We assume we have UTF-8 content.
6029 */
6030 char tmp[10];
6031 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006032
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006033 if (base != cur)
6034 xmlBufferAdd(buf, base, cur - base);
6035 if (*cur < 0xC0) {
6036 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006037 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006038 if (doc != NULL)
6039 doc->encoding =
6040 xmlStrdup(BAD_CAST "ISO-8859-1");
6041 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6042 tmp[sizeof(tmp) - 1] = 0;
6043 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6044 cur++;
6045 base = cur;
6046 continue;
6047 } else if (*cur < 0xE0) {
6048 val = (cur[0]) & 0x1F;
6049 val <<= 6;
6050 val |= (cur[1]) & 0x3F;
6051 l = 2;
6052 } else if (*cur < 0xF0) {
6053 val = (cur[0]) & 0x0F;
6054 val <<= 6;
6055 val |= (cur[1]) & 0x3F;
6056 val <<= 6;
6057 val |= (cur[2]) & 0x3F;
6058 l = 3;
6059 } else if (*cur < 0xF8) {
6060 val = (cur[0]) & 0x07;
6061 val <<= 6;
6062 val |= (cur[1]) & 0x3F;
6063 val <<= 6;
6064 val |= (cur[2]) & 0x3F;
6065 val <<= 6;
6066 val |= (cur[3]) & 0x3F;
6067 l = 4;
6068 }
6069 if ((l == 1) || (!IS_CHAR(val))) {
6070 xmlGenericError(xmlGenericErrorContext,
6071 "xmlAttrSerializeContent : char out of range\n");
6072 if (doc != NULL)
6073 doc->encoding =
6074 xmlStrdup(BAD_CAST "ISO-8859-1");
6075 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6076 tmp[sizeof(tmp) - 1] = 0;
6077 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6078 cur++;
6079 base = cur;
6080 continue;
6081 }
6082 /*
6083 * We could do multiple things here. Just save
6084 * as a char ref
6085 */
6086 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6087 tmp[sizeof(tmp) - 1] = 0;
6088 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6089 cur += l;
6090 base = cur;
6091 } else {
6092 cur++;
6093 }
6094 }
6095 if (base != cur)
6096 xmlBufferAdd(buf, base, cur - base);
6097 break;
6098 case XML_ENTITY_REF_NODE:
6099 xmlBufferAdd(buf, BAD_CAST "&", 1);
6100 xmlBufferAdd(buf, children->name,
6101 xmlStrlen(children->name));
6102 xmlBufferAdd(buf, BAD_CAST ";", 1);
6103 break;
6104 default:
6105 /* should not happen unless we have a badly built tree */
6106 break;
6107 }
6108 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006109 }
6110}
6111
6112/**
6113 * xmlNodeDump:
6114 * @buf: the XML buffer output
6115 * @doc: the document
6116 * @cur: the current node
6117 * @level: the imbrication level for indenting
6118 * @format: is formatting allowed
6119 *
6120 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006121 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6122 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006123 *
6124 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006125 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006126int
Owen Taylor3473f882001-02-23 17:55:21 +00006127xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006128 int format)
6129{
6130 unsigned int use;
6131 int ret;
6132 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006133
6134 if (cur == NULL) {
6135#ifdef DEBUG_TREE
6136 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006137 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006138#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006139 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006140 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006141 if (buf == NULL) {
6142#ifdef DEBUG_TREE
6143 xmlGenericError(xmlGenericErrorContext,
6144 "xmlNodeDump : buf == NULL\n");
6145#endif
6146 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006147 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006148 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6149 if (outbuf == NULL) {
6150 xmlGenericError(xmlGenericErrorContext,
6151 "xmlNodeDump: out of memory!\n");
6152 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006153 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006154 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6155 outbuf->buffer = buf;
6156 outbuf->encoder = NULL;
6157 outbuf->writecallback = NULL;
6158 outbuf->closecallback = NULL;
6159 outbuf->context = NULL;
6160 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006161
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006162 use = buf->use;
6163 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6164 xmlFree(outbuf);
6165 ret = buf->use - use;
6166 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006167}
6168
6169/**
6170 * xmlElemDump:
6171 * @f: the FILE * for the output
6172 * @doc: the document
6173 * @cur: the current node
6174 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006175 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006176 */
6177void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006178xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6179{
6180 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006181
6182 if (cur == NULL) {
6183#ifdef DEBUG_TREE
6184 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006185 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006186#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006187 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006188 }
Owen Taylor3473f882001-02-23 17:55:21 +00006189#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006190 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006191 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006192 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006193 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006194#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006195
6196 outbuf = xmlOutputBufferCreateFile(f, NULL);
6197 if (outbuf == NULL)
6198 return;
6199 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006200#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006201 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6202#else
6203 xmlGenericError(xmlGenericErrorContext,
6204 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006205#endif /* LIBXML_HTML_ENABLED */
6206 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006207 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6208 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006209}
6210
6211/************************************************************************
6212 * *
6213 * Dumping XML tree content to an I/O output buffer *
6214 * *
6215 ************************************************************************/
6216
Owen Taylor3473f882001-02-23 17:55:21 +00006217static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006218xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6219 int level, int format, const char *encoding);
6220static void
Owen Taylor3473f882001-02-23 17:55:21 +00006221xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6222 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006223static void
6224xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6225 xmlNodePtr cur, int level, int format, const char *encoding);
6226
Owen Taylor3473f882001-02-23 17:55:21 +00006227/**
6228 * xmlNsDumpOutput:
6229 * @buf: the XML buffer output
6230 * @cur: a namespace
6231 *
6232 * Dump a local Namespace definition.
6233 * Should be called in the context of attributes dumps.
6234 */
6235static void
6236xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6237 if (cur == NULL) {
6238#ifdef DEBUG_TREE
6239 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006240 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006241#endif
6242 return;
6243 }
6244 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006245 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6246 return;
6247
Owen Taylor3473f882001-02-23 17:55:21 +00006248 /* Within the context of an element attributes */
6249 if (cur->prefix != NULL) {
6250 xmlOutputBufferWriteString(buf, " xmlns:");
6251 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6252 } else
6253 xmlOutputBufferWriteString(buf, " xmlns");
6254 xmlOutputBufferWriteString(buf, "=");
6255 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6256 }
6257}
6258
6259/**
6260 * xmlNsListDumpOutput:
6261 * @buf: the XML buffer output
6262 * @cur: the first namespace
6263 *
6264 * Dump a list of local Namespace definitions.
6265 * Should be called in the context of attributes dumps.
6266 */
6267static void
6268xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6269 while (cur != NULL) {
6270 xmlNsDumpOutput(buf, cur);
6271 cur = cur->next;
6272 }
6273}
6274
6275/**
6276 * xmlDtdDumpOutput:
6277 * @buf: the XML buffer output
6278 * @doc: the document
6279 * @encoding: an optional encoding string
6280 *
6281 * Dump the XML document DTD, if any.
6282 */
6283static void
6284xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6285 if (dtd == NULL) {
6286#ifdef DEBUG_TREE
6287 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006288 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006289#endif
6290 return;
6291 }
6292 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6293 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6294 if (dtd->ExternalID != NULL) {
6295 xmlOutputBufferWriteString(buf, " PUBLIC ");
6296 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6297 xmlOutputBufferWriteString(buf, " ");
6298 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6299 } else if (dtd->SystemID != NULL) {
6300 xmlOutputBufferWriteString(buf, " SYSTEM ");
6301 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6302 }
6303 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6304 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6305 xmlOutputBufferWriteString(buf, ">");
6306 return;
6307 }
6308 xmlOutputBufferWriteString(buf, " [\n");
6309 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6310 xmlOutputBufferWriteString(buf, "]>");
6311}
6312
6313/**
6314 * xmlAttrDumpOutput:
6315 * @buf: the XML buffer output
6316 * @doc: the document
6317 * @cur: the attribute pointer
6318 * @encoding: an optional encoding string
6319 *
6320 * Dump an XML attribute
6321 */
6322static void
6323xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006324 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006325 if (cur == NULL) {
6326#ifdef DEBUG_TREE
6327 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006328 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006329#endif
6330 return;
6331 }
6332 xmlOutputBufferWriteString(buf, " ");
6333 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6334 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6335 xmlOutputBufferWriteString(buf, ":");
6336 }
6337 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006338 xmlOutputBufferWriteString(buf, "=\"");
6339 xmlAttrSerializeContent(buf->buffer, doc, cur);
6340 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006341}
6342
6343/**
6344 * xmlAttrListDumpOutput:
6345 * @buf: the XML buffer output
6346 * @doc: the document
6347 * @cur: the first attribute pointer
6348 * @encoding: an optional encoding string
6349 *
6350 * Dump a list of XML attributes
6351 */
6352static void
6353xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6354 xmlAttrPtr cur, const char *encoding) {
6355 if (cur == NULL) {
6356#ifdef DEBUG_TREE
6357 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006358 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006359#endif
6360 return;
6361 }
6362 while (cur != NULL) {
6363 xmlAttrDumpOutput(buf, doc, cur, encoding);
6364 cur = cur->next;
6365 }
6366}
6367
6368
6369
6370/**
6371 * xmlNodeListDumpOutput:
6372 * @buf: the XML buffer output
6373 * @doc: the document
6374 * @cur: the first node
6375 * @level: the imbrication level for indenting
6376 * @format: is formatting allowed
6377 * @encoding: an optional encoding string
6378 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006379 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006380 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6381 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006382 */
6383static void
6384xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6385 xmlNodePtr cur, int level, int format, const char *encoding) {
6386 int i;
6387
6388 if (cur == NULL) {
6389#ifdef DEBUG_TREE
6390 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006391 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006392#endif
6393 return;
6394 }
6395 while (cur != NULL) {
6396 if ((format) && (xmlIndentTreeOutput) &&
6397 (cur->type == XML_ELEMENT_NODE))
6398 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006399 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006400 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006401 if (format) {
6402 xmlOutputBufferWriteString(buf, "\n");
6403 }
6404 cur = cur->next;
6405 }
6406}
6407
6408/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006409 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006410 * @buf: the XML buffer output
6411 * @doc: the document
6412 * @cur: the current node
6413 * @level: the imbrication level for indenting
6414 * @format: is formatting allowed
6415 * @encoding: an optional encoding string
6416 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006417 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006418 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6419 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006420 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006421static void
6422xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6423 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006424 int i;
6425 xmlNodePtr tmp;
6426
6427 if (cur == NULL) {
6428#ifdef DEBUG_TREE
6429 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006430 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006431#endif
6432 return;
6433 }
6434 if (cur->type == XML_XINCLUDE_START)
6435 return;
6436 if (cur->type == XML_XINCLUDE_END)
6437 return;
6438 if (cur->type == XML_DTD_NODE) {
6439 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6440 return;
6441 }
6442 if (cur->type == XML_ELEMENT_DECL) {
6443 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6444 return;
6445 }
6446 if (cur->type == XML_ATTRIBUTE_DECL) {
6447 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6448 return;
6449 }
6450 if (cur->type == XML_ENTITY_DECL) {
6451 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6452 return;
6453 }
6454 if (cur->type == XML_TEXT_NODE) {
6455 if (cur->content != NULL) {
6456 if ((cur->name == xmlStringText) ||
6457 (cur->name != xmlStringTextNoenc)) {
6458 xmlChar *buffer;
6459
Owen Taylor3473f882001-02-23 17:55:21 +00006460 if (encoding == NULL)
6461 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6462 else
6463 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006464 if (buffer != NULL) {
6465 xmlOutputBufferWriteString(buf, (const char *)buffer);
6466 xmlFree(buffer);
6467 }
6468 } else {
6469 /*
6470 * Disable escaping, needed for XSLT
6471 */
Owen Taylor3473f882001-02-23 17:55:21 +00006472 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006473 }
6474 }
6475
6476 return;
6477 }
6478 if (cur->type == XML_PI_NODE) {
6479 if (cur->content != NULL) {
6480 xmlOutputBufferWriteString(buf, "<?");
6481 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6482 if (cur->content != NULL) {
6483 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006484 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006485 }
6486 xmlOutputBufferWriteString(buf, "?>");
6487 } else {
6488 xmlOutputBufferWriteString(buf, "<?");
6489 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6490 xmlOutputBufferWriteString(buf, "?>");
6491 }
6492 return;
6493 }
6494 if (cur->type == XML_COMMENT_NODE) {
6495 if (cur->content != NULL) {
6496 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006497 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006498 xmlOutputBufferWriteString(buf, "-->");
6499 }
6500 return;
6501 }
6502 if (cur->type == XML_ENTITY_REF_NODE) {
6503 xmlOutputBufferWriteString(buf, "&");
6504 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6505 xmlOutputBufferWriteString(buf, ";");
6506 return;
6507 }
6508 if (cur->type == XML_CDATA_SECTION_NODE) {
6509 xmlOutputBufferWriteString(buf, "<![CDATA[");
6510 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006511 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006512 xmlOutputBufferWriteString(buf, "]]>");
6513 return;
6514 }
6515
6516 if (format == 1) {
6517 tmp = cur->children;
6518 while (tmp != NULL) {
6519 if ((tmp->type == XML_TEXT_NODE) ||
6520 (tmp->type == XML_ENTITY_REF_NODE)) {
6521 format = 0;
6522 break;
6523 }
6524 tmp = tmp->next;
6525 }
6526 }
6527 xmlOutputBufferWriteString(buf, "<");
6528 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6529 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6530 xmlOutputBufferWriteString(buf, ":");
6531 }
6532
6533 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6534 if (cur->nsDef)
6535 xmlNsListDumpOutput(buf, cur->nsDef);
6536 if (cur->properties != NULL)
6537 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6538
Daniel Veillard7db37732001-07-12 01:20:08 +00006539 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6540 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006541 xmlOutputBufferWriteString(buf, "/>");
6542 return;
6543 }
6544 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006545 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006546 xmlChar *buffer;
6547
Owen Taylor3473f882001-02-23 17:55:21 +00006548 if (encoding == NULL)
6549 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6550 else
6551 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006552 if (buffer != NULL) {
6553 xmlOutputBufferWriteString(buf, (const char *)buffer);
6554 xmlFree(buffer);
6555 }
6556 }
6557 if (cur->children != NULL) {
6558 if (format) xmlOutputBufferWriteString(buf, "\n");
6559 xmlNodeListDumpOutput(buf, doc, cur->children,
6560 (level >= 0?level+1:-1), format, encoding);
6561 if ((xmlIndentTreeOutput) && (format))
6562 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006563 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006564 }
6565 xmlOutputBufferWriteString(buf, "</");
6566 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6567 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6568 xmlOutputBufferWriteString(buf, ":");
6569 }
6570
6571 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6572 xmlOutputBufferWriteString(buf, ">");
6573}
6574
6575/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006576 * xmlNodeDumpOutput:
6577 * @buf: the XML buffer output
6578 * @doc: the document
6579 * @cur: the current node
6580 * @level: the imbrication level for indenting
6581 * @format: is formatting allowed
6582 * @encoding: an optional encoding string
6583 *
6584 * Dump an XML node, recursive behaviour, children are printed too.
6585 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6586 * or xmlKeepBlanksDefault(0) was called
6587 */
6588void
6589xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006590 int level, int format, const char *encoding)
6591{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006592#ifdef LIBXML_HTML_ENABLED
6593 xmlDtdPtr dtd;
6594 int is_xhtml = 0;
6595
6596 dtd = xmlGetIntSubset(doc);
6597 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006598 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6599 if (is_xhtml < 0)
6600 is_xhtml = 0;
6601 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
6602 (cur->type == XML_ELEMENT_NODE) &&
6603 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
6604 if (encoding != NULL)
6605 htmlSetMetaEncoding((htmlDocPtr) cur,
6606 (const xmlChar *) encoding);
6607 else
6608 htmlSetMetaEncoding((htmlDocPtr) cur, BAD_CAST "UTF-8");
6609 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006610 }
6611
6612 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006613 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006614 else
6615#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006616 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006617}
6618
6619/**
Owen Taylor3473f882001-02-23 17:55:21 +00006620 * xmlDocContentDumpOutput:
6621 * @buf: the XML buffer output
6622 * @cur: the document
6623 * @encoding: an optional encoding string
6624 * @format: should formatting spaces been added
6625 *
6626 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006627 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6628 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006629 */
6630static void
6631xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6632 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006633#ifdef LIBXML_HTML_ENABLED
6634 xmlDtdPtr dtd;
6635 int is_xhtml = 0;
6636#endif
6637
Owen Taylor3473f882001-02-23 17:55:21 +00006638 xmlOutputBufferWriteString(buf, "<?xml version=");
6639 if (cur->version != NULL)
6640 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6641 else
6642 xmlOutputBufferWriteString(buf, "\"1.0\"");
6643 if (encoding == NULL) {
6644 if (cur->encoding != NULL)
6645 encoding = (const char *) cur->encoding;
6646 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6647 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6648 }
6649 if (encoding != NULL) {
6650 xmlOutputBufferWriteString(buf, " encoding=");
6651 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6652 }
6653 switch (cur->standalone) {
6654 case 0:
6655 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6656 break;
6657 case 1:
6658 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6659 break;
6660 }
6661 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006662
6663#ifdef LIBXML_HTML_ENABLED
6664 dtd = xmlGetIntSubset(cur);
6665 if (dtd != NULL) {
6666 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6667 if (is_xhtml < 0) is_xhtml = 0;
6668 }
6669 if (is_xhtml) {
6670 if (encoding != NULL)
6671 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
6672 else
6673 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
6674 }
6675#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006676 if (cur->children != NULL) {
6677 xmlNodePtr child = cur->children;
6678
6679 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006680#ifdef LIBXML_HTML_ENABLED
6681 if (is_xhtml)
6682 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6683 else
6684#endif
6685 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006686 xmlOutputBufferWriteString(buf, "\n");
6687 child = child->next;
6688 }
6689 }
6690}
6691
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006692#ifdef LIBXML_HTML_ENABLED
6693/************************************************************************
6694 * *
6695 * Functions specific to XHTML serialization *
6696 * *
6697 ************************************************************************/
6698
6699#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
6700 "-//W3C//DTD XHTML 1.0 Strict//EN"
6701#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
6702 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
6703#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
6704 "-//W3C//DTD XHTML 1.0 Frameset//EN"
6705#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
6706 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
6707#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
6708 "-//W3C//DTD XHTML 1.0 Transitional//EN"
6709#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
6710 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
6711
6712#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
6713/**
6714 * xmlIsXHTML:
6715 * @systemID: the system identifier
6716 * @publicID: the public identifier
6717 *
6718 * Try to find if the document correspond to an XHTML DTD
6719 *
6720 * Returns 1 if true, 0 if not and -1 in case of error
6721 */
6722int
6723xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
6724 if ((systemID == NULL) && (publicID == NULL))
6725 return(-1);
6726 if (publicID != NULL) {
6727 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
6728 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
6729 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
6730 }
6731 if (systemID != NULL) {
6732 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
6733 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
6734 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
6735 }
6736 return(0);
6737}
6738
6739/**
6740 * xhtmlIsEmpty:
6741 * @node: the node
6742 *
6743 * Check if a node is an empty xhtml node
6744 *
6745 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
6746 */
6747static int
6748xhtmlIsEmpty(xmlNodePtr node) {
6749 if (node == NULL)
6750 return(-1);
6751 if (node->type != XML_ELEMENT_NODE)
6752 return(0);
6753 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
6754 return(0);
6755 if (node->children != NULL)
6756 return(0);
6757 switch (node->name[0]) {
6758 case 'a':
6759 if (xmlStrEqual(node->name, BAD_CAST "area"))
6760 return(1);
6761 return(0);
6762 case 'b':
6763 if (xmlStrEqual(node->name, BAD_CAST "br"))
6764 return(1);
6765 if (xmlStrEqual(node->name, BAD_CAST "base"))
6766 return(1);
6767 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
6768 return(1);
6769 return(0);
6770 case 'c':
6771 if (xmlStrEqual(node->name, BAD_CAST "col"))
6772 return(1);
6773 return(0);
6774 case 'f':
6775 if (xmlStrEqual(node->name, BAD_CAST "frame"))
6776 return(1);
6777 return(0);
6778 case 'h':
6779 if (xmlStrEqual(node->name, BAD_CAST "hr"))
6780 return(1);
6781 return(0);
6782 case 'i':
6783 if (xmlStrEqual(node->name, BAD_CAST "img"))
6784 return(1);
6785 if (xmlStrEqual(node->name, BAD_CAST "input"))
6786 return(1);
6787 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
6788 return(1);
6789 return(0);
6790 case 'l':
6791 if (xmlStrEqual(node->name, BAD_CAST "link"))
6792 return(1);
6793 return(0);
6794 case 'm':
6795 if (xmlStrEqual(node->name, BAD_CAST "meta"))
6796 return(1);
6797 return(0);
6798 case 'p':
6799 if (xmlStrEqual(node->name, BAD_CAST "param"))
6800 return(1);
6801 return(0);
6802 }
6803 return(0);
6804}
6805
6806/**
6807 * xhtmlAttrListDumpOutput:
6808 * @buf: the XML buffer output
6809 * @doc: the document
6810 * @cur: the first attribute pointer
6811 * @encoding: an optional encoding string
6812 *
6813 * Dump a list of XML attributes
6814 */
6815static void
6816xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6817 xmlAttrPtr cur, const char *encoding) {
6818 xmlAttrPtr xml_lang = NULL;
6819 xmlAttrPtr lang = NULL;
6820 xmlAttrPtr name = NULL;
6821 xmlAttrPtr id = NULL;
6822
6823 if (cur == NULL) {
6824#ifdef DEBUG_TREE
6825 xmlGenericError(xmlGenericErrorContext,
6826 "xmlAttrListDumpOutput : property == NULL\n");
6827#endif
6828 return;
6829 }
6830 while (cur != NULL) {
6831 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
6832 id = cur;
6833 else
6834 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
6835 name = cur;
6836 else
6837 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
6838 lang = cur;
6839 else
6840 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
6841 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
6842 xml_lang = cur;
6843 else if ((cur->ns == NULL) &&
6844 ((cur->children == NULL) ||
6845 (cur->children->content == NULL) ||
6846 (cur->children->content[0] == 0)) &&
6847 (htmlIsBooleanAttr(cur->name))) {
6848 if (cur->children != NULL)
6849 xmlFreeNode(cur->children);
6850 cur->children = xmlNewText(cur->name);
6851 if (cur->children != NULL)
6852 cur->children->parent = (xmlNodePtr) cur;
6853 }
6854 xmlAttrDumpOutput(buf, doc, cur, encoding);
6855 cur = cur->next;
6856 }
6857 /*
6858 * C.8
6859 */
6860 if ((name != NULL) && (id == NULL)) {
6861 xmlOutputBufferWriteString(buf, " id=\"");
6862 xmlAttrSerializeContent(buf->buffer, doc, name);
6863 xmlOutputBufferWriteString(buf, "\"");
6864 }
6865 /*
6866 * C.7.
6867 */
6868 if ((lang != NULL) && (xml_lang == NULL)) {
6869 xmlOutputBufferWriteString(buf, " xml:lang=\"");
6870 xmlAttrSerializeContent(buf->buffer, doc, lang);
6871 xmlOutputBufferWriteString(buf, "\"");
6872 } else
6873 if ((xml_lang != NULL) && (lang == NULL)) {
6874 xmlOutputBufferWriteString(buf, " lang=\"");
6875 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
6876 xmlOutputBufferWriteString(buf, "\"");
6877 }
6878}
6879
6880/**
6881 * xhtmlNodeListDumpOutput:
6882 * @buf: the XML buffer output
6883 * @doc: the XHTML document
6884 * @cur: the first node
6885 * @level: the imbrication level for indenting
6886 * @format: is formatting allowed
6887 * @encoding: an optional encoding string
6888 *
6889 * Dump an XML node list, recursive behaviour, children are printed too.
6890 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6891 * or xmlKeepBlanksDefault(0) was called
6892 */
6893static void
6894xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6895 xmlNodePtr cur, int level, int format, const char *encoding) {
6896 int i;
6897
6898 if (cur == NULL) {
6899#ifdef DEBUG_TREE
6900 xmlGenericError(xmlGenericErrorContext,
6901 "xhtmlNodeListDumpOutput : node == NULL\n");
6902#endif
6903 return;
6904 }
6905 while (cur != NULL) {
6906 if ((format) && (xmlIndentTreeOutput) &&
6907 (cur->type == XML_ELEMENT_NODE))
6908 for (i = 0;i < level;i++)
6909 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
6910 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6911 if (format) {
6912 xmlOutputBufferWriteString(buf, "\n");
6913 }
6914 cur = cur->next;
6915 }
6916}
6917
6918/**
6919 * xhtmlNodeDumpOutput:
6920 * @buf: the XML buffer output
6921 * @doc: the XHTML document
6922 * @cur: the current node
6923 * @level: the imbrication level for indenting
6924 * @format: is formatting allowed
6925 * @encoding: an optional encoding string
6926 *
6927 * Dump an XHTML node, recursive behaviour, children are printed too.
6928 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6929 * or xmlKeepBlanksDefault(0) was called
6930 */
6931static void
6932xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6933 int level, int format, const char *encoding) {
6934 int i;
6935 xmlNodePtr tmp;
6936
6937 if (cur == NULL) {
6938#ifdef DEBUG_TREE
6939 xmlGenericError(xmlGenericErrorContext,
6940 "xmlNodeDumpOutput : node == NULL\n");
6941#endif
6942 return;
6943 }
6944 if (cur->type == XML_XINCLUDE_START)
6945 return;
6946 if (cur->type == XML_XINCLUDE_END)
6947 return;
6948 if (cur->type == XML_DTD_NODE) {
6949 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6950 return;
6951 }
6952 if (cur->type == XML_ELEMENT_DECL) {
6953 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6954 return;
6955 }
6956 if (cur->type == XML_ATTRIBUTE_DECL) {
6957 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6958 return;
6959 }
6960 if (cur->type == XML_ENTITY_DECL) {
6961 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6962 return;
6963 }
6964 if (cur->type == XML_TEXT_NODE) {
6965 if (cur->content != NULL) {
6966 if ((cur->name == xmlStringText) ||
6967 (cur->name != xmlStringTextNoenc)) {
6968 xmlChar *buffer;
6969
6970 if (encoding == NULL)
6971 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6972 else
6973 buffer = xmlEncodeSpecialChars(doc, cur->content);
6974 if (buffer != NULL) {
6975 xmlOutputBufferWriteString(buf, (const char *)buffer);
6976 xmlFree(buffer);
6977 }
6978 } else {
6979 /*
6980 * Disable escaping, needed for XSLT
6981 */
6982 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6983 }
6984 }
6985
6986 return;
6987 }
6988 if (cur->type == XML_PI_NODE) {
6989 if (cur->content != NULL) {
6990 xmlOutputBufferWriteString(buf, "<?");
6991 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6992 if (cur->content != NULL) {
6993 xmlOutputBufferWriteString(buf, " ");
6994 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6995 }
6996 xmlOutputBufferWriteString(buf, "?>");
6997 } else {
6998 xmlOutputBufferWriteString(buf, "<?");
6999 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7000 xmlOutputBufferWriteString(buf, "?>");
7001 }
7002 return;
7003 }
7004 if (cur->type == XML_COMMENT_NODE) {
7005 if (cur->content != NULL) {
7006 xmlOutputBufferWriteString(buf, "<!--");
7007 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7008 xmlOutputBufferWriteString(buf, "-->");
7009 }
7010 return;
7011 }
7012 if (cur->type == XML_ENTITY_REF_NODE) {
7013 xmlOutputBufferWriteString(buf, "&");
7014 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7015 xmlOutputBufferWriteString(buf, ";");
7016 return;
7017 }
7018 if (cur->type == XML_CDATA_SECTION_NODE) {
7019 xmlOutputBufferWriteString(buf, "<![CDATA[");
7020 if (cur->content != NULL)
7021 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7022 xmlOutputBufferWriteString(buf, "]]>");
7023 return;
7024 }
7025
7026 if (format == 1) {
7027 tmp = cur->children;
7028 while (tmp != NULL) {
7029 if ((tmp->type == XML_TEXT_NODE) ||
7030 (tmp->type == XML_ENTITY_REF_NODE)) {
7031 format = 0;
7032 break;
7033 }
7034 tmp = tmp->next;
7035 }
7036 }
7037 xmlOutputBufferWriteString(buf, "<");
7038 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7039 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7040 xmlOutputBufferWriteString(buf, ":");
7041 }
7042
7043 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7044 if (cur->nsDef)
7045 xmlNsListDumpOutput(buf, cur->nsDef);
7046 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7047 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7048 /*
7049 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7050 */
7051 xmlOutputBufferWriteString(buf,
7052 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7053 }
7054 if (cur->properties != NULL)
7055 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7056
7057 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7058 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7059 (xhtmlIsEmpty(cur) == 1)) {
7060 /*
7061 * C.2. Empty Elements
7062 */
7063 xmlOutputBufferWriteString(buf, " />");
7064 } else {
7065 /*
7066 * C.3. Element Minimization and Empty Element Content
7067 */
7068 xmlOutputBufferWriteString(buf, "></");
7069 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7070 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7071 xmlOutputBufferWriteString(buf, ":");
7072 }
7073 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7074 xmlOutputBufferWriteString(buf, ">");
7075 }
7076 return;
7077 }
7078 xmlOutputBufferWriteString(buf, ">");
7079 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7080 xmlChar *buffer;
7081
7082 if (encoding == NULL)
7083 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7084 else
7085 buffer = xmlEncodeSpecialChars(doc, cur->content);
7086 if (buffer != NULL) {
7087 xmlOutputBufferWriteString(buf, (const char *)buffer);
7088 xmlFree(buffer);
7089 }
7090 }
7091
7092 /*
7093 * 4.8. Script and Style elements
7094 */
7095 if ((cur->type == XML_ELEMENT_NODE) &&
7096 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7097 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7098 ((cur->ns == NULL) ||
7099 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7100 xmlNodePtr child = cur->children;
7101
7102 while (child != NULL) {
7103 if ((child->type == XML_TEXT_NODE) ||
7104 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007105 /*
7106 * Apparently CDATA escaping for style just break on IE,
7107 * mozilla and galeon, so ...
7108 */
7109 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7110 (xmlStrchr(child->content, '<') == NULL) &&
7111 (xmlStrchr(child->content, '>') == NULL) &&
7112 (xmlStrchr(child->content, '&') == NULL)) {
7113 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7114 } else {
7115 xmlOutputBufferWriteString(buf, "<![CDATA[");
7116 if (child->content != NULL)
7117 xmlOutputBufferWriteString(buf,
7118 (const char *)child->content);
7119 xmlOutputBufferWriteString(buf, "]]>");
7120 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007121 } else {
7122 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7123 }
7124 child = child->next;
7125 }
7126 } else if (cur->children != NULL) {
7127 if (format) xmlOutputBufferWriteString(buf, "\n");
7128 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7129 (level >= 0?level+1:-1), format, encoding);
7130 if ((xmlIndentTreeOutput) && (format))
7131 for (i = 0;i < level;i++)
7132 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7133 }
7134 xmlOutputBufferWriteString(buf, "</");
7135 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7136 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7137 xmlOutputBufferWriteString(buf, ":");
7138 }
7139
7140 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7141 xmlOutputBufferWriteString(buf, ">");
7142}
7143#endif
7144
Owen Taylor3473f882001-02-23 17:55:21 +00007145/************************************************************************
7146 * *
7147 * Saving functions front-ends *
7148 * *
7149 ************************************************************************/
7150
7151/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007152 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007153 * @out_doc: Document to generate XML text from
7154 * @doc_txt_ptr: Memory pointer for allocated XML text
7155 * @doc_txt_len: Length of the generated XML text
7156 * @txt_encoding: Character encoding to use when generating XML text
7157 * @format: should formatting spaces been added
7158 *
7159 * Dump the current DOM tree into memory using the character encoding specified
7160 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007161 * allocated memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007162 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7163 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007164 */
7165
7166void
7167xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007168 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007169 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007170 int dummy = 0;
7171
7172 xmlCharEncoding doc_charset;
7173 xmlOutputBufferPtr out_buff = NULL;
7174 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7175
7176 if (doc_txt_len == NULL) {
7177 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7178 }
7179
7180 if (doc_txt_ptr == NULL) {
7181 *doc_txt_len = 0;
7182 xmlGenericError(xmlGenericErrorContext,
7183 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7184 return;
7185 }
7186
7187 *doc_txt_ptr = NULL;
7188 *doc_txt_len = 0;
7189
7190 if (out_doc == NULL) {
7191 /* No document, no output */
7192 xmlGenericError(xmlGenericErrorContext,
7193 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7194 return;
7195 }
7196
7197 /*
7198 * Validate the encoding value, if provided.
7199 * This logic is copied from xmlSaveFileEnc.
7200 */
7201
7202 if (txt_encoding == NULL)
7203 txt_encoding = (const char *) out_doc->encoding;
7204 if (txt_encoding != NULL) {
7205 doc_charset = xmlParseCharEncoding(txt_encoding);
7206
7207 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7208 xmlGenericError(xmlGenericErrorContext,
7209 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7210 return;
7211
7212 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7213 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7214 if ( conv_hdlr == NULL ) {
7215 xmlGenericError(xmlGenericErrorContext,
7216 "%s: %s %s '%s'\n",
7217 "xmlDocDumpFormatMemoryEnc",
7218 "Failed to identify encoding handler for",
7219 "character set",
7220 txt_encoding);
7221 return;
7222 }
7223 }
7224 }
7225
7226 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7227 xmlGenericError(xmlGenericErrorContext,
7228 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7229 return;
7230 }
7231
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007232 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007233 xmlOutputBufferFlush(out_buff);
7234 if (out_buff->conv != NULL) {
7235 *doc_txt_len = out_buff->conv->use;
7236 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7237 } else {
7238 *doc_txt_len = out_buff->buffer->use;
7239 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7240 }
7241 (void)xmlOutputBufferClose(out_buff);
7242
7243 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7244 *doc_txt_len = 0;
7245 xmlGenericError(xmlGenericErrorContext,
7246 "xmlDocDumpFormatMemoryEnc: %s\n",
7247 "Failed to allocate memory for document text representation.");
7248 }
7249
7250 return;
7251}
7252
7253/**
7254 * xmlDocDumpMemory:
7255 * @cur: the document
7256 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007257 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007258 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007259 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007260 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007261 */
7262void
7263xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7264 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7265}
7266
7267/**
7268 * xmlDocDumpFormatMemory:
7269 * @cur: the document
7270 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007271 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007272 * @format: should formatting spaces been added
7273 *
7274 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007275 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007276 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007277 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7278 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007279 */
7280void
7281xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7282 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7283}
7284
7285/**
7286 * xmlDocDumpMemoryEnc:
7287 * @out_doc: Document to generate XML text from
7288 * @doc_txt_ptr: Memory pointer for allocated XML text
7289 * @doc_txt_len: Length of the generated XML text
7290 * @txt_encoding: Character encoding to use when generating XML text
7291 *
7292 * Dump the current DOM tree into memory using the character encoding specified
7293 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007294 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007295 */
7296
7297void
7298xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7299 int * doc_txt_len, const char * txt_encoding) {
7300 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007301 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007302}
7303
7304/**
7305 * xmlGetDocCompressMode:
7306 * @doc: the document
7307 *
7308 * get the compression ratio for a document, ZLIB based
7309 * Returns 0 (uncompressed) to 9 (max compression)
7310 */
7311int
7312xmlGetDocCompressMode (xmlDocPtr doc) {
7313 if (doc == NULL) return(-1);
7314 return(doc->compression);
7315}
7316
7317/**
7318 * xmlSetDocCompressMode:
7319 * @doc: the document
7320 * @mode: the compression ratio
7321 *
7322 * set the compression ratio for a document, ZLIB based
7323 * Correct values: 0 (uncompressed) to 9 (max compression)
7324 */
7325void
7326xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7327 if (doc == NULL) return;
7328 if (mode < 0) doc->compression = 0;
7329 else if (mode > 9) doc->compression = 9;
7330 else doc->compression = mode;
7331}
7332
7333/**
7334 * xmlGetCompressMode:
7335 *
7336 * get the default compression mode used, ZLIB based.
7337 * Returns 0 (uncompressed) to 9 (max compression)
7338 */
7339int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007340xmlGetCompressMode(void)
7341{
7342 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007343}
7344
7345/**
7346 * xmlSetCompressMode:
7347 * @mode: the compression ratio
7348 *
7349 * set the default compression mode used, ZLIB based
7350 * Correct values: 0 (uncompressed) to 9 (max compression)
7351 */
7352void
7353xmlSetCompressMode(int mode) {
7354 if (mode < 0) xmlCompressMode = 0;
7355 else if (mode > 9) xmlCompressMode = 9;
7356 else xmlCompressMode = mode;
7357}
7358
7359/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007360 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007361 * @f: the FILE*
7362 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007363 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007364 *
7365 * Dump an XML document to an open FILE.
7366 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007367 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007368 */
7369int
Daniel Veillard9e412302002-06-10 15:59:44 +00007370xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007371 xmlOutputBufferPtr buf;
7372 const char * encoding;
7373 xmlCharEncodingHandlerPtr handler = NULL;
7374 int ret;
7375
7376 if (cur == NULL) {
7377#ifdef DEBUG_TREE
7378 xmlGenericError(xmlGenericErrorContext,
7379 "xmlDocDump : document == NULL\n");
7380#endif
7381 return(-1);
7382 }
7383 encoding = (const char *) cur->encoding;
7384
7385 if (encoding != NULL) {
7386 xmlCharEncoding enc;
7387
7388 enc = xmlParseCharEncoding(encoding);
7389
7390 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7391 xmlGenericError(xmlGenericErrorContext,
7392 "xmlDocDump: document not in UTF8\n");
7393 return(-1);
7394 }
7395 if (enc != XML_CHAR_ENCODING_UTF8) {
7396 handler = xmlFindCharEncodingHandler(encoding);
7397 if (handler == NULL) {
7398 xmlFree((char *) cur->encoding);
7399 cur->encoding = NULL;
7400 }
7401 }
7402 }
7403 buf = xmlOutputBufferCreateFile(f, handler);
7404 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007405 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007406
7407 ret = xmlOutputBufferClose(buf);
7408 return(ret);
7409}
7410
7411/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007412 * xmlDocDump:
7413 * @f: the FILE*
7414 * @cur: the document
7415 *
7416 * Dump an XML document to an open FILE.
7417 *
7418 * returns: the number of bytes written or -1 in case of failure.
7419 */
7420int
7421xmlDocDump(FILE *f, xmlDocPtr cur) {
7422 return(xmlDocFormatDump (f, cur, 0));
7423}
7424
7425/**
Owen Taylor3473f882001-02-23 17:55:21 +00007426 * xmlSaveFileTo:
7427 * @buf: an output I/O buffer
7428 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007429 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007430 *
7431 * Dump an XML document to an I/O buffer.
7432 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007433 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007434 */
7435int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007436xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007437 int ret;
7438
7439 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007440 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007441 ret = xmlOutputBufferClose(buf);
7442 return(ret);
7443}
7444
7445/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007446 * xmlSaveFormatFileTo:
7447 * @buf: an output I/O buffer
7448 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007449 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007450 * @format: should formatting spaces been added
7451 *
7452 * Dump an XML document to an I/O buffer.
7453 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007454 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007455 */
7456int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007457xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007458 int ret;
7459
7460 if (buf == NULL) return(0);
7461 xmlDocContentDumpOutput(buf, cur, encoding, format);
7462 ret = xmlOutputBufferClose(buf);
7463 return(ret);
7464}
7465
7466/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00007467 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00007468 * @filename: the filename or URL to output
7469 * @cur: the document being saved
7470 * @encoding: the name of the encoding to use or NULL.
7471 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007472 *
7473 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007474 */
7475int
Daniel Veillardf012a642001-07-23 19:10:52 +00007476xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7477 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007478 xmlOutputBufferPtr buf;
7479 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007480 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007481 int ret;
7482
Daniel Veillardfb25a512002-01-13 20:32:08 +00007483 if (encoding == NULL)
7484 encoding = (const char *) cur->encoding;
7485
Owen Taylor3473f882001-02-23 17:55:21 +00007486 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007487
7488 enc = xmlParseCharEncoding(encoding);
7489 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7490 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007491 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007492 return(-1);
7493 }
7494 if (enc != XML_CHAR_ENCODING_UTF8) {
7495 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007496 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007497 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007498 }
7499 }
7500
Daniel Veillardf012a642001-07-23 19:10:52 +00007501#ifdef HAVE_ZLIB_H
7502 if (cur->compression < 0) cur->compression = xmlCompressMode;
7503#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007504 /*
7505 * save the content to a temp buffer.
7506 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007507 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007508 if (buf == NULL) return(-1);
7509
Daniel Veillardf012a642001-07-23 19:10:52 +00007510 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007511
7512 ret = xmlOutputBufferClose(buf);
7513 return(ret);
7514}
7515
Daniel Veillardf012a642001-07-23 19:10:52 +00007516
7517/**
7518 * xmlSaveFileEnc:
7519 * @filename: the filename (or URL)
7520 * @cur: the document
7521 * @encoding: the name of an encoding (or NULL)
7522 *
7523 * Dump an XML document, converting it to the given encoding
7524 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007525 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007526 */
7527int
7528xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7529 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7530}
7531
Owen Taylor3473f882001-02-23 17:55:21 +00007532/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007533 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007534 * @filename: the filename (or URL)
7535 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007536 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007537 *
7538 * Dump an XML document to a file. Will use compression if
7539 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007540 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007541 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007542 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007543 */
7544int
Daniel Veillard67fee942001-04-26 18:59:03 +00007545xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007546 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007547}
7548
Daniel Veillard67fee942001-04-26 18:59:03 +00007549/**
7550 * xmlSaveFile:
7551 * @filename: the filename (or URL)
7552 * @cur: the document
7553 *
7554 * Dump an XML document to a file. Will use compression if
7555 * compiled in and enabled. If @filename is "-" the stdout file is
7556 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007557 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007558 */
7559int
7560xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007561 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007562}
7563