blob: c3d304501f2254a99c06b26428238dad3cf7424f [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 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000902 * Build the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +0000903 * made of TEXTs and ENTITY_REFs
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000904 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000905 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000906 */
907xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000908xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
909{
Owen Taylor3473f882001-02-23 17:55:21 +0000910 xmlNodePtr node = list;
911 xmlChar *ret = NULL;
912 xmlEntityPtr ent;
913
Daniel Veillard7646b182002-04-20 06:41:40 +0000914 if (list == NULL)
915 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000916
917 while (node != NULL) {
918 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000919 (node->type == XML_CDATA_SECTION_NODE)) {
920 if (inLine) {
921 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000922 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000923 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000924
Daniel Veillard7646b182002-04-20 06:41:40 +0000925 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
926 if (buffer != NULL) {
927 ret = xmlStrcat(ret, buffer);
928 xmlFree(buffer);
929 }
930 }
931 } else if (node->type == XML_ENTITY_REF_NODE) {
932 if (inLine) {
933 ent = xmlGetDocEntity(doc, node->name);
934 if (ent != NULL) {
935 xmlChar *buffer;
936
937 /* an entity content can be any "well balanced chunk",
938 * i.e. the result of the content [43] production:
939 * http://www.w3.org/TR/REC-xml#NT-content.
940 * So it can contain text, CDATA section or nested
941 * entity reference nodes (among others).
942 * -> we recursive call xmlNodeListGetString()
943 * which handles these types */
944 buffer = xmlNodeListGetString(doc, ent->children, 1);
945 if (buffer != NULL) {
946 ret = xmlStrcat(ret, buffer);
947 xmlFree(buffer);
948 }
949 } else {
950 ret = xmlStrcat(ret, node->content);
951 }
952 } else {
953 xmlChar buf[2];
954
955 buf[0] = '&';
956 buf[1] = 0;
957 ret = xmlStrncat(ret, buf, 1);
958 ret = xmlStrcat(ret, node->name);
959 buf[0] = ';';
960 buf[1] = 0;
961 ret = xmlStrncat(ret, buf, 1);
962 }
963 }
964#if 0
965 else {
966 xmlGenericError(xmlGenericErrorContext,
967 "xmlGetNodeListString : invalid node type %d\n",
968 node->type);
969 }
970#endif
971 node = node->next;
972 }
973 return (ret);
974}
Owen Taylor3473f882001-02-23 17:55:21 +0000975/**
976 * xmlNodeListGetRawString:
977 * @doc: the document
978 * @list: a Node list
979 * @inLine: should we replace entity contents or show their external form
980 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000981 * Builds the string equivalent to the text contained in the Node list
Owen Taylor3473f882001-02-23 17:55:21 +0000982 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
983 * this function doesn't do any character encoding handling.
984 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000985 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000986 */
987xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000988xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
989{
Owen Taylor3473f882001-02-23 17:55:21 +0000990 xmlNodePtr node = list;
991 xmlChar *ret = NULL;
992 xmlEntityPtr ent;
993
Daniel Veillard7646b182002-04-20 06:41:40 +0000994 if (list == NULL)
995 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000996
997 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000998 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000999 (node->type == XML_CDATA_SECTION_NODE)) {
1000 if (inLine) {
1001 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001002 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001003 xmlChar *buffer;
1004
1005 buffer = xmlEncodeSpecialChars(doc, node->content);
1006 if (buffer != NULL) {
1007 ret = xmlStrcat(ret, buffer);
1008 xmlFree(buffer);
1009 }
1010 }
1011 } else if (node->type == XML_ENTITY_REF_NODE) {
1012 if (inLine) {
1013 ent = xmlGetDocEntity(doc, node->name);
1014 if (ent != NULL) {
1015 xmlChar *buffer;
1016
1017 /* an entity content can be any "well balanced chunk",
1018 * i.e. the result of the content [43] production:
1019 * http://www.w3.org/TR/REC-xml#NT-content.
1020 * So it can contain text, CDATA section or nested
1021 * entity reference nodes (among others).
1022 * -> we recursive call xmlNodeListGetRawString()
1023 * which handles these types */
1024 buffer =
1025 xmlNodeListGetRawString(doc, ent->children, 1);
1026 if (buffer != NULL) {
1027 ret = xmlStrcat(ret, buffer);
1028 xmlFree(buffer);
1029 }
1030 } else {
1031 ret = xmlStrcat(ret, node->content);
1032 }
1033 } else {
1034 xmlChar buf[2];
1035
1036 buf[0] = '&';
1037 buf[1] = 0;
1038 ret = xmlStrncat(ret, buf, 1);
1039 ret = xmlStrcat(ret, node->name);
1040 buf[0] = ';';
1041 buf[1] = 0;
1042 ret = xmlStrncat(ret, buf, 1);
1043 }
1044 }
Owen Taylor3473f882001-02-23 17:55:21 +00001045#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001046 else {
1047 xmlGenericError(xmlGenericErrorContext,
1048 "xmlGetNodeListString : invalid node type %d\n",
1049 node->type);
1050 }
Owen Taylor3473f882001-02-23 17:55:21 +00001051#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001052 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001053 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001054 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001055}
1056
1057/**
1058 * xmlNewProp:
1059 * @node: the holding node
1060 * @name: the name of the attribute
1061 * @value: the value of the attribute
1062 *
1063 * Create a new property carried by a node.
1064 * Returns a pointer to the attribute
1065 */
1066xmlAttrPtr
1067xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1068 xmlAttrPtr cur;
1069 xmlDocPtr doc = NULL;
1070
1071 if (name == NULL) {
1072#ifdef DEBUG_TREE
1073 xmlGenericError(xmlGenericErrorContext,
1074 "xmlNewProp : name == NULL\n");
1075#endif
1076 return(NULL);
1077 }
1078
1079 /*
1080 * Allocate a new property and fill the fields.
1081 */
1082 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1083 if (cur == NULL) {
1084 xmlGenericError(xmlGenericErrorContext,
1085 "xmlNewProp : malloc failed\n");
1086 return(NULL);
1087 }
1088 memset(cur, 0, sizeof(xmlAttr));
1089 cur->type = XML_ATTRIBUTE_NODE;
1090
1091 cur->parent = node;
1092 if (node != NULL) {
1093 doc = node->doc;
1094 cur->doc = doc;
1095 }
1096 cur->name = xmlStrdup(name);
1097 if (value != NULL) {
1098 xmlChar *buffer;
1099 xmlNodePtr tmp;
1100
1101 buffer = xmlEncodeEntitiesReentrant(doc, value);
1102 cur->children = xmlStringGetNodeList(doc, buffer);
1103 cur->last = NULL;
1104 tmp = cur->children;
1105 while (tmp != NULL) {
1106 tmp->parent = (xmlNodePtr) cur;
1107 tmp->doc = doc;
1108 if (tmp->next == NULL)
1109 cur->last = tmp;
1110 tmp = tmp->next;
1111 }
1112 xmlFree(buffer);
1113 }
1114
1115 /*
1116 * Add it at the end to preserve parsing order ...
1117 */
1118 if (node != NULL) {
1119 if (node->properties == NULL) {
1120 node->properties = cur;
1121 } else {
1122 xmlAttrPtr prev = node->properties;
1123
1124 while (prev->next != NULL) prev = prev->next;
1125 prev->next = cur;
1126 cur->prev = prev;
1127 }
1128 }
1129 return(cur);
1130}
1131
1132/**
1133 * xmlNewNsProp:
1134 * @node: the holding node
1135 * @ns: the namespace
1136 * @name: the name of the attribute
1137 * @value: the value of the attribute
1138 *
1139 * Create a new property tagged with a namespace and carried by a node.
1140 * Returns a pointer to the attribute
1141 */
1142xmlAttrPtr
1143xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1144 const xmlChar *value) {
1145 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001146 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001147
1148 if (name == NULL) {
1149#ifdef DEBUG_TREE
1150 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001151 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001152#endif
1153 return(NULL);
1154 }
1155
1156 /*
1157 * Allocate a new property and fill the fields.
1158 */
1159 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1160 if (cur == NULL) {
1161 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001162 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001163 return(NULL);
1164 }
1165 memset(cur, 0, sizeof(xmlAttr));
1166 cur->type = XML_ATTRIBUTE_NODE;
1167
1168 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001169 if (node != NULL) {
1170 doc = node->doc;
1171 cur->doc = doc;
1172 }
Owen Taylor3473f882001-02-23 17:55:21 +00001173 cur->ns = ns;
1174 cur->name = xmlStrdup(name);
1175 if (value != NULL) {
1176 xmlChar *buffer;
1177 xmlNodePtr tmp;
1178
Daniel Veillarda682b212001-06-07 19:59:42 +00001179 buffer = xmlEncodeEntitiesReentrant(doc, value);
1180 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001181 cur->last = NULL;
1182 tmp = cur->children;
1183 while (tmp != NULL) {
1184 tmp->parent = (xmlNodePtr) cur;
1185 if (tmp->next == NULL)
1186 cur->last = tmp;
1187 tmp = tmp->next;
1188 }
1189 xmlFree(buffer);
1190 }
1191
1192 /*
1193 * Add it at the end to preserve parsing order ...
1194 */
1195 if (node != NULL) {
1196 if (node->properties == NULL) {
1197 node->properties = cur;
1198 } else {
1199 xmlAttrPtr prev = node->properties;
1200
1201 while (prev->next != NULL) prev = prev->next;
1202 prev->next = cur;
1203 cur->prev = prev;
1204 }
1205 }
1206 return(cur);
1207}
1208
1209/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001210 * xmlNewNsPropEatName:
1211 * @node: the holding node
1212 * @ns: the namespace
1213 * @name: the name of the attribute
1214 * @value: the value of the attribute
1215 *
1216 * Create a new property tagged with a namespace and carried by a node.
1217 * Returns a pointer to the attribute
1218 */
1219xmlAttrPtr
1220xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1221 const xmlChar *value) {
1222 xmlAttrPtr cur;
1223 xmlDocPtr doc = NULL;
1224
1225 if (name == NULL) {
1226#ifdef DEBUG_TREE
1227 xmlGenericError(xmlGenericErrorContext,
1228 "xmlNewNsPropEatName : name == NULL\n");
1229#endif
1230 return(NULL);
1231 }
1232
1233 /*
1234 * Allocate a new property and fill the fields.
1235 */
1236 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1237 if (cur == NULL) {
1238 xmlGenericError(xmlGenericErrorContext,
1239 "xmlNewNsPropEatName : malloc failed\n");
1240 return(NULL);
1241 }
1242 memset(cur, 0, sizeof(xmlAttr));
1243 cur->type = XML_ATTRIBUTE_NODE;
1244
1245 cur->parent = node;
1246 if (node != NULL) {
1247 doc = node->doc;
1248 cur->doc = doc;
1249 }
1250 cur->ns = ns;
1251 cur->name = name;
1252 if (value != NULL) {
1253 xmlChar *buffer;
1254 xmlNodePtr tmp;
1255
1256 buffer = xmlEncodeEntitiesReentrant(doc, value);
1257 cur->children = xmlStringGetNodeList(doc, buffer);
1258 cur->last = NULL;
1259 tmp = cur->children;
1260 while (tmp != NULL) {
1261 tmp->parent = (xmlNodePtr) cur;
1262 if (tmp->next == NULL)
1263 cur->last = tmp;
1264 tmp = tmp->next;
1265 }
1266 xmlFree(buffer);
1267 }
1268
1269 /*
1270 * Add it at the end to preserve parsing order ...
1271 */
1272 if (node != NULL) {
1273 if (node->properties == NULL) {
1274 node->properties = cur;
1275 } else {
1276 xmlAttrPtr prev = node->properties;
1277
1278 while (prev->next != NULL) prev = prev->next;
1279 prev->next = cur;
1280 cur->prev = prev;
1281 }
1282 }
1283 return(cur);
1284}
1285
1286/**
Owen Taylor3473f882001-02-23 17:55:21 +00001287 * xmlNewDocProp:
1288 * @doc: the document
1289 * @name: the name of the attribute
1290 * @value: the value of the attribute
1291 *
1292 * Create a new property carried by a document.
1293 * Returns a pointer to the attribute
1294 */
1295xmlAttrPtr
1296xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1297 xmlAttrPtr cur;
1298
1299 if (name == NULL) {
1300#ifdef DEBUG_TREE
1301 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001302 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001303#endif
1304 return(NULL);
1305 }
1306
1307 /*
1308 * Allocate a new property and fill the fields.
1309 */
1310 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1311 if (cur == NULL) {
1312 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001313 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001314 return(NULL);
1315 }
1316 memset(cur, 0, sizeof(xmlAttr));
1317 cur->type = XML_ATTRIBUTE_NODE;
1318
1319 cur->name = xmlStrdup(name);
1320 cur->doc = doc;
1321 if (value != NULL) {
1322 xmlNodePtr tmp;
1323
1324 cur->children = xmlStringGetNodeList(doc, value);
1325 cur->last = NULL;
1326
1327 tmp = cur->children;
1328 while (tmp != NULL) {
1329 tmp->parent = (xmlNodePtr) cur;
1330 if (tmp->next == NULL)
1331 cur->last = tmp;
1332 tmp = tmp->next;
1333 }
1334 }
1335 return(cur);
1336}
1337
1338/**
1339 * xmlFreePropList:
1340 * @cur: the first property in the list
1341 *
1342 * Free a property and all its siblings, all the children are freed too.
1343 */
1344void
1345xmlFreePropList(xmlAttrPtr cur) {
1346 xmlAttrPtr next;
1347 if (cur == NULL) {
1348#ifdef DEBUG_TREE
1349 xmlGenericError(xmlGenericErrorContext,
1350 "xmlFreePropList : property == NULL\n");
1351#endif
1352 return;
1353 }
1354 while (cur != NULL) {
1355 next = cur->next;
1356 xmlFreeProp(cur);
1357 cur = next;
1358 }
1359}
1360
1361/**
1362 * xmlFreeProp:
1363 * @cur: an attribute
1364 *
1365 * Free one attribute, all the content is freed too
1366 */
1367void
1368xmlFreeProp(xmlAttrPtr cur) {
1369 if (cur == NULL) {
1370#ifdef DEBUG_TREE
1371 xmlGenericError(xmlGenericErrorContext,
1372 "xmlFreeProp : property == NULL\n");
1373#endif
1374 return;
1375 }
1376 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001377 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1378 ((cur->parent->doc->intSubset != NULL) ||
1379 (cur->parent->doc->extSubset != NULL))) {
1380 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1381 xmlRemoveID(cur->parent->doc, cur);
1382 }
Owen Taylor3473f882001-02-23 17:55:21 +00001383 if (cur->name != NULL) xmlFree((char *) cur->name);
1384 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001385 xmlFree(cur);
1386}
1387
1388/**
1389 * xmlRemoveProp:
1390 * @cur: an attribute
1391 *
1392 * Unlink and free one attribute, all the content is freed too
1393 * Note this doesn't work for namespace definition attributes
1394 *
1395 * Returns 0 if success and -1 in case of error.
1396 */
1397int
1398xmlRemoveProp(xmlAttrPtr cur) {
1399 xmlAttrPtr tmp;
1400 if (cur == NULL) {
1401#ifdef DEBUG_TREE
1402 xmlGenericError(xmlGenericErrorContext,
1403 "xmlRemoveProp : cur == NULL\n");
1404#endif
1405 return(-1);
1406 }
1407 if (cur->parent == NULL) {
1408#ifdef DEBUG_TREE
1409 xmlGenericError(xmlGenericErrorContext,
1410 "xmlRemoveProp : cur->parent == NULL\n");
1411#endif
1412 return(-1);
1413 }
1414 tmp = cur->parent->properties;
1415 if (tmp == cur) {
1416 cur->parent->properties = cur->next;
1417 xmlFreeProp(cur);
1418 return(0);
1419 }
1420 while (tmp != NULL) {
1421 if (tmp->next == cur) {
1422 tmp->next = cur->next;
1423 if (tmp->next != NULL)
1424 tmp->next->prev = tmp;
1425 xmlFreeProp(cur);
1426 return(0);
1427 }
1428 tmp = tmp->next;
1429 }
1430#ifdef DEBUG_TREE
1431 xmlGenericError(xmlGenericErrorContext,
1432 "xmlRemoveProp : attribute not owned by its node\n");
1433#endif
1434 return(-1);
1435}
1436
1437/**
1438 * xmlNewPI:
1439 * @name: the processing instruction name
1440 * @content: the PI content
1441 *
1442 * Creation of a processing instruction element.
1443 * Returns a pointer to the new node object.
1444 */
1445xmlNodePtr
1446xmlNewPI(const xmlChar *name, const xmlChar *content) {
1447 xmlNodePtr cur;
1448
1449 if (name == NULL) {
1450#ifdef DEBUG_TREE
1451 xmlGenericError(xmlGenericErrorContext,
1452 "xmlNewPI : name == NULL\n");
1453#endif
1454 return(NULL);
1455 }
1456
1457 /*
1458 * Allocate a new node and fill the fields.
1459 */
1460 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1461 if (cur == NULL) {
1462 xmlGenericError(xmlGenericErrorContext,
1463 "xmlNewPI : malloc failed\n");
1464 return(NULL);
1465 }
1466 memset(cur, 0, sizeof(xmlNode));
1467 cur->type = XML_PI_NODE;
1468
1469 cur->name = xmlStrdup(name);
1470 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001471 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001472 }
1473 return(cur);
1474}
1475
1476/**
1477 * xmlNewNode:
1478 * @ns: namespace if any
1479 * @name: the node name
1480 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001481 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001482 *
1483 * Returns a pointer to the new node object.
1484 */
1485xmlNodePtr
1486xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1487 xmlNodePtr cur;
1488
1489 if (name == NULL) {
1490#ifdef DEBUG_TREE
1491 xmlGenericError(xmlGenericErrorContext,
1492 "xmlNewNode : name == NULL\n");
1493#endif
1494 return(NULL);
1495 }
1496
1497 /*
1498 * Allocate a new node and fill the fields.
1499 */
1500 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1501 if (cur == NULL) {
1502 xmlGenericError(xmlGenericErrorContext,
1503 "xmlNewNode : malloc failed\n");
1504 return(NULL);
1505 }
1506 memset(cur, 0, sizeof(xmlNode));
1507 cur->type = XML_ELEMENT_NODE;
1508
1509 cur->name = xmlStrdup(name);
1510 cur->ns = ns;
1511 return(cur);
1512}
1513
1514/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001515 * xmlNewNodeEatName:
1516 * @ns: namespace if any
1517 * @name: the node name
1518 *
1519 * Creation of a new node element. @ns is optional (NULL).
1520 *
1521 * Returns a pointer to the new node object.
1522 */
1523xmlNodePtr
1524xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1525 xmlNodePtr cur;
1526
1527 if (name == NULL) {
1528#ifdef DEBUG_TREE
1529 xmlGenericError(xmlGenericErrorContext,
1530 "xmlNewNode : name == NULL\n");
1531#endif
1532 return(NULL);
1533 }
1534
1535 /*
1536 * Allocate a new node and fill the fields.
1537 */
1538 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1539 if (cur == NULL) {
1540 xmlGenericError(xmlGenericErrorContext,
1541 "xmlNewNode : malloc failed\n");
1542 return(NULL);
1543 }
1544 memset(cur, 0, sizeof(xmlNode));
1545 cur->type = XML_ELEMENT_NODE;
1546
1547 cur->name = name;
1548 cur->ns = ns;
1549 return(cur);
1550}
1551
1552/**
Owen Taylor3473f882001-02-23 17:55:21 +00001553 * xmlNewDocNode:
1554 * @doc: the document
1555 * @ns: namespace if any
1556 * @name: the node name
1557 * @content: the XML text content if any
1558 *
1559 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001560 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001561 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1562 * references, but XML special chars need to be escaped first by using
1563 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1564 * need entities support.
1565 *
1566 * Returns a pointer to the new node object.
1567 */
1568xmlNodePtr
1569xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1570 const xmlChar *name, const xmlChar *content) {
1571 xmlNodePtr cur;
1572
1573 cur = xmlNewNode(ns, name);
1574 if (cur != NULL) {
1575 cur->doc = doc;
1576 if (content != NULL) {
1577 cur->children = xmlStringGetNodeList(doc, content);
1578 UPDATE_LAST_CHILD_AND_PARENT(cur)
1579 }
1580 }
1581 return(cur);
1582}
1583
Daniel Veillard46de64e2002-05-29 08:21:33 +00001584/**
1585 * xmlNewDocNodeEatName:
1586 * @doc: the document
1587 * @ns: namespace if any
1588 * @name: the node name
1589 * @content: the XML text content if any
1590 *
1591 * Creation of a new node element within a document. @ns and @content
1592 * are optional (NULL).
1593 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1594 * references, but XML special chars need to be escaped first by using
1595 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1596 * need entities support.
1597 *
1598 * Returns a pointer to the new node object.
1599 */
1600xmlNodePtr
1601xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1602 xmlChar *name, const xmlChar *content) {
1603 xmlNodePtr cur;
1604
1605 cur = xmlNewNodeEatName(ns, name);
1606 if (cur != NULL) {
1607 cur->doc = doc;
1608 if (content != NULL) {
1609 cur->children = xmlStringGetNodeList(doc, content);
1610 UPDATE_LAST_CHILD_AND_PARENT(cur)
1611 }
1612 }
1613 return(cur);
1614}
1615
Owen Taylor3473f882001-02-23 17:55:21 +00001616
1617/**
1618 * xmlNewDocRawNode:
1619 * @doc: the document
1620 * @ns: namespace if any
1621 * @name: the node name
1622 * @content: the text content if any
1623 *
1624 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001625 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001626 *
1627 * Returns a pointer to the new node object.
1628 */
1629xmlNodePtr
1630xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1631 const xmlChar *name, const xmlChar *content) {
1632 xmlNodePtr cur;
1633
1634 cur = xmlNewNode(ns, name);
1635 if (cur != NULL) {
1636 cur->doc = doc;
1637 if (content != NULL) {
1638 cur->children = xmlNewDocText(doc, content);
1639 UPDATE_LAST_CHILD_AND_PARENT(cur)
1640 }
1641 }
1642 return(cur);
1643}
1644
1645/**
1646 * xmlNewDocFragment:
1647 * @doc: the document owning the fragment
1648 *
1649 * Creation of a new Fragment node.
1650 * Returns a pointer to the new node object.
1651 */
1652xmlNodePtr
1653xmlNewDocFragment(xmlDocPtr doc) {
1654 xmlNodePtr cur;
1655
1656 /*
1657 * Allocate a new DocumentFragment node and fill the fields.
1658 */
1659 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1660 if (cur == NULL) {
1661 xmlGenericError(xmlGenericErrorContext,
1662 "xmlNewDocFragment : malloc failed\n");
1663 return(NULL);
1664 }
1665 memset(cur, 0, sizeof(xmlNode));
1666 cur->type = XML_DOCUMENT_FRAG_NODE;
1667
1668 cur->doc = doc;
1669 return(cur);
1670}
1671
1672/**
1673 * xmlNewText:
1674 * @content: the text content
1675 *
1676 * Creation of a new text node.
1677 * Returns a pointer to the new node object.
1678 */
1679xmlNodePtr
1680xmlNewText(const xmlChar *content) {
1681 xmlNodePtr cur;
1682
1683 /*
1684 * Allocate a new node and fill the fields.
1685 */
1686 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1687 if (cur == NULL) {
1688 xmlGenericError(xmlGenericErrorContext,
1689 "xmlNewText : malloc failed\n");
1690 return(NULL);
1691 }
1692 memset(cur, 0, sizeof(xmlNode));
1693 cur->type = XML_TEXT_NODE;
1694
1695 cur->name = xmlStringText;
1696 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001697 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001698 }
1699 return(cur);
1700}
1701
1702/**
1703 * xmlNewTextChild:
1704 * @parent: the parent node
1705 * @ns: a namespace if any
1706 * @name: the name of the child
1707 * @content: the text content of the child if any.
1708 *
1709 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001710 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001711 * a child TEXT node will be created containing the string content.
1712 *
1713 * Returns a pointer to the new node object.
1714 */
1715xmlNodePtr
1716xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1717 const xmlChar *name, const xmlChar *content) {
1718 xmlNodePtr cur, prev;
1719
1720 if (parent == NULL) {
1721#ifdef DEBUG_TREE
1722 xmlGenericError(xmlGenericErrorContext,
1723 "xmlNewTextChild : parent == NULL\n");
1724#endif
1725 return(NULL);
1726 }
1727
1728 if (name == NULL) {
1729#ifdef DEBUG_TREE
1730 xmlGenericError(xmlGenericErrorContext,
1731 "xmlNewTextChild : name == NULL\n");
1732#endif
1733 return(NULL);
1734 }
1735
1736 /*
1737 * Allocate a new node
1738 */
1739 if (ns == NULL)
1740 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1741 else
1742 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1743 if (cur == NULL) return(NULL);
1744
1745 /*
1746 * add the new element at the end of the children list.
1747 */
1748 cur->type = XML_ELEMENT_NODE;
1749 cur->parent = parent;
1750 cur->doc = parent->doc;
1751 if (parent->children == NULL) {
1752 parent->children = cur;
1753 parent->last = cur;
1754 } else {
1755 prev = parent->last;
1756 prev->next = cur;
1757 cur->prev = prev;
1758 parent->last = cur;
1759 }
1760
1761 return(cur);
1762}
1763
1764/**
1765 * xmlNewCharRef:
1766 * @doc: the document
1767 * @name: the char ref string, starting with # or "&# ... ;"
1768 *
1769 * Creation of a new character reference node.
1770 * Returns a pointer to the new node object.
1771 */
1772xmlNodePtr
1773xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1774 xmlNodePtr cur;
1775
1776 /*
1777 * Allocate a new node and fill the fields.
1778 */
1779 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1780 if (cur == NULL) {
1781 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001782 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001783 return(NULL);
1784 }
1785 memset(cur, 0, sizeof(xmlNode));
1786 cur->type = XML_ENTITY_REF_NODE;
1787
1788 cur->doc = doc;
1789 if (name[0] == '&') {
1790 int len;
1791 name++;
1792 len = xmlStrlen(name);
1793 if (name[len - 1] == ';')
1794 cur->name = xmlStrndup(name, len - 1);
1795 else
1796 cur->name = xmlStrndup(name, len);
1797 } else
1798 cur->name = xmlStrdup(name);
1799 return(cur);
1800}
1801
1802/**
1803 * xmlNewReference:
1804 * @doc: the document
1805 * @name: the reference name, or the reference string with & and ;
1806 *
1807 * Creation of a new reference node.
1808 * Returns a pointer to the new node object.
1809 */
1810xmlNodePtr
1811xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1812 xmlNodePtr cur;
1813 xmlEntityPtr ent;
1814
1815 /*
1816 * Allocate a new node and fill the fields.
1817 */
1818 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1819 if (cur == NULL) {
1820 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001821 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001822 return(NULL);
1823 }
1824 memset(cur, 0, sizeof(xmlNode));
1825 cur->type = XML_ENTITY_REF_NODE;
1826
1827 cur->doc = doc;
1828 if (name[0] == '&') {
1829 int len;
1830 name++;
1831 len = xmlStrlen(name);
1832 if (name[len - 1] == ';')
1833 cur->name = xmlStrndup(name, len - 1);
1834 else
1835 cur->name = xmlStrndup(name, len);
1836 } else
1837 cur->name = xmlStrdup(name);
1838
1839 ent = xmlGetDocEntity(doc, cur->name);
1840 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001841 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001842 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001843 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001844 * updated. Not sure if this is 100% correct.
1845 * -George
1846 */
1847 cur->children = (xmlNodePtr) ent;
1848 cur->last = (xmlNodePtr) ent;
1849 }
1850 return(cur);
1851}
1852
1853/**
1854 * xmlNewDocText:
1855 * @doc: the document
1856 * @content: the text content
1857 *
1858 * Creation of a new text node within a document.
1859 * Returns a pointer to the new node object.
1860 */
1861xmlNodePtr
1862xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1863 xmlNodePtr cur;
1864
1865 cur = xmlNewText(content);
1866 if (cur != NULL) cur->doc = doc;
1867 return(cur);
1868}
1869
1870/**
1871 * xmlNewTextLen:
1872 * @content: the text content
1873 * @len: the text len.
1874 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001875 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001876 * Returns a pointer to the new node object.
1877 */
1878xmlNodePtr
1879xmlNewTextLen(const xmlChar *content, int len) {
1880 xmlNodePtr cur;
1881
1882 /*
1883 * Allocate a new node and fill the fields.
1884 */
1885 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1886 if (cur == NULL) {
1887 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001888 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001889 return(NULL);
1890 }
1891 memset(cur, 0, sizeof(xmlNode));
1892 cur->type = XML_TEXT_NODE;
1893
1894 cur->name = xmlStringText;
1895 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001896 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001897 }
1898 return(cur);
1899}
1900
1901/**
1902 * xmlNewDocTextLen:
1903 * @doc: the document
1904 * @content: the text content
1905 * @len: the text len.
1906 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001907 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001908 * text node pertain to a given document.
1909 * Returns a pointer to the new node object.
1910 */
1911xmlNodePtr
1912xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1913 xmlNodePtr cur;
1914
1915 cur = xmlNewTextLen(content, len);
1916 if (cur != NULL) cur->doc = doc;
1917 return(cur);
1918}
1919
1920/**
1921 * xmlNewComment:
1922 * @content: the comment content
1923 *
1924 * Creation of a new node containing a comment.
1925 * Returns a pointer to the new node object.
1926 */
1927xmlNodePtr
1928xmlNewComment(const xmlChar *content) {
1929 xmlNodePtr cur;
1930
1931 /*
1932 * Allocate a new node and fill the fields.
1933 */
1934 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1935 if (cur == NULL) {
1936 xmlGenericError(xmlGenericErrorContext,
1937 "xmlNewComment : malloc failed\n");
1938 return(NULL);
1939 }
1940 memset(cur, 0, sizeof(xmlNode));
1941 cur->type = XML_COMMENT_NODE;
1942
1943 cur->name = xmlStringComment;
1944 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001945 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001946 }
1947 return(cur);
1948}
1949
1950/**
1951 * xmlNewCDataBlock:
1952 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001953 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001954 * @len: the length of the block
1955 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001956 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001957 * Returns a pointer to the new node object.
1958 */
1959xmlNodePtr
1960xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1961 xmlNodePtr cur;
1962
1963 /*
1964 * Allocate a new node and fill the fields.
1965 */
1966 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1967 if (cur == NULL) {
1968 xmlGenericError(xmlGenericErrorContext,
1969 "xmlNewCDataBlock : malloc failed\n");
1970 return(NULL);
1971 }
1972 memset(cur, 0, sizeof(xmlNode));
1973 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001974 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001975
1976 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001977 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001978 }
1979 return(cur);
1980}
1981
1982/**
1983 * xmlNewDocComment:
1984 * @doc: the document
1985 * @content: the comment content
1986 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001987 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001988 * Returns a pointer to the new node object.
1989 */
1990xmlNodePtr
1991xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1992 xmlNodePtr cur;
1993
1994 cur = xmlNewComment(content);
1995 if (cur != NULL) cur->doc = doc;
1996 return(cur);
1997}
1998
1999/**
2000 * xmlSetTreeDoc:
2001 * @tree: the top element
2002 * @doc: the document
2003 *
2004 * update all nodes under the tree to point to the right document
2005 */
2006void
2007xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002008 xmlAttrPtr prop;
2009
Owen Taylor3473f882001-02-23 17:55:21 +00002010 if (tree == NULL)
2011 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002012 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002013 if(tree->type == XML_ELEMENT_NODE) {
2014 prop = tree->properties;
2015 while (prop != NULL) {
2016 prop->doc = doc;
2017 xmlSetListDoc(prop->children, doc);
2018 prop = prop->next;
2019 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002020 }
Owen Taylor3473f882001-02-23 17:55:21 +00002021 if (tree->children != NULL)
2022 xmlSetListDoc(tree->children, doc);
2023 tree->doc = doc;
2024 }
2025}
2026
2027/**
2028 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002029 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002030 * @doc: the document
2031 *
2032 * update all nodes in the list to point to the right document
2033 */
2034void
2035xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2036 xmlNodePtr cur;
2037
2038 if (list == NULL)
2039 return;
2040 cur = list;
2041 while (cur != NULL) {
2042 if (cur->doc != doc)
2043 xmlSetTreeDoc(cur, doc);
2044 cur = cur->next;
2045 }
2046}
2047
2048
2049/**
2050 * xmlNewChild:
2051 * @parent: the parent node
2052 * @ns: a namespace if any
2053 * @name: the name of the child
2054 * @content: the XML content of the child if any.
2055 *
2056 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002057 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002058 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2059 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2060 * references, but XML special chars need to be escaped first by using
2061 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2062 * support is not needed.
2063 *
2064 * Returns a pointer to the new node object.
2065 */
2066xmlNodePtr
2067xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2068 const xmlChar *name, const xmlChar *content) {
2069 xmlNodePtr cur, prev;
2070
2071 if (parent == NULL) {
2072#ifdef DEBUG_TREE
2073 xmlGenericError(xmlGenericErrorContext,
2074 "xmlNewChild : parent == NULL\n");
2075#endif
2076 return(NULL);
2077 }
2078
2079 if (name == NULL) {
2080#ifdef DEBUG_TREE
2081 xmlGenericError(xmlGenericErrorContext,
2082 "xmlNewChild : name == NULL\n");
2083#endif
2084 return(NULL);
2085 }
2086
2087 /*
2088 * Allocate a new node
2089 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002090 if (parent->type == XML_ELEMENT_NODE) {
2091 if (ns == NULL)
2092 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2093 else
2094 cur = xmlNewDocNode(parent->doc, ns, name, content);
2095 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2096 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2097 if (ns == NULL)
2098 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2099 else
2100 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002101 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2102 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002103 } else {
2104 return(NULL);
2105 }
Owen Taylor3473f882001-02-23 17:55:21 +00002106 if (cur == NULL) return(NULL);
2107
2108 /*
2109 * add the new element at the end of the children list.
2110 */
2111 cur->type = XML_ELEMENT_NODE;
2112 cur->parent = parent;
2113 cur->doc = parent->doc;
2114 if (parent->children == NULL) {
2115 parent->children = cur;
2116 parent->last = cur;
2117 } else {
2118 prev = parent->last;
2119 prev->next = cur;
2120 cur->prev = prev;
2121 parent->last = cur;
2122 }
2123
2124 return(cur);
2125}
2126
2127/**
2128 * xmlAddNextSibling:
2129 * @cur: the child node
2130 * @elem: the new node
2131 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002132 * Add a new node @elem as the next sibling of @cur
2133 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002134 * first unlinked from its existing context.
2135 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002136 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2137 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002138 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002139 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002140 */
2141xmlNodePtr
2142xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2143 if (cur == NULL) {
2144#ifdef DEBUG_TREE
2145 xmlGenericError(xmlGenericErrorContext,
2146 "xmlAddNextSibling : cur == NULL\n");
2147#endif
2148 return(NULL);
2149 }
2150 if (elem == NULL) {
2151#ifdef DEBUG_TREE
2152 xmlGenericError(xmlGenericErrorContext,
2153 "xmlAddNextSibling : elem == NULL\n");
2154#endif
2155 return(NULL);
2156 }
2157
2158 xmlUnlinkNode(elem);
2159
2160 if (elem->type == XML_TEXT_NODE) {
2161 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002162 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002163 xmlFreeNode(elem);
2164 return(cur);
2165 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002166 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2167 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002168 xmlChar *tmp;
2169
2170 tmp = xmlStrdup(elem->content);
2171 tmp = xmlStrcat(tmp, cur->next->content);
2172 xmlNodeSetContent(cur->next, tmp);
2173 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002174 xmlFreeNode(elem);
2175 return(cur->next);
2176 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002177 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2178 /* check if an attribute with the same name exists */
2179 xmlAttrPtr attr;
2180
2181 if (elem->ns == NULL)
2182 attr = xmlHasProp(cur->parent, elem->name);
2183 else
2184 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2185 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2186 /* different instance, destroy it (attributes must be unique) */
2187 xmlFreeProp(attr);
2188 }
Owen Taylor3473f882001-02-23 17:55:21 +00002189 }
2190
2191 if (elem->doc != cur->doc) {
2192 xmlSetTreeDoc(elem, cur->doc);
2193 }
2194 elem->parent = cur->parent;
2195 elem->prev = cur;
2196 elem->next = cur->next;
2197 cur->next = elem;
2198 if (elem->next != NULL)
2199 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002200 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002201 elem->parent->last = elem;
2202 return(elem);
2203}
2204
2205/**
2206 * xmlAddPrevSibling:
2207 * @cur: the child node
2208 * @elem: the new node
2209 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002210 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002211 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002212 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002213 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002214 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2215 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002216 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002217 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002218 */
2219xmlNodePtr
2220xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2221 if (cur == NULL) {
2222#ifdef DEBUG_TREE
2223 xmlGenericError(xmlGenericErrorContext,
2224 "xmlAddPrevSibling : cur == NULL\n");
2225#endif
2226 return(NULL);
2227 }
2228 if (elem == NULL) {
2229#ifdef DEBUG_TREE
2230 xmlGenericError(xmlGenericErrorContext,
2231 "xmlAddPrevSibling : elem == NULL\n");
2232#endif
2233 return(NULL);
2234 }
2235
2236 xmlUnlinkNode(elem);
2237
2238 if (elem->type == XML_TEXT_NODE) {
2239 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002240 xmlChar *tmp;
2241
2242 tmp = xmlStrdup(elem->content);
2243 tmp = xmlStrcat(tmp, cur->content);
2244 xmlNodeSetContent(cur, tmp);
2245 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002246 xmlFreeNode(elem);
2247 return(cur);
2248 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002249 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2250 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002251 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002252 xmlFreeNode(elem);
2253 return(cur->prev);
2254 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002255 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2256 /* check if an attribute with the same name exists */
2257 xmlAttrPtr attr;
2258
2259 if (elem->ns == NULL)
2260 attr = xmlHasProp(cur->parent, elem->name);
2261 else
2262 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2263 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2264 /* different instance, destroy it (attributes must be unique) */
2265 xmlFreeProp(attr);
2266 }
Owen Taylor3473f882001-02-23 17:55:21 +00002267 }
2268
2269 if (elem->doc != cur->doc) {
2270 xmlSetTreeDoc(elem, cur->doc);
2271 }
2272 elem->parent = cur->parent;
2273 elem->next = cur;
2274 elem->prev = cur->prev;
2275 cur->prev = elem;
2276 if (elem->prev != NULL)
2277 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002278 if (elem->parent != NULL) {
2279 if (elem->type == XML_ATTRIBUTE_NODE) {
2280 if (elem->parent->properties == (xmlAttrPtr) cur) {
2281 elem->parent->properties = (xmlAttrPtr) elem;
2282 }
2283 } else {
2284 if (elem->parent->children == cur) {
2285 elem->parent->children = elem;
2286 }
2287 }
2288 }
Owen Taylor3473f882001-02-23 17:55:21 +00002289 return(elem);
2290}
2291
2292/**
2293 * xmlAddSibling:
2294 * @cur: the child node
2295 * @elem: the new node
2296 *
2297 * Add a new element @elem to the list of siblings of @cur
2298 * merging adjacent TEXT nodes (@elem may be freed)
2299 * If the new element was already inserted in a document it is
2300 * first unlinked from its existing context.
2301 *
2302 * Returns the new element or NULL in case of error.
2303 */
2304xmlNodePtr
2305xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2306 xmlNodePtr parent;
2307
2308 if (cur == NULL) {
2309#ifdef DEBUG_TREE
2310 xmlGenericError(xmlGenericErrorContext,
2311 "xmlAddSibling : cur == NULL\n");
2312#endif
2313 return(NULL);
2314 }
2315
2316 if (elem == NULL) {
2317#ifdef DEBUG_TREE
2318 xmlGenericError(xmlGenericErrorContext,
2319 "xmlAddSibling : elem == NULL\n");
2320#endif
2321 return(NULL);
2322 }
2323
2324 /*
2325 * Constant time is we can rely on the ->parent->last to find
2326 * the last sibling.
2327 */
2328 if ((cur->parent != NULL) &&
2329 (cur->parent->children != NULL) &&
2330 (cur->parent->last != NULL) &&
2331 (cur->parent->last->next == NULL)) {
2332 cur = cur->parent->last;
2333 } else {
2334 while (cur->next != NULL) cur = cur->next;
2335 }
2336
2337 xmlUnlinkNode(elem);
2338
2339 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002340 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002341 xmlFreeNode(elem);
2342 return(cur);
2343 }
2344
2345 if (elem->doc != cur->doc) {
2346 xmlSetTreeDoc(elem, cur->doc);
2347 }
2348 parent = cur->parent;
2349 elem->prev = cur;
2350 elem->next = NULL;
2351 elem->parent = parent;
2352 cur->next = elem;
2353 if (parent != NULL)
2354 parent->last = elem;
2355
2356 return(elem);
2357}
2358
2359/**
2360 * xmlAddChildList:
2361 * @parent: the parent node
2362 * @cur: the first node in the list
2363 *
2364 * Add a list of node at the end of the child list of the parent
2365 * merging adjacent TEXT nodes (@cur may be freed)
2366 *
2367 * Returns the last child or NULL in case of error.
2368 */
2369xmlNodePtr
2370xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2371 xmlNodePtr prev;
2372
2373 if (parent == NULL) {
2374#ifdef DEBUG_TREE
2375 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002376 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002377#endif
2378 return(NULL);
2379 }
2380
2381 if (cur == NULL) {
2382#ifdef DEBUG_TREE
2383 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002384 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002385#endif
2386 return(NULL);
2387 }
2388
2389 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2390 (cur->doc != parent->doc)) {
2391#ifdef DEBUG_TREE
2392 xmlGenericError(xmlGenericErrorContext,
2393 "Elements moved to a different document\n");
2394#endif
2395 }
2396
2397 /*
2398 * add the first element at the end of the children list.
2399 */
2400 if (parent->children == NULL) {
2401 parent->children = cur;
2402 } else {
2403 /*
2404 * If cur and parent->last both are TEXT nodes, then merge them.
2405 */
2406 if ((cur->type == XML_TEXT_NODE) &&
2407 (parent->last->type == XML_TEXT_NODE) &&
2408 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002409 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002410 /*
2411 * if it's the only child, nothing more to be done.
2412 */
2413 if (cur->next == NULL) {
2414 xmlFreeNode(cur);
2415 return(parent->last);
2416 }
2417 prev = cur;
2418 cur = cur->next;
2419 xmlFreeNode(prev);
2420 }
2421 prev = parent->last;
2422 prev->next = cur;
2423 cur->prev = prev;
2424 }
2425 while (cur->next != NULL) {
2426 cur->parent = parent;
2427 if (cur->doc != parent->doc) {
2428 xmlSetTreeDoc(cur, parent->doc);
2429 }
2430 cur = cur->next;
2431 }
2432 cur->parent = parent;
2433 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2434 parent->last = cur;
2435
2436 return(cur);
2437}
2438
2439/**
2440 * xmlAddChild:
2441 * @parent: the parent node
2442 * @cur: the child node
2443 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002444 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002445 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002446 * If the new node was already inserted in a document it is
2447 * first unlinked from its existing context.
2448 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2449 * If there is an attribute with equal name, it is first destroyed.
2450 *
Owen Taylor3473f882001-02-23 17:55:21 +00002451 * Returns the child or NULL in case of error.
2452 */
2453xmlNodePtr
2454xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2455 xmlNodePtr prev;
2456
2457 if (parent == NULL) {
2458#ifdef DEBUG_TREE
2459 xmlGenericError(xmlGenericErrorContext,
2460 "xmlAddChild : parent == NULL\n");
2461#endif
2462 return(NULL);
2463 }
2464
2465 if (cur == NULL) {
2466#ifdef DEBUG_TREE
2467 xmlGenericError(xmlGenericErrorContext,
2468 "xmlAddChild : child == NULL\n");
2469#endif
2470 return(NULL);
2471 }
2472
Owen Taylor3473f882001-02-23 17:55:21 +00002473 /*
2474 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002475 * cur is then freed.
2476 */
2477 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002478 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002479 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002480 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002481 xmlFreeNode(cur);
2482 return(parent);
2483 }
2484 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2485 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002486 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002487 xmlFreeNode(cur);
2488 return(parent->last);
2489 }
2490 }
2491
2492 /*
2493 * add the new element at the end of the children list.
2494 */
2495 cur->parent = parent;
2496 if (cur->doc != parent->doc) {
2497 xmlSetTreeDoc(cur, parent->doc);
2498 }
2499
2500 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002501 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002502 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002503 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002504 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002505 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002506 xmlFreeNode(cur);
2507 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002508 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002509 if (cur->type == XML_ATTRIBUTE_NODE) {
2510 if (parent->properties == NULL) {
2511 parent->properties = (xmlAttrPtr) cur;
2512 } else {
2513 /* check if an attribute with the same name exists */
2514 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002515
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002516 if (cur->ns == NULL)
2517 lastattr = xmlHasProp(parent, cur->name);
2518 else
2519 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2520 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2521 /* different instance, destroy it (attributes must be unique) */
2522 xmlFreeProp(lastattr);
2523 }
2524 /* find the end */
2525 lastattr = parent->properties;
2526 while (lastattr->next != NULL) {
2527 lastattr = lastattr->next;
2528 }
2529 lastattr->next = (xmlAttrPtr) cur;
2530 ((xmlAttrPtr) cur)->prev = lastattr;
2531 }
2532 } else {
2533 if (parent->children == NULL) {
2534 parent->children = cur;
2535 parent->last = cur;
2536 } else {
2537 prev = parent->last;
2538 prev->next = cur;
2539 cur->prev = prev;
2540 parent->last = cur;
2541 }
2542 }
Owen Taylor3473f882001-02-23 17:55:21 +00002543 return(cur);
2544}
2545
2546/**
2547 * xmlGetLastChild:
2548 * @parent: the parent node
2549 *
2550 * Search the last child of a node.
2551 * Returns the last child or NULL if none.
2552 */
2553xmlNodePtr
2554xmlGetLastChild(xmlNodePtr parent) {
2555 if (parent == NULL) {
2556#ifdef DEBUG_TREE
2557 xmlGenericError(xmlGenericErrorContext,
2558 "xmlGetLastChild : parent == NULL\n");
2559#endif
2560 return(NULL);
2561 }
2562 return(parent->last);
2563}
2564
2565/**
2566 * xmlFreeNodeList:
2567 * @cur: the first node in the list
2568 *
2569 * Free a node and all its siblings, this is a recursive behaviour, all
2570 * the children are freed too.
2571 */
2572void
2573xmlFreeNodeList(xmlNodePtr cur) {
2574 xmlNodePtr next;
2575 if (cur == NULL) {
2576#ifdef DEBUG_TREE
2577 xmlGenericError(xmlGenericErrorContext,
2578 "xmlFreeNodeList : node == NULL\n");
2579#endif
2580 return;
2581 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002582 if (cur->type == XML_NAMESPACE_DECL) {
2583 xmlFreeNsList((xmlNsPtr) cur);
2584 return;
2585 }
Owen Taylor3473f882001-02-23 17:55:21 +00002586 while (cur != NULL) {
2587 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002588 /* unroll to speed up freeing the document */
2589 if (cur->type != XML_DTD_NODE) {
2590 if ((cur->children != NULL) &&
2591 (cur->type != XML_ENTITY_REF_NODE))
2592 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002593 if (((cur->type == XML_ELEMENT_NODE) ||
2594 (cur->type == XML_XINCLUDE_START) ||
2595 (cur->type == XML_XINCLUDE_END)) &&
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002596 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002597 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002598 if ((cur->type != XML_ELEMENT_NODE) &&
2599 (cur->type != XML_XINCLUDE_START) &&
2600 (cur->type != XML_XINCLUDE_END) &&
2601 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002602 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002603 }
2604 if (((cur->type == XML_ELEMENT_NODE) ||
2605 (cur->type == XML_XINCLUDE_START) ||
2606 (cur->type == XML_XINCLUDE_END)) &&
2607 (cur->nsDef != NULL))
2608 xmlFreeNsList(cur->nsDef);
2609
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002610 /*
2611 * When a node is a text node or a comment, it uses a global static
2612 * variable for the name of the node.
2613 *
2614 * The xmlStrEqual comparisons need to be done when (happened with
2615 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002616 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002617 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002618 * the string addresses compare are not sufficient.
2619 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002620 if ((cur->name != NULL) &&
2621 (cur->name != xmlStringText) &&
2622 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002623 (cur->name != xmlStringComment)) {
2624 if (cur->type == XML_TEXT_NODE) {
2625 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2626 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2627 xmlFree((char *) cur->name);
2628 } else if (cur->type == XML_COMMENT_NODE) {
2629 if (!xmlStrEqual(cur->name, xmlStringComment))
2630 xmlFree((char *) cur->name);
2631 } else
2632 xmlFree((char *) cur->name);
2633 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002634 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002635 xmlFree(cur);
2636 }
Owen Taylor3473f882001-02-23 17:55:21 +00002637 cur = next;
2638 }
2639}
2640
2641/**
2642 * xmlFreeNode:
2643 * @cur: the node
2644 *
2645 * Free a node, this is a recursive behaviour, all the children are freed too.
2646 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2647 */
2648void
2649xmlFreeNode(xmlNodePtr cur) {
2650 if (cur == NULL) {
2651#ifdef DEBUG_TREE
2652 xmlGenericError(xmlGenericErrorContext,
2653 "xmlFreeNode : node == NULL\n");
2654#endif
2655 return;
2656 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002657 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002658 if (cur->type == XML_DTD_NODE) {
2659 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002660 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002661 }
2662 if (cur->type == XML_NAMESPACE_DECL) {
2663 xmlFreeNs((xmlNsPtr) cur);
2664 return;
2665 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00002666 if (cur->type == XML_ATTRIBUTE_NODE) {
2667 xmlFreeProp((xmlAttrPtr) cur);
2668 return;
2669 }
Owen Taylor3473f882001-02-23 17:55:21 +00002670 if ((cur->children != NULL) &&
2671 (cur->type != XML_ENTITY_REF_NODE))
2672 xmlFreeNodeList(cur->children);
Daniel Veillard01c13b52002-12-10 15:19:08 +00002673 if (((cur->type == XML_ELEMENT_NODE) ||
2674 (cur->type == XML_XINCLUDE_START) ||
2675 (cur->type == XML_XINCLUDE_END)) &&
2676 (cur->properties != NULL))
Daniel Veillard02141ea2001-04-30 11:46:40 +00002677 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002678 if ((cur->type != XML_ELEMENT_NODE) &&
2679 (cur->content != NULL) &&
2680 (cur->type != XML_ENTITY_REF_NODE) &&
2681 (cur->type != XML_XINCLUDE_END) &&
2682 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002683 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002684 }
2685
Daniel Veillardacd370f2001-06-09 17:17:51 +00002686 /*
2687 * When a node is a text node or a comment, it uses a global static
2688 * variable for the name of the node.
2689 *
2690 * The xmlStrEqual comparisons need to be done when (happened with
2691 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002692 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002693 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002694 * are not sufficient.
2695 */
Owen Taylor3473f882001-02-23 17:55:21 +00002696 if ((cur->name != NULL) &&
2697 (cur->name != xmlStringText) &&
2698 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002699 (cur->name != xmlStringComment)) {
2700 if (cur->type == XML_TEXT_NODE) {
2701 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2702 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2703 xmlFree((char *) cur->name);
2704 } else if (cur->type == XML_COMMENT_NODE) {
2705 if (!xmlStrEqual(cur->name, xmlStringComment))
2706 xmlFree((char *) cur->name);
2707 } else
2708 xmlFree((char *) cur->name);
2709 }
2710
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002711 if (((cur->type == XML_ELEMENT_NODE) ||
2712 (cur->type == XML_XINCLUDE_START) ||
2713 (cur->type == XML_XINCLUDE_END)) &&
2714 (cur->nsDef != NULL))
2715 xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002716 xmlFree(cur);
2717}
2718
2719/**
2720 * xmlUnlinkNode:
2721 * @cur: the node
2722 *
2723 * Unlink a node from it's current context, the node is not freed
2724 */
2725void
2726xmlUnlinkNode(xmlNodePtr cur) {
2727 if (cur == NULL) {
2728#ifdef DEBUG_TREE
2729 xmlGenericError(xmlGenericErrorContext,
2730 "xmlUnlinkNode : node == NULL\n");
2731#endif
2732 return;
2733 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002734 if (cur->type == XML_DTD_NODE) {
2735 xmlDocPtr doc;
2736 doc = cur->doc;
2737 if (doc->intSubset == (xmlDtdPtr) cur)
2738 doc->intSubset = NULL;
2739 if (doc->extSubset == (xmlDtdPtr) cur)
2740 doc->extSubset = NULL;
2741 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002742 if (cur->parent != NULL) {
2743 xmlNodePtr parent;
2744 parent = cur->parent;
2745 if (cur->type == XML_ATTRIBUTE_NODE) {
2746 if (parent->properties == (xmlAttrPtr) cur)
2747 parent->properties = ((xmlAttrPtr) cur)->next;
2748 } else {
2749 if (parent->children == cur)
2750 parent->children = cur->next;
2751 if (parent->last == cur)
2752 parent->last = cur->prev;
2753 }
2754 cur->parent = NULL;
2755 }
Owen Taylor3473f882001-02-23 17:55:21 +00002756 if (cur->next != NULL)
2757 cur->next->prev = cur->prev;
2758 if (cur->prev != NULL)
2759 cur->prev->next = cur->next;
2760 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002761}
2762
2763/**
2764 * xmlReplaceNode:
2765 * @old: the old node
2766 * @cur: the node
2767 *
2768 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002769 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002770 * first unlinked from its existing context.
2771 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002772 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002773 */
2774xmlNodePtr
2775xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2776 if (old == NULL) {
2777#ifdef DEBUG_TREE
2778 xmlGenericError(xmlGenericErrorContext,
2779 "xmlReplaceNode : old == NULL\n");
2780#endif
2781 return(NULL);
2782 }
2783 if (cur == NULL) {
2784 xmlUnlinkNode(old);
2785 return(old);
2786 }
2787 if (cur == old) {
2788 return(old);
2789 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002790 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2791#ifdef DEBUG_TREE
2792 xmlGenericError(xmlGenericErrorContext,
2793 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2794#endif
2795 return(old);
2796 }
2797 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2798#ifdef DEBUG_TREE
2799 xmlGenericError(xmlGenericErrorContext,
2800 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2801#endif
2802 return(old);
2803 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002804 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2805#ifdef DEBUG_TREE
2806 xmlGenericError(xmlGenericErrorContext,
2807 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2808#endif
2809 return(old);
2810 }
2811 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2812#ifdef DEBUG_TREE
2813 xmlGenericError(xmlGenericErrorContext,
2814 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2815#endif
2816 return(old);
2817 }
Owen Taylor3473f882001-02-23 17:55:21 +00002818 xmlUnlinkNode(cur);
2819 cur->doc = old->doc;
2820 cur->parent = old->parent;
2821 cur->next = old->next;
2822 if (cur->next != NULL)
2823 cur->next->prev = cur;
2824 cur->prev = old->prev;
2825 if (cur->prev != NULL)
2826 cur->prev->next = cur;
2827 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002828 if (cur->type == XML_ATTRIBUTE_NODE) {
2829 if (cur->parent->properties == (xmlAttrPtr)old)
2830 cur->parent->properties = ((xmlAttrPtr) cur);
2831 } else {
2832 if (cur->parent->children == old)
2833 cur->parent->children = cur;
2834 if (cur->parent->last == old)
2835 cur->parent->last = cur;
2836 }
Owen Taylor3473f882001-02-23 17:55:21 +00002837 }
2838 old->next = old->prev = NULL;
2839 old->parent = NULL;
2840 return(old);
2841}
2842
2843/************************************************************************
2844 * *
2845 * Copy operations *
2846 * *
2847 ************************************************************************/
2848
2849/**
2850 * xmlCopyNamespace:
2851 * @cur: the namespace
2852 *
2853 * Do a copy of the namespace.
2854 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002855 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002856 */
2857xmlNsPtr
2858xmlCopyNamespace(xmlNsPtr cur) {
2859 xmlNsPtr ret;
2860
2861 if (cur == NULL) return(NULL);
2862 switch (cur->type) {
2863 case XML_LOCAL_NAMESPACE:
2864 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2865 break;
2866 default:
2867#ifdef DEBUG_TREE
2868 xmlGenericError(xmlGenericErrorContext,
2869 "xmlCopyNamespace: invalid type %d\n", cur->type);
2870#endif
2871 return(NULL);
2872 }
2873 return(ret);
2874}
2875
2876/**
2877 * xmlCopyNamespaceList:
2878 * @cur: the first namespace
2879 *
2880 * Do a copy of an namespace list.
2881 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002882 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002883 */
2884xmlNsPtr
2885xmlCopyNamespaceList(xmlNsPtr cur) {
2886 xmlNsPtr ret = NULL;
2887 xmlNsPtr p = NULL,q;
2888
2889 while (cur != NULL) {
2890 q = xmlCopyNamespace(cur);
2891 if (p == NULL) {
2892 ret = p = q;
2893 } else {
2894 p->next = q;
2895 p = q;
2896 }
2897 cur = cur->next;
2898 }
2899 return(ret);
2900}
2901
2902static xmlNodePtr
2903xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2904/**
2905 * xmlCopyProp:
2906 * @target: the element where the attribute will be grafted
2907 * @cur: the attribute
2908 *
2909 * Do a copy of the attribute.
2910 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002911 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002912 */
2913xmlAttrPtr
2914xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2915 xmlAttrPtr ret;
2916
2917 if (cur == NULL) return(NULL);
2918 if (target != NULL)
2919 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2920 else if (cur->parent != NULL)
2921 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2922 else if (cur->children != NULL)
2923 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2924 else
2925 ret = xmlNewDocProp(NULL, cur->name, NULL);
2926 if (ret == NULL) return(NULL);
2927 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002928
Owen Taylor3473f882001-02-23 17:55:21 +00002929 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002930 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002931/*
2932 * if (target->doc)
2933 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2934 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2935 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2936 * else
2937 * ns = NULL;
2938 * ret->ns = ns;
2939 */
2940 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2941 if (ns == NULL) {
2942 /*
2943 * Humm, we are copying an element whose namespace is defined
2944 * out of the new tree scope. Search it in the original tree
2945 * and add it at the top of the new tree
2946 */
2947 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2948 if (ns != NULL) {
2949 xmlNodePtr root = target;
2950 xmlNodePtr pred = NULL;
2951
2952 while (root->parent != NULL) {
2953 pred = root;
2954 root = root->parent;
2955 }
2956 if (root == (xmlNodePtr) target->doc) {
2957 /* correct possibly cycling above the document elt */
2958 root = pred;
2959 }
2960 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2961 }
2962 } else {
2963 /*
2964 * we have to find something appropriate here since
2965 * we cant be sure, that the namespce we found is identified
2966 * by the prefix
2967 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002968 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002969 /* this is the nice case */
2970 ret->ns = ns;
2971 } else {
2972 /*
2973 * we are in trouble: we need a new reconcilied namespace.
2974 * This is expensive
2975 */
2976 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2977 }
2978 }
2979
Owen Taylor3473f882001-02-23 17:55:21 +00002980 } else
2981 ret->ns = NULL;
2982
2983 if (cur->children != NULL) {
2984 xmlNodePtr tmp;
2985
2986 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2987 ret->last = NULL;
2988 tmp = ret->children;
2989 while (tmp != NULL) {
2990 /* tmp->parent = (xmlNodePtr)ret; */
2991 if (tmp->next == NULL)
2992 ret->last = tmp;
2993 tmp = tmp->next;
2994 }
2995 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002996 /*
2997 * Try to handle IDs
2998 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002999 if ((target!= NULL) && (cur!= NULL) &&
3000 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00003001 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
3002 if (xmlIsID(cur->doc, cur->parent, cur)) {
3003 xmlChar *id;
3004
3005 id = xmlNodeListGetString(cur->doc, cur->children, 1);
3006 if (id != NULL) {
3007 xmlAddID(NULL, target->doc, id, ret);
3008 xmlFree(id);
3009 }
3010 }
3011 }
Owen Taylor3473f882001-02-23 17:55:21 +00003012 return(ret);
3013}
3014
3015/**
3016 * xmlCopyPropList:
3017 * @target: the element where the attributes will be grafted
3018 * @cur: the first attribute
3019 *
3020 * Do a copy of an attribute list.
3021 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003022 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003023 */
3024xmlAttrPtr
3025xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3026 xmlAttrPtr ret = NULL;
3027 xmlAttrPtr p = NULL,q;
3028
3029 while (cur != NULL) {
3030 q = xmlCopyProp(target, cur);
3031 if (p == NULL) {
3032 ret = p = q;
3033 } else {
3034 p->next = q;
3035 q->prev = p;
3036 p = q;
3037 }
3038 cur = cur->next;
3039 }
3040 return(ret);
3041}
3042
3043/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003044 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003045 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003046 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003047 * tricky reason: namespaces. Doing a direct copy of a node
3048 * say RPM:Copyright without changing the namespace pointer to
3049 * something else can produce stale links. One way to do it is
3050 * to keep a reference counter but this doesn't work as soon
3051 * as one move the element or the subtree out of the scope of
3052 * the existing namespace. The actual solution seems to add
3053 * a copy of the namespace at the top of the copied tree if
3054 * not available in the subtree.
3055 * Hence two functions, the public front-end call the inner ones
3056 */
3057
3058static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003059xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003060 int recursive) {
3061 xmlNodePtr ret;
3062
3063 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003064 switch (node->type) {
3065 case XML_TEXT_NODE:
3066 case XML_CDATA_SECTION_NODE:
3067 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003068 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003069 case XML_ENTITY_REF_NODE:
3070 case XML_ENTITY_NODE:
3071 case XML_PI_NODE:
3072 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003073 case XML_XINCLUDE_START:
3074 case XML_XINCLUDE_END:
3075 break;
3076 case XML_ATTRIBUTE_NODE:
3077 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3078 case XML_NAMESPACE_DECL:
3079 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3080
Daniel Veillard39196eb2001-06-19 18:09:42 +00003081 case XML_DOCUMENT_NODE:
3082 case XML_HTML_DOCUMENT_NODE:
3083#ifdef LIBXML_DOCB_ENABLED
3084 case XML_DOCB_DOCUMENT_NODE:
3085#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003086 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003087 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003088 case XML_NOTATION_NODE:
3089 case XML_DTD_NODE:
3090 case XML_ELEMENT_DECL:
3091 case XML_ATTRIBUTE_DECL:
3092 case XML_ENTITY_DECL:
3093 return(NULL);
3094 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003095
Owen Taylor3473f882001-02-23 17:55:21 +00003096 /*
3097 * Allocate a new node and fill the fields.
3098 */
3099 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3100 if (ret == NULL) {
3101 xmlGenericError(xmlGenericErrorContext,
3102 "xmlStaticCopyNode : malloc failed\n");
3103 return(NULL);
3104 }
3105 memset(ret, 0, sizeof(xmlNode));
3106 ret->type = node->type;
3107
3108 ret->doc = doc;
3109 ret->parent = parent;
3110 if (node->name == xmlStringText)
3111 ret->name = xmlStringText;
3112 else if (node->name == xmlStringTextNoenc)
3113 ret->name = xmlStringTextNoenc;
3114 else if (node->name == xmlStringComment)
3115 ret->name = xmlStringComment;
3116 else if (node->name != NULL)
3117 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003118 if ((node->type != XML_ELEMENT_NODE) &&
3119 (node->content != NULL) &&
3120 (node->type != XML_ENTITY_REF_NODE) &&
3121 (node->type != XML_XINCLUDE_END) &&
3122 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003123 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003124 }else{
3125 if (node->type == XML_ELEMENT_NODE)
3126 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003127 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003128 if (parent != NULL) {
3129 xmlNodePtr tmp;
3130
3131 tmp = xmlAddChild(parent, ret);
3132 /* node could have coalesced */
3133 if (tmp != ret)
3134 return(tmp);
3135 }
Owen Taylor3473f882001-02-23 17:55:21 +00003136
3137 if (!recursive) return(ret);
3138 if (node->nsDef != NULL)
3139 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3140
3141 if (node->ns != NULL) {
3142 xmlNsPtr ns;
3143
3144 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3145 if (ns == NULL) {
3146 /*
3147 * Humm, we are copying an element whose namespace is defined
3148 * out of the new tree scope. Search it in the original tree
3149 * and add it at the top of the new tree
3150 */
3151 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3152 if (ns != NULL) {
3153 xmlNodePtr root = ret;
3154
3155 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003156 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003157 }
3158 } else {
3159 /*
3160 * reference the existing namespace definition in our own tree.
3161 */
3162 ret->ns = ns;
3163 }
3164 }
3165 if (node->properties != NULL)
3166 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003167 if (node->type == XML_ENTITY_REF_NODE) {
3168 if ((doc == NULL) || (node->doc != doc)) {
3169 /*
3170 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003171 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003172 * we cannot keep the reference. Try to find it in the
3173 * target document.
3174 */
3175 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3176 } else {
3177 ret->children = node->children;
3178 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003179 ret->last = ret->children;
3180 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003181 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003182 UPDATE_LAST_CHILD_AND_PARENT(ret)
3183 }
Owen Taylor3473f882001-02-23 17:55:21 +00003184 return(ret);
3185}
3186
3187static xmlNodePtr
3188xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3189 xmlNodePtr ret = NULL;
3190 xmlNodePtr p = NULL,q;
3191
3192 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003193 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003194 if (doc == NULL) {
3195 node = node->next;
3196 continue;
3197 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003198 if (doc->intSubset == NULL) {
3199 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3200 q->doc = doc;
3201 q->parent = parent;
3202 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003203 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003204 } else {
3205 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003206 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003207 }
3208 } else
3209 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003210 if (ret == NULL) {
3211 q->prev = NULL;
3212 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003213 } else if (p != q) {
3214 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003215 p->next = q;
3216 q->prev = p;
3217 p = q;
3218 }
3219 node = node->next;
3220 }
3221 return(ret);
3222}
3223
3224/**
3225 * xmlCopyNode:
3226 * @node: the node
3227 * @recursive: if 1 do a recursive copy.
3228 *
3229 * Do a copy of the node.
3230 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003231 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003232 */
3233xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003234xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003235 xmlNodePtr ret;
3236
3237 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3238 return(ret);
3239}
3240
3241/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003242 * xmlDocCopyNode:
3243 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003244 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003245 * @recursive: if 1 do a recursive copy.
3246 *
3247 * Do a copy of the node to a given document.
3248 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003249 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003250 */
3251xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003252xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003253 xmlNodePtr ret;
3254
3255 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3256 return(ret);
3257}
3258
3259/**
Owen Taylor3473f882001-02-23 17:55:21 +00003260 * xmlCopyNodeList:
3261 * @node: the first node in the list.
3262 *
3263 * Do a recursive copy of the node list.
3264 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003265 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003266 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003267xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003268 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3269 return(ret);
3270}
3271
3272/**
Owen Taylor3473f882001-02-23 17:55:21 +00003273 * xmlCopyDtd:
3274 * @dtd: the dtd
3275 *
3276 * Do a copy of the dtd.
3277 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003278 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003279 */
3280xmlDtdPtr
3281xmlCopyDtd(xmlDtdPtr dtd) {
3282 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003283 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003284
3285 if (dtd == NULL) return(NULL);
3286 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3287 if (ret == NULL) return(NULL);
3288 if (dtd->entities != NULL)
3289 ret->entities = (void *) xmlCopyEntitiesTable(
3290 (xmlEntitiesTablePtr) dtd->entities);
3291 if (dtd->notations != NULL)
3292 ret->notations = (void *) xmlCopyNotationTable(
3293 (xmlNotationTablePtr) dtd->notations);
3294 if (dtd->elements != NULL)
3295 ret->elements = (void *) xmlCopyElementTable(
3296 (xmlElementTablePtr) dtd->elements);
3297 if (dtd->attributes != NULL)
3298 ret->attributes = (void *) xmlCopyAttributeTable(
3299 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003300 if (dtd->pentities != NULL)
3301 ret->pentities = (void *) xmlCopyEntitiesTable(
3302 (xmlEntitiesTablePtr) dtd->pentities);
3303
3304 cur = dtd->children;
3305 while (cur != NULL) {
3306 q = NULL;
3307
3308 if (cur->type == XML_ENTITY_DECL) {
3309 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3310 switch (tmp->etype) {
3311 case XML_INTERNAL_GENERAL_ENTITY:
3312 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3313 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3314 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3315 break;
3316 case XML_INTERNAL_PARAMETER_ENTITY:
3317 case XML_EXTERNAL_PARAMETER_ENTITY:
3318 q = (xmlNodePtr)
3319 xmlGetParameterEntityFromDtd(ret, tmp->name);
3320 break;
3321 case XML_INTERNAL_PREDEFINED_ENTITY:
3322 break;
3323 }
3324 } else if (cur->type == XML_ELEMENT_DECL) {
3325 xmlElementPtr tmp = (xmlElementPtr) cur;
3326 q = (xmlNodePtr)
3327 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3328 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3329 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3330 q = (xmlNodePtr)
3331 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3332 } else if (cur->type == XML_COMMENT_NODE) {
3333 q = xmlCopyNode(cur, 0);
3334 }
3335
3336 if (q == NULL) {
3337 cur = cur->next;
3338 continue;
3339 }
3340
3341 if (p == NULL)
3342 ret->children = q;
3343 else
3344 p->next = q;
3345
3346 q->prev = p;
3347 q->parent = (xmlNodePtr) ret;
3348 q->next = NULL;
3349 ret->last = q;
3350 p = q;
3351 cur = cur->next;
3352 }
3353
Owen Taylor3473f882001-02-23 17:55:21 +00003354 return(ret);
3355}
3356
3357/**
3358 * xmlCopyDoc:
3359 * @doc: the document
3360 * @recursive: if 1 do a recursive copy.
3361 *
3362 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003363 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003364 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003365 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003366 */
3367xmlDocPtr
3368xmlCopyDoc(xmlDocPtr doc, int recursive) {
3369 xmlDocPtr ret;
3370
3371 if (doc == NULL) return(NULL);
3372 ret = xmlNewDoc(doc->version);
3373 if (ret == NULL) return(NULL);
3374 if (doc->name != NULL)
3375 ret->name = xmlMemStrdup(doc->name);
3376 if (doc->encoding != NULL)
3377 ret->encoding = xmlStrdup(doc->encoding);
3378 ret->charset = doc->charset;
3379 ret->compression = doc->compression;
3380 ret->standalone = doc->standalone;
3381 if (!recursive) return(ret);
3382
Daniel Veillardb33c2012001-04-25 12:59:04 +00003383 ret->last = NULL;
3384 ret->children = NULL;
3385 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003386 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003387 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003388 ret->intSubset->parent = ret;
3389 }
Owen Taylor3473f882001-02-23 17:55:21 +00003390 if (doc->oldNs != NULL)
3391 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3392 if (doc->children != NULL) {
3393 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003394
3395 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3396 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003397 ret->last = NULL;
3398 tmp = ret->children;
3399 while (tmp != NULL) {
3400 if (tmp->next == NULL)
3401 ret->last = tmp;
3402 tmp = tmp->next;
3403 }
3404 }
3405 return(ret);
3406}
3407
3408/************************************************************************
3409 * *
3410 * Content access functions *
3411 * *
3412 ************************************************************************/
3413
3414/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003415 * xmlGetLineNo:
Daniel Veillard01c13b52002-12-10 15:19:08 +00003416 * @node: valid node
Daniel Veillard8faa7832001-11-26 15:58:08 +00003417 *
3418 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003419 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003420 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003421 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003422 */
3423long
3424xmlGetLineNo(xmlNodePtr node)
3425{
3426 long result = -1;
3427
3428 if (!node)
3429 return result;
3430 if (node->type == XML_ELEMENT_NODE)
3431 result = (long) node->content;
3432 else if ((node->prev != NULL) &&
3433 ((node->prev->type == XML_ELEMENT_NODE) ||
3434 (node->prev->type == XML_TEXT_NODE)))
3435 result = xmlGetLineNo(node->prev);
3436 else if ((node->parent != NULL) &&
3437 ((node->parent->type == XML_ELEMENT_NODE) ||
3438 (node->parent->type == XML_TEXT_NODE)))
3439 result = xmlGetLineNo(node->parent);
3440
3441 return result;
3442}
3443
3444/**
3445 * xmlGetNodePath:
3446 * @node: a node
3447 *
3448 * Build a structure based Path for the given node
3449 *
3450 * Returns the new path or NULL in case of error. The caller must free
3451 * the returned string
3452 */
3453xmlChar *
3454xmlGetNodePath(xmlNodePtr node)
3455{
3456 xmlNodePtr cur, tmp, next;
3457 xmlChar *buffer = NULL, *temp;
3458 size_t buf_len;
3459 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003460 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003461 const char *name;
3462 char nametemp[100];
3463 int occur = 0;
3464
3465 if (node == NULL)
3466 return (NULL);
3467
3468 buf_len = 500;
3469 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3470 if (buffer == NULL)
3471 return (NULL);
3472 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3473 if (buf == NULL) {
3474 xmlFree(buffer);
3475 return (NULL);
3476 }
3477
3478 buffer[0] = 0;
3479 cur = node;
3480 do {
3481 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003482 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003483 occur = 0;
3484 if ((cur->type == XML_DOCUMENT_NODE) ||
3485 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3486 if (buffer[0] == '/')
3487 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003488 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003489 next = NULL;
3490 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003491 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003492 name = (const char *) cur->name;
3493 if (cur->ns) {
3494 snprintf(nametemp, sizeof(nametemp) - 1,
3495 "%s:%s", cur->ns->prefix, cur->name);
3496 nametemp[sizeof(nametemp) - 1] = 0;
3497 name = nametemp;
3498 }
3499 next = cur->parent;
3500
3501 /*
3502 * Thumbler index computation
3503 */
3504 tmp = cur->prev;
3505 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003506 if ((tmp->type == XML_ELEMENT_NODE) &&
3507 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003508 occur++;
3509 tmp = tmp->prev;
3510 }
3511 if (occur == 0) {
3512 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003513 while (tmp != NULL && occur == 0) {
3514 if ((tmp->type == XML_ELEMENT_NODE) &&
3515 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003516 occur++;
3517 tmp = tmp->next;
3518 }
3519 if (occur != 0)
3520 occur = 1;
3521 } else
3522 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003523 } else if (cur->type == XML_COMMENT_NODE) {
3524 sep = "/";
3525 name = "comment()";
3526 next = cur->parent;
3527
3528 /*
3529 * Thumbler index computation
3530 */
3531 tmp = cur->prev;
3532 while (tmp != NULL) {
3533 if (tmp->type == XML_COMMENT_NODE)
3534 occur++;
3535 tmp = tmp->prev;
3536 }
3537 if (occur == 0) {
3538 tmp = cur->next;
3539 while (tmp != NULL && occur == 0) {
3540 if (tmp->type == XML_COMMENT_NODE)
3541 occur++;
3542 tmp = tmp->next;
3543 }
3544 if (occur != 0)
3545 occur = 1;
3546 } else
3547 occur++;
3548 } else if ((cur->type == XML_TEXT_NODE) ||
3549 (cur->type == XML_CDATA_SECTION_NODE)) {
3550 sep = "/";
3551 name = "text()";
3552 next = cur->parent;
3553
3554 /*
3555 * Thumbler index computation
3556 */
3557 tmp = cur->prev;
3558 while (tmp != NULL) {
3559 if ((cur->type == XML_TEXT_NODE) ||
3560 (cur->type == XML_CDATA_SECTION_NODE))
3561 occur++;
3562 tmp = tmp->prev;
3563 }
3564 if (occur == 0) {
3565 tmp = cur->next;
3566 while (tmp != NULL && occur == 0) {
3567 if ((cur->type == XML_TEXT_NODE) ||
3568 (cur->type == XML_CDATA_SECTION_NODE))
3569 occur++;
3570 tmp = tmp->next;
3571 }
3572 if (occur != 0)
3573 occur = 1;
3574 } else
3575 occur++;
3576 } else if (cur->type == XML_PI_NODE) {
3577 sep = "/";
3578 snprintf(nametemp, sizeof(nametemp) - 1,
3579 "processing-instruction('%s')", cur->name);
3580 nametemp[sizeof(nametemp) - 1] = 0;
3581 name = nametemp;
3582
3583 next = cur->parent;
3584
3585 /*
3586 * Thumbler index computation
3587 */
3588 tmp = cur->prev;
3589 while (tmp != NULL) {
3590 if ((tmp->type == XML_PI_NODE) &&
3591 (xmlStrEqual(cur->name, tmp->name)))
3592 occur++;
3593 tmp = tmp->prev;
3594 }
3595 if (occur == 0) {
3596 tmp = cur->next;
3597 while (tmp != NULL && occur == 0) {
3598 if ((tmp->type == XML_PI_NODE) &&
3599 (xmlStrEqual(cur->name, tmp->name)))
3600 occur++;
3601 tmp = tmp->next;
3602 }
3603 if (occur != 0)
3604 occur = 1;
3605 } else
3606 occur++;
3607
Daniel Veillard8faa7832001-11-26 15:58:08 +00003608 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003609 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003610 name = (const char *) (((xmlAttrPtr) cur)->name);
3611 next = ((xmlAttrPtr) cur)->parent;
3612 } else {
3613 next = cur->parent;
3614 }
3615
3616 /*
3617 * Make sure there is enough room
3618 */
3619 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3620 buf_len =
3621 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3622 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3623 if (temp == NULL) {
3624 xmlFree(buf);
3625 xmlFree(buffer);
3626 return (NULL);
3627 }
3628 buffer = temp;
3629 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3630 if (temp == NULL) {
3631 xmlFree(buf);
3632 xmlFree(buffer);
3633 return (NULL);
3634 }
3635 buf = temp;
3636 }
3637 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003638 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003639 sep, name, (char *) buffer);
3640 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003641 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003642 sep, name, occur, (char *) buffer);
3643 snprintf((char *) buffer, buf_len, "%s", buf);
3644 cur = next;
3645 } while (cur != NULL);
3646 xmlFree(buf);
3647 return (buffer);
3648}
3649
3650/**
Owen Taylor3473f882001-02-23 17:55:21 +00003651 * xmlDocGetRootElement:
3652 * @doc: the document
3653 *
3654 * Get the root element of the document (doc->children is a list
3655 * containing possibly comments, PIs, etc ...).
3656 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003657 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003658 */
3659xmlNodePtr
3660xmlDocGetRootElement(xmlDocPtr doc) {
3661 xmlNodePtr ret;
3662
3663 if (doc == NULL) return(NULL);
3664 ret = doc->children;
3665 while (ret != NULL) {
3666 if (ret->type == XML_ELEMENT_NODE)
3667 return(ret);
3668 ret = ret->next;
3669 }
3670 return(ret);
3671}
3672
3673/**
3674 * xmlDocSetRootElement:
3675 * @doc: the document
3676 * @root: the new document root element
3677 *
3678 * Set the root element of the document (doc->children is a list
3679 * containing possibly comments, PIs, etc ...).
3680 *
3681 * Returns the old root element if any was found
3682 */
3683xmlNodePtr
3684xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3685 xmlNodePtr old = NULL;
3686
3687 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003688 if (root == NULL)
3689 return(NULL);
3690 xmlUnlinkNode(root);
3691 root->doc = doc;
3692 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003693 old = doc->children;
3694 while (old != NULL) {
3695 if (old->type == XML_ELEMENT_NODE)
3696 break;
3697 old = old->next;
3698 }
3699 if (old == NULL) {
3700 if (doc->children == NULL) {
3701 doc->children = root;
3702 doc->last = root;
3703 } else {
3704 xmlAddSibling(doc->children, root);
3705 }
3706 } else {
3707 xmlReplaceNode(old, root);
3708 }
3709 return(old);
3710}
3711
3712/**
3713 * xmlNodeSetLang:
3714 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003715 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003716 *
3717 * Set the language of a node, i.e. the values of the xml:lang
3718 * attribute.
3719 */
3720void
3721xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003722 xmlNsPtr ns;
3723
Owen Taylor3473f882001-02-23 17:55:21 +00003724 if (cur == NULL) return;
3725 switch(cur->type) {
3726 case XML_TEXT_NODE:
3727 case XML_CDATA_SECTION_NODE:
3728 case XML_COMMENT_NODE:
3729 case XML_DOCUMENT_NODE:
3730 case XML_DOCUMENT_TYPE_NODE:
3731 case XML_DOCUMENT_FRAG_NODE:
3732 case XML_NOTATION_NODE:
3733 case XML_HTML_DOCUMENT_NODE:
3734 case XML_DTD_NODE:
3735 case XML_ELEMENT_DECL:
3736 case XML_ATTRIBUTE_DECL:
3737 case XML_ENTITY_DECL:
3738 case XML_PI_NODE:
3739 case XML_ENTITY_REF_NODE:
3740 case XML_ENTITY_NODE:
3741 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003742#ifdef LIBXML_DOCB_ENABLED
3743 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003744#endif
3745 case XML_XINCLUDE_START:
3746 case XML_XINCLUDE_END:
3747 return;
3748 case XML_ELEMENT_NODE:
3749 case XML_ATTRIBUTE_NODE:
3750 break;
3751 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003752 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3753 if (ns == NULL)
3754 return;
3755 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003756}
3757
3758/**
3759 * xmlNodeGetLang:
3760 * @cur: the node being checked
3761 *
3762 * Searches the language of a node, i.e. the values of the xml:lang
3763 * attribute or the one carried by the nearest ancestor.
3764 *
3765 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003766 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003767 */
3768xmlChar *
3769xmlNodeGetLang(xmlNodePtr cur) {
3770 xmlChar *lang;
3771
3772 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003773 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003774 if (lang != NULL)
3775 return(lang);
3776 cur = cur->parent;
3777 }
3778 return(NULL);
3779}
3780
3781
3782/**
3783 * xmlNodeSetSpacePreserve:
3784 * @cur: the node being changed
3785 * @val: the xml:space value ("0": default, 1: "preserve")
3786 *
3787 * Set (or reset) the space preserving behaviour of a node, i.e. the
3788 * value of the xml:space attribute.
3789 */
3790void
3791xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003792 xmlNsPtr ns;
3793
Owen Taylor3473f882001-02-23 17:55:21 +00003794 if (cur == NULL) return;
3795 switch(cur->type) {
3796 case XML_TEXT_NODE:
3797 case XML_CDATA_SECTION_NODE:
3798 case XML_COMMENT_NODE:
3799 case XML_DOCUMENT_NODE:
3800 case XML_DOCUMENT_TYPE_NODE:
3801 case XML_DOCUMENT_FRAG_NODE:
3802 case XML_NOTATION_NODE:
3803 case XML_HTML_DOCUMENT_NODE:
3804 case XML_DTD_NODE:
3805 case XML_ELEMENT_DECL:
3806 case XML_ATTRIBUTE_DECL:
3807 case XML_ENTITY_DECL:
3808 case XML_PI_NODE:
3809 case XML_ENTITY_REF_NODE:
3810 case XML_ENTITY_NODE:
3811 case XML_NAMESPACE_DECL:
3812 case XML_XINCLUDE_START:
3813 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003814#ifdef LIBXML_DOCB_ENABLED
3815 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003816#endif
3817 return;
3818 case XML_ELEMENT_NODE:
3819 case XML_ATTRIBUTE_NODE:
3820 break;
3821 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003822 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3823 if (ns == NULL)
3824 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003825 switch (val) {
3826 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003827 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003828 break;
3829 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003830 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003831 break;
3832 }
3833}
3834
3835/**
3836 * xmlNodeGetSpacePreserve:
3837 * @cur: the node being checked
3838 *
3839 * Searches the space preserving behaviour of a node, i.e. the values
3840 * of the xml:space attribute or the one carried by the nearest
3841 * ancestor.
3842 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003843 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003844 */
3845int
3846xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3847 xmlChar *space;
3848
3849 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003850 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003851 if (space != NULL) {
3852 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3853 xmlFree(space);
3854 return(1);
3855 }
3856 if (xmlStrEqual(space, BAD_CAST "default")) {
3857 xmlFree(space);
3858 return(0);
3859 }
3860 xmlFree(space);
3861 }
3862 cur = cur->parent;
3863 }
3864 return(-1);
3865}
3866
3867/**
3868 * xmlNodeSetName:
3869 * @cur: the node being changed
3870 * @name: the new tag name
3871 *
3872 * Set (or reset) the name of a node.
3873 */
3874void
3875xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3876 if (cur == NULL) return;
3877 if (name == NULL) return;
3878 switch(cur->type) {
3879 case XML_TEXT_NODE:
3880 case XML_CDATA_SECTION_NODE:
3881 case XML_COMMENT_NODE:
3882 case XML_DOCUMENT_TYPE_NODE:
3883 case XML_DOCUMENT_FRAG_NODE:
3884 case XML_NOTATION_NODE:
3885 case XML_HTML_DOCUMENT_NODE:
3886 case XML_NAMESPACE_DECL:
3887 case XML_XINCLUDE_START:
3888 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003889#ifdef LIBXML_DOCB_ENABLED
3890 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003891#endif
3892 return;
3893 case XML_ELEMENT_NODE:
3894 case XML_ATTRIBUTE_NODE:
3895 case XML_PI_NODE:
3896 case XML_ENTITY_REF_NODE:
3897 case XML_ENTITY_NODE:
3898 case XML_DTD_NODE:
3899 case XML_DOCUMENT_NODE:
3900 case XML_ELEMENT_DECL:
3901 case XML_ATTRIBUTE_DECL:
3902 case XML_ENTITY_DECL:
3903 break;
3904 }
3905 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3906 cur->name = xmlStrdup(name);
3907}
3908
3909/**
3910 * xmlNodeSetBase:
3911 * @cur: the node being changed
3912 * @uri: the new base URI
3913 *
3914 * Set (or reset) the base URI of a node, i.e. the value of the
3915 * xml:base attribute.
3916 */
3917void
3918xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003919 xmlNsPtr ns;
3920
Owen Taylor3473f882001-02-23 17:55:21 +00003921 if (cur == NULL) return;
3922 switch(cur->type) {
3923 case XML_TEXT_NODE:
3924 case XML_CDATA_SECTION_NODE:
3925 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003926 case XML_DOCUMENT_TYPE_NODE:
3927 case XML_DOCUMENT_FRAG_NODE:
3928 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003929 case XML_DTD_NODE:
3930 case XML_ELEMENT_DECL:
3931 case XML_ATTRIBUTE_DECL:
3932 case XML_ENTITY_DECL:
3933 case XML_PI_NODE:
3934 case XML_ENTITY_REF_NODE:
3935 case XML_ENTITY_NODE:
3936 case XML_NAMESPACE_DECL:
3937 case XML_XINCLUDE_START:
3938 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003939 return;
3940 case XML_ELEMENT_NODE:
3941 case XML_ATTRIBUTE_NODE:
3942 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003943 case XML_DOCUMENT_NODE:
3944#ifdef LIBXML_DOCB_ENABLED
3945 case XML_DOCB_DOCUMENT_NODE:
3946#endif
3947 case XML_HTML_DOCUMENT_NODE: {
3948 xmlDocPtr doc = (xmlDocPtr) cur;
3949
3950 if (doc->URL != NULL)
3951 xmlFree((xmlChar *) doc->URL);
3952 if (uri == NULL)
3953 doc->URL = NULL;
3954 else
3955 doc->URL = xmlStrdup(uri);
3956 return;
3957 }
Owen Taylor3473f882001-02-23 17:55:21 +00003958 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003959
3960 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3961 if (ns == NULL)
3962 return;
3963 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003964}
3965
3966/**
Owen Taylor3473f882001-02-23 17:55:21 +00003967 * xmlNodeGetBase:
3968 * @doc: the document the node pertains to
3969 * @cur: the node being checked
3970 *
3971 * Searches for the BASE URL. The code should work on both XML
3972 * and HTML document even if base mechanisms are completely different.
3973 * It returns the base as defined in RFC 2396 sections
3974 * 5.1.1. Base URI within Document Content
3975 * and
3976 * 5.1.2. Base URI from the Encapsulating Entity
3977 * However it does not return the document base (5.1.3), use
3978 * xmlDocumentGetBase() for this
3979 *
3980 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003981 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003982 */
3983xmlChar *
3984xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003985 xmlChar *oldbase = NULL;
3986 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003987
3988 if ((cur == NULL) && (doc == NULL))
3989 return(NULL);
3990 if (doc == NULL) doc = cur->doc;
3991 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3992 cur = doc->children;
3993 while ((cur != NULL) && (cur->name != NULL)) {
3994 if (cur->type != XML_ELEMENT_NODE) {
3995 cur = cur->next;
3996 continue;
3997 }
3998 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3999 cur = cur->children;
4000 continue;
4001 }
4002 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
4003 cur = cur->children;
4004 continue;
4005 }
4006 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
4007 return(xmlGetProp(cur, BAD_CAST "href"));
4008 }
4009 cur = cur->next;
4010 }
4011 return(NULL);
4012 }
4013 while (cur != NULL) {
4014 if (cur->type == XML_ENTITY_DECL) {
4015 xmlEntityPtr ent = (xmlEntityPtr) cur;
4016 return(xmlStrdup(ent->URI));
4017 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004018 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004019 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004020 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004021 if (oldbase != NULL) {
4022 newbase = xmlBuildURI(oldbase, base);
4023 if (newbase != NULL) {
4024 xmlFree(oldbase);
4025 xmlFree(base);
4026 oldbase = newbase;
4027 } else {
4028 xmlFree(oldbase);
4029 xmlFree(base);
4030 return(NULL);
4031 }
4032 } else {
4033 oldbase = base;
4034 }
4035 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4036 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4037 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4038 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004039 }
4040 }
Owen Taylor3473f882001-02-23 17:55:21 +00004041 cur = cur->parent;
4042 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004043 if ((doc != NULL) && (doc->URL != NULL)) {
4044 if (oldbase == NULL)
4045 return(xmlStrdup(doc->URL));
4046 newbase = xmlBuildURI(oldbase, doc->URL);
4047 xmlFree(oldbase);
4048 return(newbase);
4049 }
4050 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004051}
4052
4053/**
4054 * xmlNodeGetContent:
4055 * @cur: the node being read
4056 *
4057 * Read the value of a node, this can be either the text carried
4058 * directly by this node if it's a TEXT node or the aggregate string
4059 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004060 * Entity references are substituted.
4061 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004062 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004063 */
4064xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004065xmlNodeGetContent(xmlNodePtr cur)
4066{
4067 if (cur == NULL)
4068 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004069 switch (cur->type) {
4070 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004071 case XML_ELEMENT_NODE:{
4072 xmlNodePtr tmp = cur;
4073 xmlBufferPtr buffer;
4074 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004075
Daniel Veillard7646b182002-04-20 06:41:40 +00004076 buffer = xmlBufferCreate();
4077 if (buffer == NULL)
4078 return (NULL);
4079 while (tmp != NULL) {
4080 switch (tmp->type) {
4081 case XML_CDATA_SECTION_NODE:
4082 case XML_TEXT_NODE:
4083 if (tmp->content != NULL)
4084 xmlBufferCat(buffer, tmp->content);
4085 break;
4086 case XML_ENTITY_REF_NODE:{
4087 /* recursive substitution of entity references */
4088 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004089
Daniel Veillard7646b182002-04-20 06:41:40 +00004090 if (cont) {
4091 xmlBufferCat(buffer,
4092 (const xmlChar *) cont);
4093 xmlFree(cont);
4094 }
4095 break;
4096 }
4097 default:
4098 break;
4099 }
4100 /*
4101 * Skip to next node
4102 */
4103 if (tmp->children != NULL) {
4104 if (tmp->children->type != XML_ENTITY_DECL) {
4105 tmp = tmp->children;
4106 continue;
4107 }
4108 }
4109 if (tmp == cur)
4110 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004111
Daniel Veillard7646b182002-04-20 06:41:40 +00004112 if (tmp->next != NULL) {
4113 tmp = tmp->next;
4114 continue;
4115 }
4116
4117 do {
4118 tmp = tmp->parent;
4119 if (tmp == NULL)
4120 break;
4121 if (tmp == cur) {
4122 tmp = NULL;
4123 break;
4124 }
4125 if (tmp->next != NULL) {
4126 tmp = tmp->next;
4127 break;
4128 }
4129 } while (tmp != NULL);
4130 }
4131 ret = buffer->content;
4132 buffer->content = NULL;
4133 xmlBufferFree(buffer);
4134 return (ret);
4135 }
4136 case XML_ATTRIBUTE_NODE:{
4137 xmlAttrPtr attr = (xmlAttrPtr) cur;
4138
4139 if (attr->parent != NULL)
4140 return (xmlNodeListGetString
4141 (attr->parent->doc, attr->children, 1));
4142 else
4143 return (xmlNodeListGetString(NULL, attr->children, 1));
4144 break;
4145 }
Owen Taylor3473f882001-02-23 17:55:21 +00004146 case XML_COMMENT_NODE:
4147 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004148 if (cur->content != NULL)
4149 return (xmlStrdup(cur->content));
4150 return (NULL);
4151 case XML_ENTITY_REF_NODE:{
4152 xmlEntityPtr ent;
4153 xmlNodePtr tmp;
4154 xmlBufferPtr buffer;
4155 xmlChar *ret;
4156
4157 /* lookup entity declaration */
4158 ent = xmlGetDocEntity(cur->doc, cur->name);
4159 if (ent == NULL)
4160 return (NULL);
4161
4162 buffer = xmlBufferCreate();
4163 if (buffer == NULL)
4164 return (NULL);
4165
4166 /* an entity content can be any "well balanced chunk",
4167 * i.e. the result of the content [43] production:
4168 * http://www.w3.org/TR/REC-xml#NT-content
4169 * -> we iterate through child nodes and recursive call
4170 * xmlNodeGetContent() which handles all possible node types */
4171 tmp = ent->children;
4172 while (tmp) {
4173 xmlChar *cont = xmlNodeGetContent(tmp);
4174
4175 if (cont) {
4176 xmlBufferCat(buffer, (const xmlChar *) cont);
4177 xmlFree(cont);
4178 }
4179 tmp = tmp->next;
4180 }
4181
4182 ret = buffer->content;
4183 buffer->content = NULL;
4184 xmlBufferFree(buffer);
4185 return (ret);
4186 }
Owen Taylor3473f882001-02-23 17:55:21 +00004187 case XML_ENTITY_NODE:
4188 case XML_DOCUMENT_NODE:
4189 case XML_HTML_DOCUMENT_NODE:
4190 case XML_DOCUMENT_TYPE_NODE:
4191 case XML_NOTATION_NODE:
4192 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004193 case XML_XINCLUDE_START:
4194 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004195#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004196 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004197#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004198 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004199 case XML_NAMESPACE_DECL: {
4200 xmlChar *tmp;
4201
4202 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4203 return (tmp);
4204 }
Owen Taylor3473f882001-02-23 17:55:21 +00004205 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004206 /* TODO !!! */
4207 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004208 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004209 /* TODO !!! */
4210 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004211 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004212 /* TODO !!! */
4213 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004214 case XML_CDATA_SECTION_NODE:
4215 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004216 if (cur->content != NULL)
4217 return (xmlStrdup(cur->content));
4218 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004219 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004220 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004221}
Owen Taylor3473f882001-02-23 17:55:21 +00004222/**
4223 * xmlNodeSetContent:
4224 * @cur: the node being modified
4225 * @content: the new value of the content
4226 *
4227 * Replace the content of a node.
4228 */
4229void
4230xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4231 if (cur == NULL) {
4232#ifdef DEBUG_TREE
4233 xmlGenericError(xmlGenericErrorContext,
4234 "xmlNodeSetContent : node == NULL\n");
4235#endif
4236 return;
4237 }
4238 switch (cur->type) {
4239 case XML_DOCUMENT_FRAG_NODE:
4240 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004241 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004242 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4243 cur->children = xmlStringGetNodeList(cur->doc, content);
4244 UPDATE_LAST_CHILD_AND_PARENT(cur)
4245 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004246 case XML_TEXT_NODE:
4247 case XML_CDATA_SECTION_NODE:
4248 case XML_ENTITY_REF_NODE:
4249 case XML_ENTITY_NODE:
4250 case XML_PI_NODE:
4251 case XML_COMMENT_NODE:
4252 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004253 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004254 }
4255 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4256 cur->last = cur->children = NULL;
4257 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004258 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004259 } else
4260 cur->content = NULL;
4261 break;
4262 case XML_DOCUMENT_NODE:
4263 case XML_HTML_DOCUMENT_NODE:
4264 case XML_DOCUMENT_TYPE_NODE:
4265 case XML_XINCLUDE_START:
4266 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004267#ifdef LIBXML_DOCB_ENABLED
4268 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004269#endif
4270 break;
4271 case XML_NOTATION_NODE:
4272 break;
4273 case XML_DTD_NODE:
4274 break;
4275 case XML_NAMESPACE_DECL:
4276 break;
4277 case XML_ELEMENT_DECL:
4278 /* TODO !!! */
4279 break;
4280 case XML_ATTRIBUTE_DECL:
4281 /* TODO !!! */
4282 break;
4283 case XML_ENTITY_DECL:
4284 /* TODO !!! */
4285 break;
4286 }
4287}
4288
4289/**
4290 * xmlNodeSetContentLen:
4291 * @cur: the node being modified
4292 * @content: the new value of the content
4293 * @len: the size of @content
4294 *
4295 * Replace the content of a node.
4296 */
4297void
4298xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4299 if (cur == NULL) {
4300#ifdef DEBUG_TREE
4301 xmlGenericError(xmlGenericErrorContext,
4302 "xmlNodeSetContentLen : node == NULL\n");
4303#endif
4304 return;
4305 }
4306 switch (cur->type) {
4307 case XML_DOCUMENT_FRAG_NODE:
4308 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004309 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004310 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4311 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4312 UPDATE_LAST_CHILD_AND_PARENT(cur)
4313 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004314 case XML_TEXT_NODE:
4315 case XML_CDATA_SECTION_NODE:
4316 case XML_ENTITY_REF_NODE:
4317 case XML_ENTITY_NODE:
4318 case XML_PI_NODE:
4319 case XML_COMMENT_NODE:
4320 case XML_NOTATION_NODE:
4321 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004322 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004323 }
4324 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4325 cur->children = cur->last = NULL;
4326 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004327 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004328 } else
4329 cur->content = NULL;
4330 break;
4331 case XML_DOCUMENT_NODE:
4332 case XML_DTD_NODE:
4333 case XML_HTML_DOCUMENT_NODE:
4334 case XML_DOCUMENT_TYPE_NODE:
4335 case XML_NAMESPACE_DECL:
4336 case XML_XINCLUDE_START:
4337 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004338#ifdef LIBXML_DOCB_ENABLED
4339 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004340#endif
4341 break;
4342 case XML_ELEMENT_DECL:
4343 /* TODO !!! */
4344 break;
4345 case XML_ATTRIBUTE_DECL:
4346 /* TODO !!! */
4347 break;
4348 case XML_ENTITY_DECL:
4349 /* TODO !!! */
4350 break;
4351 }
4352}
4353
4354/**
4355 * xmlNodeAddContentLen:
4356 * @cur: the node being modified
4357 * @content: extra content
4358 * @len: the size of @content
4359 *
4360 * Append the extra substring to the node content.
4361 */
4362void
4363xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4364 if (cur == NULL) {
4365#ifdef DEBUG_TREE
4366 xmlGenericError(xmlGenericErrorContext,
4367 "xmlNodeAddContentLen : node == NULL\n");
4368#endif
4369 return;
4370 }
4371 if (len <= 0) return;
4372 switch (cur->type) {
4373 case XML_DOCUMENT_FRAG_NODE:
4374 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004375 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004376
Daniel Veillard7db37732001-07-12 01:20:08 +00004377 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004378 newNode = xmlNewTextLen(content, len);
4379 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004380 tmp = xmlAddChild(cur, newNode);
4381 if (tmp != newNode)
4382 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004383 if ((last != NULL) && (last->next == newNode)) {
4384 xmlTextMerge(last, newNode);
4385 }
4386 }
4387 break;
4388 }
4389 case XML_ATTRIBUTE_NODE:
4390 break;
4391 case XML_TEXT_NODE:
4392 case XML_CDATA_SECTION_NODE:
4393 case XML_ENTITY_REF_NODE:
4394 case XML_ENTITY_NODE:
4395 case XML_PI_NODE:
4396 case XML_COMMENT_NODE:
4397 case XML_NOTATION_NODE:
4398 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004399 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004400 }
4401 case XML_DOCUMENT_NODE:
4402 case XML_DTD_NODE:
4403 case XML_HTML_DOCUMENT_NODE:
4404 case XML_DOCUMENT_TYPE_NODE:
4405 case XML_NAMESPACE_DECL:
4406 case XML_XINCLUDE_START:
4407 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004408#ifdef LIBXML_DOCB_ENABLED
4409 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004410#endif
4411 break;
4412 case XML_ELEMENT_DECL:
4413 case XML_ATTRIBUTE_DECL:
4414 case XML_ENTITY_DECL:
4415 break;
4416 }
4417}
4418
4419/**
4420 * xmlNodeAddContent:
4421 * @cur: the node being modified
4422 * @content: extra content
4423 *
4424 * Append the extra substring to the node content.
4425 */
4426void
4427xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4428 int len;
4429
4430 if (cur == NULL) {
4431#ifdef DEBUG_TREE
4432 xmlGenericError(xmlGenericErrorContext,
4433 "xmlNodeAddContent : node == NULL\n");
4434#endif
4435 return;
4436 }
4437 if (content == NULL) return;
4438 len = xmlStrlen(content);
4439 xmlNodeAddContentLen(cur, content, len);
4440}
4441
4442/**
4443 * xmlTextMerge:
4444 * @first: the first text node
4445 * @second: the second text node being merged
4446 *
4447 * Merge two text nodes into one
4448 * Returns the first text node augmented
4449 */
4450xmlNodePtr
4451xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4452 if (first == NULL) return(second);
4453 if (second == NULL) return(first);
4454 if (first->type != XML_TEXT_NODE) return(first);
4455 if (second->type != XML_TEXT_NODE) return(first);
4456 if (second->name != first->name)
4457 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004458 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004459 xmlUnlinkNode(second);
4460 xmlFreeNode(second);
4461 return(first);
4462}
4463
4464/**
4465 * xmlGetNsList:
4466 * @doc: the document
4467 * @node: the current node
4468 *
4469 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004470 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004471 * that need to be freed by the caller or NULL if no
4472 * namespace if defined
4473 */
4474xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004475xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4476{
Owen Taylor3473f882001-02-23 17:55:21 +00004477 xmlNsPtr cur;
4478 xmlNsPtr *ret = NULL;
4479 int nbns = 0;
4480 int maxns = 10;
4481 int i;
4482
4483 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004484 if (node->type == XML_ELEMENT_NODE) {
4485 cur = node->nsDef;
4486 while (cur != NULL) {
4487 if (ret == NULL) {
4488 ret =
4489 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4490 sizeof(xmlNsPtr));
4491 if (ret == NULL) {
4492 xmlGenericError(xmlGenericErrorContext,
4493 "xmlGetNsList : out of memory!\n");
4494 return (NULL);
4495 }
4496 ret[nbns] = NULL;
4497 }
4498 for (i = 0; i < nbns; i++) {
4499 if ((cur->prefix == ret[i]->prefix) ||
4500 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4501 break;
4502 }
4503 if (i >= nbns) {
4504 if (nbns >= maxns) {
4505 maxns *= 2;
4506 ret = (xmlNsPtr *) xmlRealloc(ret,
4507 (maxns +
4508 1) *
4509 sizeof(xmlNsPtr));
4510 if (ret == NULL) {
4511 xmlGenericError(xmlGenericErrorContext,
4512 "xmlGetNsList : realloc failed!\n");
4513 return (NULL);
4514 }
4515 }
4516 ret[nbns++] = cur;
4517 ret[nbns] = NULL;
4518 }
Owen Taylor3473f882001-02-23 17:55:21 +00004519
Daniel Veillard77044732001-06-29 21:31:07 +00004520 cur = cur->next;
4521 }
4522 }
4523 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004524 }
Daniel Veillard77044732001-06-29 21:31:07 +00004525 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004526}
4527
4528/**
4529 * xmlSearchNs:
4530 * @doc: the document
4531 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004532 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004533 *
4534 * Search a Ns registered under a given name space for a document.
4535 * recurse on the parents until it finds the defined namespace
4536 * or return NULL otherwise.
4537 * @nameSpace can be NULL, this is a search for the default namespace.
4538 * We don't allow to cross entities boundaries. If you don't declare
4539 * the namespace within those you will be in troubles !!! A warning
4540 * is generated to cover this case.
4541 *
4542 * Returns the namespace pointer or NULL.
4543 */
4544xmlNsPtr
4545xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4546 xmlNsPtr cur;
4547
4548 if (node == NULL) return(NULL);
4549 if ((nameSpace != NULL) &&
4550 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004551 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4552 /*
4553 * The XML-1.0 namespace is normally held on the root
4554 * element. In this case exceptionally create it on the
4555 * node element.
4556 */
4557 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4558 if (cur == NULL) {
4559 xmlGenericError(xmlGenericErrorContext,
4560 "xmlSearchNs : malloc failed\n");
4561 return(NULL);
4562 }
4563 memset(cur, 0, sizeof(xmlNs));
4564 cur->type = XML_LOCAL_NAMESPACE;
4565 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4566 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4567 cur->next = node->nsDef;
4568 node->nsDef = cur;
4569 return(cur);
4570 }
Owen Taylor3473f882001-02-23 17:55:21 +00004571 if (doc->oldNs == NULL) {
4572 /*
4573 * Allocate a new Namespace and fill the fields.
4574 */
4575 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4576 if (doc->oldNs == NULL) {
4577 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004578 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004579 return(NULL);
4580 }
4581 memset(doc->oldNs, 0, sizeof(xmlNs));
4582 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4583
4584 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4585 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4586 }
4587 return(doc->oldNs);
4588 }
4589 while (node != NULL) {
4590 if ((node->type == XML_ENTITY_REF_NODE) ||
4591 (node->type == XML_ENTITY_NODE) ||
4592 (node->type == XML_ENTITY_DECL))
4593 return(NULL);
4594 if (node->type == XML_ELEMENT_NODE) {
4595 cur = node->nsDef;
4596 while (cur != NULL) {
4597 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4598 (cur->href != NULL))
4599 return(cur);
4600 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4601 (cur->href != NULL) &&
4602 (xmlStrEqual(cur->prefix, nameSpace)))
4603 return(cur);
4604 cur = cur->next;
4605 }
4606 }
4607 node = node->parent;
4608 }
4609 return(NULL);
4610}
4611
4612/**
4613 * xmlSearchNsByHref:
4614 * @doc: the document
4615 * @node: the current node
4616 * @href: the namespace value
4617 *
4618 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4619 * the defined namespace or return NULL otherwise.
4620 * Returns the namespace pointer or NULL.
4621 */
4622xmlNsPtr
4623xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4624 xmlNsPtr cur;
4625 xmlNodePtr orig = node;
4626
4627 if ((node == NULL) || (href == NULL)) return(NULL);
4628 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004629 /*
4630 * Only the document can hold the XML spec namespace.
4631 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004632 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4633 /*
4634 * The XML-1.0 namespace is normally held on the root
4635 * element. In this case exceptionally create it on the
4636 * node element.
4637 */
4638 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4639 if (cur == NULL) {
4640 xmlGenericError(xmlGenericErrorContext,
4641 "xmlSearchNs : malloc failed\n");
4642 return(NULL);
4643 }
4644 memset(cur, 0, sizeof(xmlNs));
4645 cur->type = XML_LOCAL_NAMESPACE;
4646 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4647 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4648 cur->next = node->nsDef;
4649 node->nsDef = cur;
4650 return(cur);
4651 }
Owen Taylor3473f882001-02-23 17:55:21 +00004652 if (doc->oldNs == NULL) {
4653 /*
4654 * Allocate a new Namespace and fill the fields.
4655 */
4656 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4657 if (doc->oldNs == NULL) {
4658 xmlGenericError(xmlGenericErrorContext,
4659 "xmlSearchNsByHref : malloc failed\n");
4660 return(NULL);
4661 }
4662 memset(doc->oldNs, 0, sizeof(xmlNs));
4663 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4664
4665 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4666 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4667 }
4668 return(doc->oldNs);
4669 }
4670 while (node != NULL) {
4671 cur = node->nsDef;
4672 while (cur != NULL) {
4673 if ((cur->href != NULL) && (href != NULL) &&
4674 (xmlStrEqual(cur->href, href))) {
4675 /*
4676 * Check that the prefix is not shadowed between orig and node
4677 */
4678 xmlNodePtr check = orig;
4679 xmlNsPtr tst;
4680
4681 while (check != node) {
4682 tst = check->nsDef;
4683 while (tst != NULL) {
4684 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4685 goto shadowed;
4686 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4687 (xmlStrEqual(tst->prefix, cur->prefix)))
4688 goto shadowed;
4689 tst = tst->next;
4690 }
4691 check = check->parent;
4692 }
4693 return(cur);
4694 }
4695shadowed:
4696 cur = cur->next;
4697 }
4698 node = node->parent;
4699 }
4700 return(NULL);
4701}
4702
4703/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004704 * xmlNewReconciliedNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004705 * @doc: the document
4706 * @tree: a node expected to hold the new namespace
4707 * @ns: the original namespace
4708 *
4709 * This function tries to locate a namespace definition in a tree
4710 * ancestors, or create a new namespace definition node similar to
4711 * @ns trying to reuse the same prefix. However if the given prefix is
4712 * null (default namespace) or reused within the subtree defined by
4713 * @tree or on one of its ancestors then a new prefix is generated.
4714 * Returns the (new) namespace definition or NULL in case of error
4715 */
4716xmlNsPtr
4717xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4718 xmlNsPtr def;
4719 xmlChar prefix[50];
4720 int counter = 1;
4721
4722 if (tree == NULL) {
4723#ifdef DEBUG_TREE
4724 xmlGenericError(xmlGenericErrorContext,
4725 "xmlNewReconciliedNs : tree == NULL\n");
4726#endif
4727 return(NULL);
4728 }
4729 if (ns == NULL) {
4730#ifdef DEBUG_TREE
4731 xmlGenericError(xmlGenericErrorContext,
4732 "xmlNewReconciliedNs : ns == NULL\n");
4733#endif
4734 return(NULL);
4735 }
4736 /*
4737 * Search an existing namespace definition inherited.
4738 */
4739 def = xmlSearchNsByHref(doc, tree, ns->href);
4740 if (def != NULL)
4741 return(def);
4742
4743 /*
4744 * Find a close prefix which is not already in use.
4745 * Let's strip namespace prefixes longer than 20 chars !
4746 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004747 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004748 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004749 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004750 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004751
Owen Taylor3473f882001-02-23 17:55:21 +00004752 def = xmlSearchNs(doc, tree, prefix);
4753 while (def != NULL) {
4754 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004755 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004756 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004757 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004758 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004759 def = xmlSearchNs(doc, tree, prefix);
4760 }
4761
4762 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004763 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004764 */
4765 def = xmlNewNs(tree, ns->href, prefix);
4766 return(def);
4767}
4768
4769/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004770 * xmlReconciliateNs:
Owen Taylor3473f882001-02-23 17:55:21 +00004771 * @doc: the document
4772 * @tree: a node defining the subtree to reconciliate
4773 *
4774 * This function checks that all the namespaces declared within the given
4775 * tree are properly declared. This is needed for example after Copy or Cut
4776 * and then paste operations. The subtree may still hold pointers to
4777 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004778 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004779 * the new environment. If not possible the new namespaces are redeclared
4780 * on @tree at the top of the given subtree.
4781 * Returns the number of namespace declarations created or -1 in case of error.
4782 */
4783int
4784xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4785 xmlNsPtr *oldNs = NULL;
4786 xmlNsPtr *newNs = NULL;
4787 int sizeCache = 0;
4788 int nbCache = 0;
4789
4790 xmlNsPtr n;
4791 xmlNodePtr node = tree;
4792 xmlAttrPtr attr;
4793 int ret = 0, i;
4794
4795 while (node != NULL) {
4796 /*
4797 * Reconciliate the node namespace
4798 */
4799 if (node->ns != NULL) {
4800 /*
4801 * initialize the cache if needed
4802 */
4803 if (sizeCache == 0) {
4804 sizeCache = 10;
4805 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4806 sizeof(xmlNsPtr));
4807 if (oldNs == NULL) {
4808 xmlGenericError(xmlGenericErrorContext,
4809 "xmlReconciliateNs : memory pbm\n");
4810 return(-1);
4811 }
4812 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4813 sizeof(xmlNsPtr));
4814 if (newNs == NULL) {
4815 xmlGenericError(xmlGenericErrorContext,
4816 "xmlReconciliateNs : memory pbm\n");
4817 xmlFree(oldNs);
4818 return(-1);
4819 }
4820 }
4821 for (i = 0;i < nbCache;i++) {
4822 if (oldNs[i] == node->ns) {
4823 node->ns = newNs[i];
4824 break;
4825 }
4826 }
4827 if (i == nbCache) {
4828 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004829 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004830 */
4831 n = xmlNewReconciliedNs(doc, tree, node->ns);
4832 if (n != NULL) { /* :-( what if else ??? */
4833 /*
4834 * check if we need to grow the cache buffers.
4835 */
4836 if (sizeCache <= nbCache) {
4837 sizeCache *= 2;
4838 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4839 sizeof(xmlNsPtr));
4840 if (oldNs == NULL) {
4841 xmlGenericError(xmlGenericErrorContext,
4842 "xmlReconciliateNs : memory pbm\n");
4843 xmlFree(newNs);
4844 return(-1);
4845 }
4846 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4847 sizeof(xmlNsPtr));
4848 if (newNs == NULL) {
4849 xmlGenericError(xmlGenericErrorContext,
4850 "xmlReconciliateNs : memory pbm\n");
4851 xmlFree(oldNs);
4852 return(-1);
4853 }
4854 }
4855 newNs[nbCache] = n;
4856 oldNs[nbCache++] = node->ns;
4857 node->ns = n;
4858 }
4859 }
4860 }
4861 /*
4862 * now check for namespace hold by attributes on the node.
4863 */
4864 attr = node->properties;
4865 while (attr != NULL) {
4866 if (attr->ns != NULL) {
4867 /*
4868 * initialize the cache if needed
4869 */
4870 if (sizeCache == 0) {
4871 sizeCache = 10;
4872 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4873 sizeof(xmlNsPtr));
4874 if (oldNs == NULL) {
4875 xmlGenericError(xmlGenericErrorContext,
4876 "xmlReconciliateNs : memory pbm\n");
4877 return(-1);
4878 }
4879 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4880 sizeof(xmlNsPtr));
4881 if (newNs == NULL) {
4882 xmlGenericError(xmlGenericErrorContext,
4883 "xmlReconciliateNs : memory pbm\n");
4884 xmlFree(oldNs);
4885 return(-1);
4886 }
4887 }
4888 for (i = 0;i < nbCache;i++) {
4889 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00004890 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00004891 break;
4892 }
4893 }
4894 if (i == nbCache) {
4895 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004896 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004897 */
4898 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4899 if (n != NULL) { /* :-( what if else ??? */
4900 /*
4901 * check if we need to grow the cache buffers.
4902 */
4903 if (sizeCache <= nbCache) {
4904 sizeCache *= 2;
4905 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4906 sizeof(xmlNsPtr));
4907 if (oldNs == NULL) {
4908 xmlGenericError(xmlGenericErrorContext,
4909 "xmlReconciliateNs : memory pbm\n");
4910 xmlFree(newNs);
4911 return(-1);
4912 }
4913 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4914 sizeof(xmlNsPtr));
4915 if (newNs == NULL) {
4916 xmlGenericError(xmlGenericErrorContext,
4917 "xmlReconciliateNs : memory pbm\n");
4918 xmlFree(oldNs);
4919 return(-1);
4920 }
4921 }
4922 newNs[nbCache] = n;
4923 oldNs[nbCache++] = attr->ns;
4924 attr->ns = n;
4925 }
4926 }
4927 }
4928 attr = attr->next;
4929 }
4930
4931 /*
4932 * Browse the full subtree, deep first
4933 */
4934 if (node->children != NULL) {
4935 /* deep first */
4936 node = node->children;
4937 } else if ((node != tree) && (node->next != NULL)) {
4938 /* then siblings */
4939 node = node->next;
4940 } else if (node != tree) {
4941 /* go up to parents->next if needed */
4942 while (node != tree) {
4943 if (node->parent != NULL)
4944 node = node->parent;
4945 if ((node != tree) && (node->next != NULL)) {
4946 node = node->next;
4947 break;
4948 }
4949 if (node->parent == NULL) {
4950 node = NULL;
4951 break;
4952 }
4953 }
4954 /* exit condition */
4955 if (node == tree)
4956 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004957 } else
4958 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004959 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004960 if (oldNs != NULL)
4961 xmlFree(oldNs);
4962 if (newNs != NULL)
4963 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004964 return(ret);
4965}
4966
4967/**
4968 * xmlHasProp:
4969 * @node: the node
4970 * @name: the attribute name
4971 *
4972 * Search an attribute associated to a node
4973 * This function also looks in DTD attribute declaration for #FIXED or
4974 * default declaration values unless DTD use has been turned off.
4975 *
4976 * Returns the attribute or the attribute declaration or NULL if
4977 * neither was found.
4978 */
4979xmlAttrPtr
4980xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4981 xmlAttrPtr prop;
4982 xmlDocPtr doc;
4983
4984 if ((node == NULL) || (name == NULL)) return(NULL);
4985 /*
4986 * Check on the properties attached to the node
4987 */
4988 prop = node->properties;
4989 while (prop != NULL) {
4990 if (xmlStrEqual(prop->name, name)) {
4991 return(prop);
4992 }
4993 prop = prop->next;
4994 }
4995 if (!xmlCheckDTD) return(NULL);
4996
4997 /*
4998 * Check if there is a default declaration in the internal
4999 * or external subsets
5000 */
5001 doc = node->doc;
5002 if (doc != NULL) {
5003 xmlAttributePtr attrDecl;
5004 if (doc->intSubset != NULL) {
5005 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5006 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5007 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5008 if (attrDecl != NULL)
5009 return((xmlAttrPtr) attrDecl);
5010 }
5011 }
5012 return(NULL);
5013}
5014
5015/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005016 * xmlHasNsProp:
5017 * @node: the node
5018 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005019 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005020 *
5021 * Search for an attribute associated to a node
5022 * This attribute has to be anchored in the namespace specified.
5023 * This does the entity substitution.
5024 * This function looks in DTD attribute declaration for #FIXED or
5025 * default declaration values unless DTD use has been turned off.
5026 *
5027 * Returns the attribute or the attribute declaration or NULL
5028 * if neither was found.
5029 */
5030xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005031xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005032 xmlAttrPtr prop;
5033 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005034
5035 if (node == NULL)
5036 return(NULL);
5037
5038 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005039 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005040 return(xmlHasProp(node, name));
5041 while (prop != NULL) {
5042 /*
5043 * One need to have
5044 * - same attribute names
5045 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005046 */
5047 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005048 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5049 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005050 }
5051 prop = prop->next;
5052 }
5053 if (!xmlCheckDTD) return(NULL);
5054
5055 /*
5056 * Check if there is a default declaration in the internal
5057 * or external subsets
5058 */
5059 doc = node->doc;
5060 if (doc != NULL) {
5061 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005062 xmlAttributePtr attrDecl = NULL;
5063 xmlNsPtr *nsList, *cur;
5064 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005065
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005066 nsList = xmlGetNsList(node->doc, node);
5067 if (nsList == NULL)
5068 return(NULL);
5069 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5070 ename = xmlStrdup(node->ns->prefix);
5071 ename = xmlStrcat(ename, BAD_CAST ":");
5072 ename = xmlStrcat(ename, node->name);
5073 } else {
5074 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005075 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005076 if (ename == NULL) {
5077 xmlFree(nsList);
5078 return(NULL);
5079 }
5080
5081 cur = nsList;
5082 while (*cur != NULL) {
5083 if (xmlStrEqual((*cur)->href, nameSpace)) {
5084 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5085 name, (*cur)->prefix);
5086 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5087 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5088 name, (*cur)->prefix);
5089 }
5090 cur++;
5091 }
5092 xmlFree(nsList);
5093 xmlFree(ename);
5094 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005095 }
5096 }
5097 return(NULL);
5098}
5099
5100/**
Owen Taylor3473f882001-02-23 17:55:21 +00005101 * xmlGetProp:
5102 * @node: the node
5103 * @name: the attribute name
5104 *
5105 * Search and get the value of an attribute associated to a node
5106 * This does the entity substitution.
5107 * This function looks in DTD attribute declaration for #FIXED or
5108 * default declaration values unless DTD use has been turned off.
5109 *
5110 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005111 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005112 */
5113xmlChar *
5114xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5115 xmlAttrPtr prop;
5116 xmlDocPtr doc;
5117
5118 if ((node == NULL) || (name == NULL)) return(NULL);
5119 /*
5120 * Check on the properties attached to the node
5121 */
5122 prop = node->properties;
5123 while (prop != NULL) {
5124 if (xmlStrEqual(prop->name, name)) {
5125 xmlChar *ret;
5126
5127 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5128 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5129 return(ret);
5130 }
5131 prop = prop->next;
5132 }
5133 if (!xmlCheckDTD) return(NULL);
5134
5135 /*
5136 * Check if there is a default declaration in the internal
5137 * or external subsets
5138 */
5139 doc = node->doc;
5140 if (doc != NULL) {
5141 xmlAttributePtr attrDecl;
5142 if (doc->intSubset != NULL) {
5143 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5144 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5145 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5146 if (attrDecl != NULL)
5147 return(xmlStrdup(attrDecl->defaultValue));
5148 }
5149 }
5150 return(NULL);
5151}
5152
5153/**
5154 * xmlGetNsProp:
5155 * @node: the node
5156 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005157 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005158 *
5159 * Search and get the value of an attribute associated to a node
5160 * This attribute has to be anchored in the namespace specified.
5161 * This does the entity substitution.
5162 * This function looks in DTD attribute declaration for #FIXED or
5163 * default declaration values unless DTD use has been turned off.
5164 *
5165 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005166 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005167 */
5168xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005169xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005170 xmlAttrPtr prop;
5171 xmlDocPtr doc;
5172 xmlNsPtr ns;
5173
5174 if (node == NULL)
5175 return(NULL);
5176
5177 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005178 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005179 return(xmlGetProp(node, name));
5180 while (prop != NULL) {
5181 /*
5182 * One need to have
5183 * - same attribute names
5184 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005185 */
5186 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005187 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005188 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005189 xmlChar *ret;
5190
5191 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5192 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5193 return(ret);
5194 }
5195 prop = prop->next;
5196 }
5197 if (!xmlCheckDTD) return(NULL);
5198
5199 /*
5200 * Check if there is a default declaration in the internal
5201 * or external subsets
5202 */
5203 doc = node->doc;
5204 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005205 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005206 xmlAttributePtr attrDecl;
5207
Owen Taylor3473f882001-02-23 17:55:21 +00005208 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5209 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5210 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5211
5212 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5213 /*
5214 * The DTD declaration only allows a prefix search
5215 */
5216 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005217 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005218 return(xmlStrdup(attrDecl->defaultValue));
5219 }
5220 }
5221 }
5222 return(NULL);
5223}
5224
5225/**
5226 * xmlSetProp:
5227 * @node: the node
5228 * @name: the attribute name
5229 * @value: the attribute value
5230 *
5231 * Set (or reset) an attribute carried by a node.
5232 * Returns the attribute pointer.
5233 */
5234xmlAttrPtr
5235xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005236 xmlAttrPtr prop;
5237 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005238
5239 if ((node == NULL) || (name == NULL))
5240 return(NULL);
5241 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005242 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005243 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005244 if ((xmlStrEqual(prop->name, name)) &&
5245 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005246 xmlNodePtr oldprop = prop->children;
5247
Owen Taylor3473f882001-02-23 17:55:21 +00005248 prop->children = NULL;
5249 prop->last = NULL;
5250 if (value != NULL) {
5251 xmlChar *buffer;
5252 xmlNodePtr tmp;
5253
5254 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5255 prop->children = xmlStringGetNodeList(node->doc, buffer);
5256 prop->last = NULL;
5257 prop->doc = doc;
5258 tmp = prop->children;
5259 while (tmp != NULL) {
5260 tmp->parent = (xmlNodePtr) prop;
5261 tmp->doc = doc;
5262 if (tmp->next == NULL)
5263 prop->last = tmp;
5264 tmp = tmp->next;
5265 }
5266 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005267 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005268 if (oldprop != NULL)
5269 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005270 return(prop);
5271 }
5272 prop = prop->next;
5273 }
5274 prop = xmlNewProp(node, name, value);
5275 return(prop);
5276}
5277
5278/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005279 * xmlUnsetProp:
5280 * @node: the node
5281 * @name: the attribute name
5282 *
5283 * Remove an attribute carried by a node.
5284 * Returns 0 if successful, -1 if not found
5285 */
5286int
5287xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5288 xmlAttrPtr prop = node->properties, prev = NULL;;
5289
5290 if ((node == NULL) || (name == NULL))
5291 return(-1);
5292 while (prop != NULL) {
5293 if ((xmlStrEqual(prop->name, name)) &&
5294 (prop->ns == NULL)) {
5295 if (prev == NULL)
5296 node->properties = prop->next;
5297 else
5298 prev->next = prop->next;
5299 xmlFreeProp(prop);
5300 return(0);
5301 }
5302 prev = prop;
5303 prop = prop->next;
5304 }
5305 return(-1);
5306}
5307
5308/**
Owen Taylor3473f882001-02-23 17:55:21 +00005309 * xmlSetNsProp:
5310 * @node: the node
5311 * @ns: the namespace definition
5312 * @name: the attribute name
5313 * @value: the attribute value
5314 *
5315 * Set (or reset) an attribute carried by a node.
5316 * The ns structure must be in scope, this is not checked.
5317 *
5318 * Returns the attribute pointer.
5319 */
5320xmlAttrPtr
5321xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5322 const xmlChar *value) {
5323 xmlAttrPtr prop;
5324
5325 if ((node == NULL) || (name == NULL))
5326 return(NULL);
5327
5328 if (ns == NULL)
5329 return(xmlSetProp(node, name, value));
5330 if (ns->href == NULL)
5331 return(NULL);
5332 prop = node->properties;
5333
5334 while (prop != NULL) {
5335 /*
5336 * One need to have
5337 * - same attribute names
5338 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005339 */
5340 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005341 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005342 if (prop->children != NULL)
5343 xmlFreeNodeList(prop->children);
5344 prop->children = NULL;
5345 prop->last = NULL;
5346 prop->ns = ns;
5347 if (value != NULL) {
5348 xmlChar *buffer;
5349 xmlNodePtr tmp;
5350
5351 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5352 prop->children = xmlStringGetNodeList(node->doc, buffer);
5353 prop->last = NULL;
5354 tmp = prop->children;
5355 while (tmp != NULL) {
5356 tmp->parent = (xmlNodePtr) prop;
5357 if (tmp->next == NULL)
5358 prop->last = tmp;
5359 tmp = tmp->next;
5360 }
5361 xmlFree(buffer);
5362 }
5363 return(prop);
5364 }
5365 prop = prop->next;
5366 }
5367 prop = xmlNewNsProp(node, ns, name, value);
5368 return(prop);
5369}
5370
5371/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005372 * xmlUnsetNsProp:
5373 * @node: the node
5374 * @ns: the namespace definition
5375 * @name: the attribute name
5376 *
5377 * Remove an attribute carried by a node.
5378 * Returns 0 if successful, -1 if not found
5379 */
5380int
5381xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5382 xmlAttrPtr prop = node->properties, prev = NULL;;
5383
5384 if ((node == NULL) || (name == NULL))
5385 return(-1);
5386 if (ns == NULL)
5387 return(xmlUnsetProp(node, name));
5388 if (ns->href == NULL)
5389 return(-1);
5390 while (prop != NULL) {
5391 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005392 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005393 if (prev == NULL)
5394 node->properties = prop->next;
5395 else
5396 prev->next = prop->next;
5397 xmlFreeProp(prop);
5398 return(0);
5399 }
5400 prev = prop;
5401 prop = prop->next;
5402 }
5403 return(-1);
5404}
5405
5406/**
Owen Taylor3473f882001-02-23 17:55:21 +00005407 * xmlNodeIsText:
5408 * @node: the node
5409 *
5410 * Is this node a Text node ?
5411 * Returns 1 yes, 0 no
5412 */
5413int
5414xmlNodeIsText(xmlNodePtr node) {
5415 if (node == NULL) return(0);
5416
5417 if (node->type == XML_TEXT_NODE) return(1);
5418 return(0);
5419}
5420
5421/**
5422 * xmlIsBlankNode:
5423 * @node: the node
5424 *
5425 * Checks whether this node is an empty or whitespace only
5426 * (and possibly ignorable) text-node.
5427 *
5428 * Returns 1 yes, 0 no
5429 */
5430int
5431xmlIsBlankNode(xmlNodePtr node) {
5432 const xmlChar *cur;
5433 if (node == NULL) return(0);
5434
Daniel Veillard7db37732001-07-12 01:20:08 +00005435 if ((node->type != XML_TEXT_NODE) &&
5436 (node->type != XML_CDATA_SECTION_NODE))
5437 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005438 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005439 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005440 while (*cur != 0) {
5441 if (!IS_BLANK(*cur)) return(0);
5442 cur++;
5443 }
5444
5445 return(1);
5446}
5447
5448/**
5449 * xmlTextConcat:
5450 * @node: the node
5451 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005452 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005453 *
5454 * Concat the given string at the end of the existing node content
5455 */
5456
5457void
5458xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5459 if (node == NULL) return;
5460
5461 if ((node->type != XML_TEXT_NODE) &&
5462 (node->type != XML_CDATA_SECTION_NODE)) {
5463#ifdef DEBUG_TREE
5464 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005465 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005466#endif
5467 return;
5468 }
Owen Taylor3473f882001-02-23 17:55:21 +00005469 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005470}
5471
5472/************************************************************************
5473 * *
5474 * Output : to a FILE or in memory *
5475 * *
5476 ************************************************************************/
5477
Owen Taylor3473f882001-02-23 17:55:21 +00005478/**
5479 * xmlBufferCreate:
5480 *
5481 * routine to create an XML buffer.
5482 * returns the new structure.
5483 */
5484xmlBufferPtr
5485xmlBufferCreate(void) {
5486 xmlBufferPtr ret;
5487
5488 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5489 if (ret == NULL) {
5490 xmlGenericError(xmlGenericErrorContext,
5491 "xmlBufferCreate : out of memory!\n");
5492 return(NULL);
5493 }
5494 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005495 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005496 ret->alloc = xmlBufferAllocScheme;
5497 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5498 if (ret->content == NULL) {
5499 xmlGenericError(xmlGenericErrorContext,
5500 "xmlBufferCreate : out of memory!\n");
5501 xmlFree(ret);
5502 return(NULL);
5503 }
5504 ret->content[0] = 0;
5505 return(ret);
5506}
5507
5508/**
5509 * xmlBufferCreateSize:
5510 * @size: initial size of buffer
5511 *
5512 * routine to create an XML buffer.
5513 * returns the new structure.
5514 */
5515xmlBufferPtr
5516xmlBufferCreateSize(size_t size) {
5517 xmlBufferPtr ret;
5518
5519 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5520 if (ret == NULL) {
5521 xmlGenericError(xmlGenericErrorContext,
5522 "xmlBufferCreate : out of memory!\n");
5523 return(NULL);
5524 }
5525 ret->use = 0;
5526 ret->alloc = xmlBufferAllocScheme;
5527 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5528 if (ret->size){
5529 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5530 if (ret->content == NULL) {
5531 xmlGenericError(xmlGenericErrorContext,
5532 "xmlBufferCreate : out of memory!\n");
5533 xmlFree(ret);
5534 return(NULL);
5535 }
5536 ret->content[0] = 0;
5537 } else
5538 ret->content = NULL;
5539 return(ret);
5540}
5541
5542/**
5543 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005544 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005545 * @scheme: allocation scheme to use
5546 *
5547 * Sets the allocation scheme for this buffer
5548 */
5549void
5550xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5551 xmlBufferAllocationScheme scheme) {
5552 if (buf == NULL) {
5553#ifdef DEBUG_BUFFER
5554 xmlGenericError(xmlGenericErrorContext,
5555 "xmlBufferSetAllocationScheme: buf == NULL\n");
5556#endif
5557 return;
5558 }
5559
5560 buf->alloc = scheme;
5561}
5562
5563/**
5564 * xmlBufferFree:
5565 * @buf: the buffer to free
5566 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005567 * Frees an XML buffer. It frees both the content and the structure which
5568 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005569 */
5570void
5571xmlBufferFree(xmlBufferPtr buf) {
5572 if (buf == NULL) {
5573#ifdef DEBUG_BUFFER
5574 xmlGenericError(xmlGenericErrorContext,
5575 "xmlBufferFree: buf == NULL\n");
5576#endif
5577 return;
5578 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005579 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005580 xmlFree(buf->content);
5581 }
Owen Taylor3473f882001-02-23 17:55:21 +00005582 xmlFree(buf);
5583}
5584
5585/**
5586 * xmlBufferEmpty:
5587 * @buf: the buffer
5588 *
5589 * empty a buffer.
5590 */
5591void
5592xmlBufferEmpty(xmlBufferPtr buf) {
5593 if (buf->content == NULL) return;
5594 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005595 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005596}
5597
5598/**
5599 * xmlBufferShrink:
5600 * @buf: the buffer to dump
5601 * @len: the number of xmlChar to remove
5602 *
5603 * Remove the beginning of an XML buffer.
5604 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005605 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005606 */
5607int
5608xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5609 if (len == 0) return(0);
5610 if (len > buf->use) return(-1);
5611
5612 buf->use -= len;
5613 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5614
5615 buf->content[buf->use] = 0;
5616 return(len);
5617}
5618
5619/**
5620 * xmlBufferGrow:
5621 * @buf: the buffer
5622 * @len: the minimum free size to allocate
5623 *
5624 * Grow the available space of an XML buffer.
5625 *
5626 * Returns the new available space or -1 in case of error
5627 */
5628int
5629xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5630 int size;
5631 xmlChar *newbuf;
5632
5633 if (len + buf->use < buf->size) return(0);
5634
5635 size = buf->use + len + 100;
5636
5637 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5638 if (newbuf == NULL) return(-1);
5639 buf->content = newbuf;
5640 buf->size = size;
5641 return(buf->size - buf->use);
5642}
5643
5644/**
5645 * xmlBufferDump:
5646 * @file: the file output
5647 * @buf: the buffer to dump
5648 *
5649 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005650 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005651 */
5652int
5653xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5654 int ret;
5655
5656 if (buf == NULL) {
5657#ifdef DEBUG_BUFFER
5658 xmlGenericError(xmlGenericErrorContext,
5659 "xmlBufferDump: buf == NULL\n");
5660#endif
5661 return(0);
5662 }
5663 if (buf->content == NULL) {
5664#ifdef DEBUG_BUFFER
5665 xmlGenericError(xmlGenericErrorContext,
5666 "xmlBufferDump: buf->content == NULL\n");
5667#endif
5668 return(0);
5669 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005670 if (file == NULL)
5671 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005672 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5673 return(ret);
5674}
5675
5676/**
5677 * xmlBufferContent:
5678 * @buf: the buffer
5679 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005680 * Function to extract the content of a buffer
5681 *
Owen Taylor3473f882001-02-23 17:55:21 +00005682 * Returns the internal content
5683 */
5684
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005685const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005686xmlBufferContent(const xmlBufferPtr buf)
5687{
5688 if(!buf)
5689 return NULL;
5690
5691 return buf->content;
5692}
5693
5694/**
5695 * xmlBufferLength:
5696 * @buf: the buffer
5697 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005698 * Function to get the length of a buffer
5699 *
Owen Taylor3473f882001-02-23 17:55:21 +00005700 * Returns the length of data in the internal content
5701 */
5702
5703int
5704xmlBufferLength(const xmlBufferPtr buf)
5705{
5706 if(!buf)
5707 return 0;
5708
5709 return buf->use;
5710}
5711
5712/**
5713 * xmlBufferResize:
5714 * @buf: the buffer to resize
5715 * @size: the desired size
5716 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005717 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005718 *
5719 * Returns 0 in case of problems, 1 otherwise
5720 */
5721int
5722xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5723{
5724 unsigned int newSize;
5725 xmlChar* rebuf = NULL;
5726
5727 /*take care of empty case*/
5728 newSize = (buf->size ? buf->size*2 : size);
5729
5730 /* Don't resize if we don't have to */
5731 if (size < buf->size)
5732 return 1;
5733
5734 /* figure out new size */
5735 switch (buf->alloc){
5736 case XML_BUFFER_ALLOC_DOUBLEIT:
5737 while (size > newSize) newSize *= 2;
5738 break;
5739 case XML_BUFFER_ALLOC_EXACT:
5740 newSize = size+10;
5741 break;
5742 default:
5743 newSize = size+10;
5744 break;
5745 }
5746
5747 if (buf->content == NULL)
5748 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5749 else
5750 rebuf = (xmlChar *) xmlRealloc(buf->content,
5751 newSize * sizeof(xmlChar));
5752 if (rebuf == NULL) {
5753 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005754 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005755 return 0;
5756 }
5757 buf->content = rebuf;
5758 buf->size = newSize;
5759
5760 return 1;
5761}
5762
5763/**
5764 * xmlBufferAdd:
5765 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005766 * @str: the #xmlChar string
5767 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005768 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005769 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005770 * str is recomputed.
5771 */
5772void
5773xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5774 unsigned int needSize;
5775
5776 if (str == NULL) {
5777#ifdef DEBUG_BUFFER
5778 xmlGenericError(xmlGenericErrorContext,
5779 "xmlBufferAdd: str == NULL\n");
5780#endif
5781 return;
5782 }
5783 if (len < -1) {
5784#ifdef DEBUG_BUFFER
5785 xmlGenericError(xmlGenericErrorContext,
5786 "xmlBufferAdd: len < 0\n");
5787#endif
5788 return;
5789 }
5790 if (len == 0) return;
5791
5792 if (len < 0)
5793 len = xmlStrlen(str);
5794
5795 if (len <= 0) return;
5796
5797 needSize = buf->use + len + 2;
5798 if (needSize > buf->size){
5799 if (!xmlBufferResize(buf, needSize)){
5800 xmlGenericError(xmlGenericErrorContext,
5801 "xmlBufferAdd : out of memory!\n");
5802 return;
5803 }
5804 }
5805
5806 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5807 buf->use += len;
5808 buf->content[buf->use] = 0;
5809}
5810
5811/**
5812 * xmlBufferAddHead:
5813 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005814 * @str: the #xmlChar string
5815 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005816 *
5817 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005818 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005819 */
5820void
5821xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5822 unsigned int needSize;
5823
5824 if (str == NULL) {
5825#ifdef DEBUG_BUFFER
5826 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005827 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005828#endif
5829 return;
5830 }
5831 if (len < -1) {
5832#ifdef DEBUG_BUFFER
5833 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005834 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005835#endif
5836 return;
5837 }
5838 if (len == 0) return;
5839
5840 if (len < 0)
5841 len = xmlStrlen(str);
5842
5843 if (len <= 0) return;
5844
5845 needSize = buf->use + len + 2;
5846 if (needSize > buf->size){
5847 if (!xmlBufferResize(buf, needSize)){
5848 xmlGenericError(xmlGenericErrorContext,
5849 "xmlBufferAddHead : out of memory!\n");
5850 return;
5851 }
5852 }
5853
5854 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5855 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5856 buf->use += len;
5857 buf->content[buf->use] = 0;
5858}
5859
5860/**
5861 * xmlBufferCat:
5862 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005863 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005864 *
5865 * Append a zero terminated string to an XML buffer.
5866 */
5867void
5868xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5869 if (str != NULL)
5870 xmlBufferAdd(buf, str, -1);
5871}
5872
5873/**
5874 * xmlBufferCCat:
5875 * @buf: the buffer to dump
5876 * @str: the C char string
5877 *
5878 * Append a zero terminated C string to an XML buffer.
5879 */
5880void
5881xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5882 const char *cur;
5883
5884 if (str == NULL) {
5885#ifdef DEBUG_BUFFER
5886 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005887 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005888#endif
5889 return;
5890 }
5891 for (cur = str;*cur != 0;cur++) {
5892 if (buf->use + 10 >= buf->size) {
5893 if (!xmlBufferResize(buf, buf->use+10)){
5894 xmlGenericError(xmlGenericErrorContext,
5895 "xmlBufferCCat : out of memory!\n");
5896 return;
5897 }
5898 }
5899 buf->content[buf->use++] = *cur;
5900 }
5901 buf->content[buf->use] = 0;
5902}
5903
5904/**
5905 * xmlBufferWriteCHAR:
5906 * @buf: the XML buffer
5907 * @string: the string to add
5908 *
5909 * routine which manages and grows an output buffer. This one adds
5910 * xmlChars at the end of the buffer.
5911 */
5912void
Owen Taylor3473f882001-02-23 17:55:21 +00005913xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00005914(xmlBufferPtr buf, const xmlChar *string) {
5915 xmlBufferCat(buf, string);
5916}
5917
5918/**
5919 * xmlBufferWriteChar:
5920 * @buf: the XML buffer output
5921 * @string: the string to add
5922 *
5923 * routine which manage and grows an output buffer. This one add
5924 * C chars at the end of the array.
5925 */
5926void
5927xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5928 xmlBufferCCat(buf, string);
5929}
5930
5931
5932/**
5933 * xmlBufferWriteQuotedString:
5934 * @buf: the XML buffer output
5935 * @string: the string to add
5936 *
5937 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005938 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005939 * quote or double-quotes internally
5940 */
5941void
5942xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5943 if (xmlStrchr(string, '"')) {
5944 if (xmlStrchr(string, '\'')) {
5945#ifdef DEBUG_BUFFER
5946 xmlGenericError(xmlGenericErrorContext,
5947 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5948#endif
5949 }
5950 xmlBufferCCat(buf, "'");
5951 xmlBufferCat(buf, string);
5952 xmlBufferCCat(buf, "'");
5953 } else {
5954 xmlBufferCCat(buf, "\"");
5955 xmlBufferCat(buf, string);
5956 xmlBufferCCat(buf, "\"");
5957 }
5958}
5959
5960
5961/************************************************************************
5962 * *
5963 * Dumping XML tree content to a simple buffer *
5964 * *
5965 ************************************************************************/
5966
Owen Taylor3473f882001-02-23 17:55:21 +00005967/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00005968 * xmlAttrSerializeContent:
5969 * @buf: the XML buffer output
5970 * @doc: the document
5971 * @attr: the attribute pointer
5972 *
5973 * Serialize the attribute in the buffer
5974 */
5975static void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00005976xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr)
5977{
Daniel Veillarda6d05382002-02-13 13:07:41 +00005978 const xmlChar *cur, *base;
5979 xmlNodePtr children;
5980
5981 children = attr->children;
5982 while (children != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00005983 switch (children->type) {
5984 case XML_TEXT_NODE:
5985 base = cur = children->content;
5986 while (*cur != 0) {
5987 if (*cur == '\n') {
5988 if (base != cur)
5989 xmlBufferAdd(buf, base, cur - base);
5990 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
5991 cur++;
5992 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00005993#if 0
Daniel Veillardebc4ca92002-11-27 11:43:05 +00005994 } else if (*cur == '\'') {
5995 if (base != cur)
5996 xmlBufferAdd(buf, base, cur - base);
5997 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
5998 cur++;
5999 base = cur;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006000#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006001 } else if (*cur == '"') {
6002 if (base != cur)
6003 xmlBufferAdd(buf, base, cur - base);
6004 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6005 cur++;
6006 base = cur;
6007 } else if (*cur == '<') {
6008 if (base != cur)
6009 xmlBufferAdd(buf, base, cur - base);
6010 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6011 cur++;
6012 base = cur;
6013 } else if (*cur == '>') {
6014 if (base != cur)
6015 xmlBufferAdd(buf, base, cur - base);
6016 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6017 cur++;
6018 base = cur;
6019 } else if (*cur == '&') {
6020 if (base != cur)
6021 xmlBufferAdd(buf, base, cur - base);
6022 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6023 cur++;
6024 base = cur;
6025 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6026 (doc->encoding ==
6027 NULL))) {
6028 /*
6029 * We assume we have UTF-8 content.
6030 */
6031 char tmp[10];
6032 int val = 0, l = 1;
Daniel Veillarda6d05382002-02-13 13:07:41 +00006033
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006034 if (base != cur)
6035 xmlBufferAdd(buf, base, cur - base);
6036 if (*cur < 0xC0) {
6037 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6d05382002-02-13 13:07:41 +00006038 "xmlAttrSerializeContent : input not UTF-8\n");
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006039 if (doc != NULL)
6040 doc->encoding =
6041 xmlStrdup(BAD_CAST "ISO-8859-1");
6042 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6043 tmp[sizeof(tmp) - 1] = 0;
6044 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6045 cur++;
6046 base = cur;
6047 continue;
6048 } else if (*cur < 0xE0) {
6049 val = (cur[0]) & 0x1F;
6050 val <<= 6;
6051 val |= (cur[1]) & 0x3F;
6052 l = 2;
6053 } else if (*cur < 0xF0) {
6054 val = (cur[0]) & 0x0F;
6055 val <<= 6;
6056 val |= (cur[1]) & 0x3F;
6057 val <<= 6;
6058 val |= (cur[2]) & 0x3F;
6059 l = 3;
6060 } else if (*cur < 0xF8) {
6061 val = (cur[0]) & 0x07;
6062 val <<= 6;
6063 val |= (cur[1]) & 0x3F;
6064 val <<= 6;
6065 val |= (cur[2]) & 0x3F;
6066 val <<= 6;
6067 val |= (cur[3]) & 0x3F;
6068 l = 4;
6069 }
6070 if ((l == 1) || (!IS_CHAR(val))) {
6071 xmlGenericError(xmlGenericErrorContext,
6072 "xmlAttrSerializeContent : char out of range\n");
6073 if (doc != NULL)
6074 doc->encoding =
6075 xmlStrdup(BAD_CAST "ISO-8859-1");
6076 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6077 tmp[sizeof(tmp) - 1] = 0;
6078 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6079 cur++;
6080 base = cur;
6081 continue;
6082 }
6083 /*
6084 * We could do multiple things here. Just save
6085 * as a char ref
6086 */
6087 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6088 tmp[sizeof(tmp) - 1] = 0;
6089 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6090 cur += l;
6091 base = cur;
6092 } else {
6093 cur++;
6094 }
6095 }
6096 if (base != cur)
6097 xmlBufferAdd(buf, base, cur - base);
6098 break;
6099 case XML_ENTITY_REF_NODE:
6100 xmlBufferAdd(buf, BAD_CAST "&", 1);
6101 xmlBufferAdd(buf, children->name,
6102 xmlStrlen(children->name));
6103 xmlBufferAdd(buf, BAD_CAST ";", 1);
6104 break;
6105 default:
6106 /* should not happen unless we have a badly built tree */
6107 break;
6108 }
6109 children = children->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006110 }
6111}
6112
6113/**
6114 * xmlNodeDump:
6115 * @buf: the XML buffer output
6116 * @doc: the document
6117 * @cur: the current node
6118 * @level: the imbrication level for indenting
6119 * @format: is formatting allowed
6120 *
6121 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006122 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6123 * or xmlKeepBlanksDefault(0) was called
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006124 *
6125 * Returns the number of bytes written to the buffer or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00006126 */
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006127int
Owen Taylor3473f882001-02-23 17:55:21 +00006128xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006129 int format)
6130{
6131 unsigned int use;
6132 int ret;
6133 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006134
6135 if (cur == NULL) {
6136#ifdef DEBUG_TREE
6137 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006138 "xmlNodeDump : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006139#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006140 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006141 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006142 if (buf == NULL) {
6143#ifdef DEBUG_TREE
6144 xmlGenericError(xmlGenericErrorContext,
6145 "xmlNodeDump : buf == NULL\n");
6146#endif
6147 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006148 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006149 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
6150 if (outbuf == NULL) {
6151 xmlGenericError(xmlGenericErrorContext,
6152 "xmlNodeDump: out of memory!\n");
6153 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006154 }
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006155 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
6156 outbuf->buffer = buf;
6157 outbuf->encoder = NULL;
6158 outbuf->writecallback = NULL;
6159 outbuf->closecallback = NULL;
6160 outbuf->context = NULL;
6161 outbuf->written = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006162
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006163 use = buf->use;
6164 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
6165 xmlFree(outbuf);
6166 ret = buf->use - use;
6167 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006168}
6169
6170/**
6171 * xmlElemDump:
6172 * @f: the FILE * for the output
6173 * @doc: the document
6174 * @cur: the current node
6175 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006176 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006177 */
6178void
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006179xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
6180{
6181 xmlOutputBufferPtr outbuf;
Owen Taylor3473f882001-02-23 17:55:21 +00006182
6183 if (cur == NULL) {
6184#ifdef DEBUG_TREE
6185 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006186 "xmlElemDump : cur == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006187#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006188 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006189 }
Owen Taylor3473f882001-02-23 17:55:21 +00006190#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006191 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006192 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006193 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006194 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006195#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006196
6197 outbuf = xmlOutputBufferCreateFile(f, NULL);
6198 if (outbuf == NULL)
6199 return;
6200 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006201#ifdef LIBXML_HTML_ENABLED
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006202 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
6203#else
6204 xmlGenericError(xmlGenericErrorContext,
6205 "HTML support not compiled in\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006206#endif /* LIBXML_HTML_ENABLED */
6207 } else
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006208 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
6209 xmlOutputBufferClose(outbuf);
Owen Taylor3473f882001-02-23 17:55:21 +00006210}
6211
6212/************************************************************************
6213 * *
6214 * Dumping XML tree content to an I/O output buffer *
6215 * *
6216 ************************************************************************/
6217
Owen Taylor3473f882001-02-23 17:55:21 +00006218static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006219xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6220 int level, int format, const char *encoding);
6221static void
Owen Taylor3473f882001-02-23 17:55:21 +00006222xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6223 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006224static void
6225xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6226 xmlNodePtr cur, int level, int format, const char *encoding);
6227
Owen Taylor3473f882001-02-23 17:55:21 +00006228/**
6229 * xmlNsDumpOutput:
6230 * @buf: the XML buffer output
6231 * @cur: a namespace
6232 *
6233 * Dump a local Namespace definition.
6234 * Should be called in the context of attributes dumps.
6235 */
6236static void
6237xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6238 if (cur == NULL) {
6239#ifdef DEBUG_TREE
6240 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006241 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006242#endif
6243 return;
6244 }
6245 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006246 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6247 return;
6248
Owen Taylor3473f882001-02-23 17:55:21 +00006249 /* Within the context of an element attributes */
6250 if (cur->prefix != NULL) {
6251 xmlOutputBufferWriteString(buf, " xmlns:");
6252 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6253 } else
6254 xmlOutputBufferWriteString(buf, " xmlns");
6255 xmlOutputBufferWriteString(buf, "=");
6256 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6257 }
6258}
6259
6260/**
6261 * xmlNsListDumpOutput:
6262 * @buf: the XML buffer output
6263 * @cur: the first namespace
6264 *
6265 * Dump a list of local Namespace definitions.
6266 * Should be called in the context of attributes dumps.
6267 */
6268static void
6269xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6270 while (cur != NULL) {
6271 xmlNsDumpOutput(buf, cur);
6272 cur = cur->next;
6273 }
6274}
6275
6276/**
6277 * xmlDtdDumpOutput:
6278 * @buf: the XML buffer output
6279 * @doc: the document
6280 * @encoding: an optional encoding string
6281 *
6282 * Dump the XML document DTD, if any.
6283 */
6284static void
6285xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6286 if (dtd == NULL) {
6287#ifdef DEBUG_TREE
6288 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006289 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006290#endif
6291 return;
6292 }
6293 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6294 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6295 if (dtd->ExternalID != NULL) {
6296 xmlOutputBufferWriteString(buf, " PUBLIC ");
6297 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6298 xmlOutputBufferWriteString(buf, " ");
6299 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6300 } else if (dtd->SystemID != NULL) {
6301 xmlOutputBufferWriteString(buf, " SYSTEM ");
6302 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6303 }
6304 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6305 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6306 xmlOutputBufferWriteString(buf, ">");
6307 return;
6308 }
6309 xmlOutputBufferWriteString(buf, " [\n");
6310 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6311 xmlOutputBufferWriteString(buf, "]>");
6312}
6313
6314/**
6315 * xmlAttrDumpOutput:
6316 * @buf: the XML buffer output
6317 * @doc: the document
6318 * @cur: the attribute pointer
6319 * @encoding: an optional encoding string
6320 *
6321 * Dump an XML attribute
6322 */
6323static void
6324xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006325 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006326 if (cur == NULL) {
6327#ifdef DEBUG_TREE
6328 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006329 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006330#endif
6331 return;
6332 }
6333 xmlOutputBufferWriteString(buf, " ");
6334 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6335 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6336 xmlOutputBufferWriteString(buf, ":");
6337 }
6338 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006339 xmlOutputBufferWriteString(buf, "=\"");
6340 xmlAttrSerializeContent(buf->buffer, doc, cur);
6341 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006342}
6343
6344/**
6345 * xmlAttrListDumpOutput:
6346 * @buf: the XML buffer output
6347 * @doc: the document
6348 * @cur: the first attribute pointer
6349 * @encoding: an optional encoding string
6350 *
6351 * Dump a list of XML attributes
6352 */
6353static void
6354xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6355 xmlAttrPtr cur, const char *encoding) {
6356 if (cur == NULL) {
6357#ifdef DEBUG_TREE
6358 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006359 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006360#endif
6361 return;
6362 }
6363 while (cur != NULL) {
6364 xmlAttrDumpOutput(buf, doc, cur, encoding);
6365 cur = cur->next;
6366 }
6367}
6368
6369
6370
6371/**
6372 * xmlNodeListDumpOutput:
6373 * @buf: the XML buffer output
6374 * @doc: the document
6375 * @cur: the first node
6376 * @level: the imbrication level for indenting
6377 * @format: is formatting allowed
6378 * @encoding: an optional encoding string
6379 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006380 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006381 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6382 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006383 */
6384static void
6385xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6386 xmlNodePtr cur, int level, int format, const char *encoding) {
6387 int i;
6388
6389 if (cur == NULL) {
6390#ifdef DEBUG_TREE
6391 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006392 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006393#endif
6394 return;
6395 }
6396 while (cur != NULL) {
6397 if ((format) && (xmlIndentTreeOutput) &&
6398 (cur->type == XML_ELEMENT_NODE))
6399 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006400 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006401 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006402 if (format) {
6403 xmlOutputBufferWriteString(buf, "\n");
6404 }
6405 cur = cur->next;
6406 }
6407}
6408
6409/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006410 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006411 * @buf: the XML buffer output
6412 * @doc: the document
6413 * @cur: the current node
6414 * @level: the imbrication level for indenting
6415 * @format: is formatting allowed
6416 * @encoding: an optional encoding string
6417 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006418 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006419 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6420 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006421 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006422static void
6423xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6424 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006425 int i;
6426 xmlNodePtr tmp;
6427
6428 if (cur == NULL) {
6429#ifdef DEBUG_TREE
6430 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006431 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006432#endif
6433 return;
6434 }
6435 if (cur->type == XML_XINCLUDE_START)
6436 return;
6437 if (cur->type == XML_XINCLUDE_END)
6438 return;
6439 if (cur->type == XML_DTD_NODE) {
6440 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6441 return;
6442 }
6443 if (cur->type == XML_ELEMENT_DECL) {
6444 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6445 return;
6446 }
6447 if (cur->type == XML_ATTRIBUTE_DECL) {
6448 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6449 return;
6450 }
6451 if (cur->type == XML_ENTITY_DECL) {
6452 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6453 return;
6454 }
6455 if (cur->type == XML_TEXT_NODE) {
6456 if (cur->content != NULL) {
6457 if ((cur->name == xmlStringText) ||
6458 (cur->name != xmlStringTextNoenc)) {
6459 xmlChar *buffer;
6460
Owen Taylor3473f882001-02-23 17:55:21 +00006461 if (encoding == NULL)
6462 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6463 else
6464 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006465 if (buffer != NULL) {
6466 xmlOutputBufferWriteString(buf, (const char *)buffer);
6467 xmlFree(buffer);
6468 }
6469 } else {
6470 /*
6471 * Disable escaping, needed for XSLT
6472 */
Owen Taylor3473f882001-02-23 17:55:21 +00006473 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006474 }
6475 }
6476
6477 return;
6478 }
6479 if (cur->type == XML_PI_NODE) {
6480 if (cur->content != NULL) {
6481 xmlOutputBufferWriteString(buf, "<?");
6482 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6483 if (cur->content != NULL) {
6484 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006485 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006486 }
6487 xmlOutputBufferWriteString(buf, "?>");
6488 } else {
6489 xmlOutputBufferWriteString(buf, "<?");
6490 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6491 xmlOutputBufferWriteString(buf, "?>");
6492 }
6493 return;
6494 }
6495 if (cur->type == XML_COMMENT_NODE) {
6496 if (cur->content != NULL) {
6497 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006498 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006499 xmlOutputBufferWriteString(buf, "-->");
6500 }
6501 return;
6502 }
6503 if (cur->type == XML_ENTITY_REF_NODE) {
6504 xmlOutputBufferWriteString(buf, "&");
6505 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6506 xmlOutputBufferWriteString(buf, ";");
6507 return;
6508 }
6509 if (cur->type == XML_CDATA_SECTION_NODE) {
6510 xmlOutputBufferWriteString(buf, "<![CDATA[");
6511 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006512 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006513 xmlOutputBufferWriteString(buf, "]]>");
6514 return;
6515 }
6516
6517 if (format == 1) {
6518 tmp = cur->children;
6519 while (tmp != NULL) {
6520 if ((tmp->type == XML_TEXT_NODE) ||
6521 (tmp->type == XML_ENTITY_REF_NODE)) {
6522 format = 0;
6523 break;
6524 }
6525 tmp = tmp->next;
6526 }
6527 }
6528 xmlOutputBufferWriteString(buf, "<");
6529 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6530 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6531 xmlOutputBufferWriteString(buf, ":");
6532 }
6533
6534 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6535 if (cur->nsDef)
6536 xmlNsListDumpOutput(buf, cur->nsDef);
6537 if (cur->properties != NULL)
6538 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6539
Daniel Veillard7db37732001-07-12 01:20:08 +00006540 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6541 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006542 xmlOutputBufferWriteString(buf, "/>");
6543 return;
6544 }
6545 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006546 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006547 xmlChar *buffer;
6548
Owen Taylor3473f882001-02-23 17:55:21 +00006549 if (encoding == NULL)
6550 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6551 else
6552 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006553 if (buffer != NULL) {
6554 xmlOutputBufferWriteString(buf, (const char *)buffer);
6555 xmlFree(buffer);
6556 }
6557 }
6558 if (cur->children != NULL) {
6559 if (format) xmlOutputBufferWriteString(buf, "\n");
6560 xmlNodeListDumpOutput(buf, doc, cur->children,
6561 (level >= 0?level+1:-1), format, encoding);
6562 if ((xmlIndentTreeOutput) && (format))
6563 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006564 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006565 }
6566 xmlOutputBufferWriteString(buf, "</");
6567 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6568 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6569 xmlOutputBufferWriteString(buf, ":");
6570 }
6571
6572 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6573 xmlOutputBufferWriteString(buf, ">");
6574}
6575
6576/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006577 * xmlNodeDumpOutput:
6578 * @buf: the XML buffer output
6579 * @doc: the document
6580 * @cur: the current node
6581 * @level: the imbrication level for indenting
6582 * @format: is formatting allowed
6583 * @encoding: an optional encoding string
6584 *
6585 * Dump an XML node, recursive behaviour, children are printed too.
6586 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6587 * or xmlKeepBlanksDefault(0) was called
6588 */
6589void
6590xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006591 int level, int format, const char *encoding)
6592{
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006593#ifdef LIBXML_HTML_ENABLED
6594 xmlDtdPtr dtd;
6595 int is_xhtml = 0;
6596
6597 dtd = xmlGetIntSubset(doc);
6598 if (dtd != NULL) {
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006599 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6600 if (is_xhtml < 0)
6601 is_xhtml = 0;
6602 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
6603 (cur->type == XML_ELEMENT_NODE) &&
6604 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
6605 if (encoding != NULL)
6606 htmlSetMetaEncoding((htmlDocPtr) cur,
6607 (const xmlChar *) encoding);
6608 else
6609 htmlSetMetaEncoding((htmlDocPtr) cur, BAD_CAST "UTF-8");
6610 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006611 }
6612
6613 if (is_xhtml)
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006614 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006615 else
6616#endif
Daniel Veillardebc4ca92002-11-27 11:43:05 +00006617 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006618}
6619
6620/**
Owen Taylor3473f882001-02-23 17:55:21 +00006621 * xmlDocContentDumpOutput:
6622 * @buf: the XML buffer output
6623 * @cur: the document
6624 * @encoding: an optional encoding string
6625 * @format: should formatting spaces been added
6626 *
6627 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006628 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6629 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006630 */
6631static void
6632xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6633 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006634#ifdef LIBXML_HTML_ENABLED
6635 xmlDtdPtr dtd;
6636 int is_xhtml = 0;
6637#endif
6638
Owen Taylor3473f882001-02-23 17:55:21 +00006639 xmlOutputBufferWriteString(buf, "<?xml version=");
6640 if (cur->version != NULL)
6641 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6642 else
6643 xmlOutputBufferWriteString(buf, "\"1.0\"");
6644 if (encoding == NULL) {
6645 if (cur->encoding != NULL)
6646 encoding = (const char *) cur->encoding;
6647 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6648 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6649 }
6650 if (encoding != NULL) {
6651 xmlOutputBufferWriteString(buf, " encoding=");
6652 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6653 }
6654 switch (cur->standalone) {
6655 case 0:
6656 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6657 break;
6658 case 1:
6659 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6660 break;
6661 }
6662 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006663
6664#ifdef LIBXML_HTML_ENABLED
6665 dtd = xmlGetIntSubset(cur);
6666 if (dtd != NULL) {
6667 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6668 if (is_xhtml < 0) is_xhtml = 0;
6669 }
6670 if (is_xhtml) {
6671 if (encoding != NULL)
6672 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
6673 else
6674 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
6675 }
6676#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006677 if (cur->children != NULL) {
6678 xmlNodePtr child = cur->children;
6679
6680 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006681#ifdef LIBXML_HTML_ENABLED
6682 if (is_xhtml)
6683 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6684 else
6685#endif
6686 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006687 xmlOutputBufferWriteString(buf, "\n");
6688 child = child->next;
6689 }
6690 }
6691}
6692
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006693#ifdef LIBXML_HTML_ENABLED
6694/************************************************************************
6695 * *
6696 * Functions specific to XHTML serialization *
6697 * *
6698 ************************************************************************/
6699
6700#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
6701 "-//W3C//DTD XHTML 1.0 Strict//EN"
6702#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
6703 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
6704#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
6705 "-//W3C//DTD XHTML 1.0 Frameset//EN"
6706#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
6707 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
6708#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
6709 "-//W3C//DTD XHTML 1.0 Transitional//EN"
6710#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
6711 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
6712
6713#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
6714/**
6715 * xmlIsXHTML:
6716 * @systemID: the system identifier
6717 * @publicID: the public identifier
6718 *
6719 * Try to find if the document correspond to an XHTML DTD
6720 *
6721 * Returns 1 if true, 0 if not and -1 in case of error
6722 */
6723int
6724xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
6725 if ((systemID == NULL) && (publicID == NULL))
6726 return(-1);
6727 if (publicID != NULL) {
6728 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
6729 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
6730 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
6731 }
6732 if (systemID != NULL) {
6733 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
6734 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
6735 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
6736 }
6737 return(0);
6738}
6739
6740/**
6741 * xhtmlIsEmpty:
6742 * @node: the node
6743 *
6744 * Check if a node is an empty xhtml node
6745 *
6746 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
6747 */
6748static int
6749xhtmlIsEmpty(xmlNodePtr node) {
6750 if (node == NULL)
6751 return(-1);
6752 if (node->type != XML_ELEMENT_NODE)
6753 return(0);
6754 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
6755 return(0);
6756 if (node->children != NULL)
6757 return(0);
6758 switch (node->name[0]) {
6759 case 'a':
6760 if (xmlStrEqual(node->name, BAD_CAST "area"))
6761 return(1);
6762 return(0);
6763 case 'b':
6764 if (xmlStrEqual(node->name, BAD_CAST "br"))
6765 return(1);
6766 if (xmlStrEqual(node->name, BAD_CAST "base"))
6767 return(1);
6768 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
6769 return(1);
6770 return(0);
6771 case 'c':
6772 if (xmlStrEqual(node->name, BAD_CAST "col"))
6773 return(1);
6774 return(0);
6775 case 'f':
6776 if (xmlStrEqual(node->name, BAD_CAST "frame"))
6777 return(1);
6778 return(0);
6779 case 'h':
6780 if (xmlStrEqual(node->name, BAD_CAST "hr"))
6781 return(1);
6782 return(0);
6783 case 'i':
6784 if (xmlStrEqual(node->name, BAD_CAST "img"))
6785 return(1);
6786 if (xmlStrEqual(node->name, BAD_CAST "input"))
6787 return(1);
6788 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
6789 return(1);
6790 return(0);
6791 case 'l':
6792 if (xmlStrEqual(node->name, BAD_CAST "link"))
6793 return(1);
6794 return(0);
6795 case 'm':
6796 if (xmlStrEqual(node->name, BAD_CAST "meta"))
6797 return(1);
6798 return(0);
6799 case 'p':
6800 if (xmlStrEqual(node->name, BAD_CAST "param"))
6801 return(1);
6802 return(0);
6803 }
6804 return(0);
6805}
6806
6807/**
6808 * xhtmlAttrListDumpOutput:
6809 * @buf: the XML buffer output
6810 * @doc: the document
6811 * @cur: the first attribute pointer
6812 * @encoding: an optional encoding string
6813 *
6814 * Dump a list of XML attributes
6815 */
6816static void
6817xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6818 xmlAttrPtr cur, const char *encoding) {
6819 xmlAttrPtr xml_lang = NULL;
6820 xmlAttrPtr lang = NULL;
6821 xmlAttrPtr name = NULL;
6822 xmlAttrPtr id = NULL;
6823
6824 if (cur == NULL) {
6825#ifdef DEBUG_TREE
6826 xmlGenericError(xmlGenericErrorContext,
6827 "xmlAttrListDumpOutput : property == NULL\n");
6828#endif
6829 return;
6830 }
6831 while (cur != NULL) {
6832 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
6833 id = cur;
6834 else
6835 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
6836 name = cur;
6837 else
6838 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
6839 lang = cur;
6840 else
6841 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
6842 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
6843 xml_lang = cur;
6844 else if ((cur->ns == NULL) &&
6845 ((cur->children == NULL) ||
6846 (cur->children->content == NULL) ||
6847 (cur->children->content[0] == 0)) &&
6848 (htmlIsBooleanAttr(cur->name))) {
6849 if (cur->children != NULL)
6850 xmlFreeNode(cur->children);
6851 cur->children = xmlNewText(cur->name);
6852 if (cur->children != NULL)
6853 cur->children->parent = (xmlNodePtr) cur;
6854 }
6855 xmlAttrDumpOutput(buf, doc, cur, encoding);
6856 cur = cur->next;
6857 }
6858 /*
6859 * C.8
6860 */
6861 if ((name != NULL) && (id == NULL)) {
6862 xmlOutputBufferWriteString(buf, " id=\"");
6863 xmlAttrSerializeContent(buf->buffer, doc, name);
6864 xmlOutputBufferWriteString(buf, "\"");
6865 }
6866 /*
6867 * C.7.
6868 */
6869 if ((lang != NULL) && (xml_lang == NULL)) {
6870 xmlOutputBufferWriteString(buf, " xml:lang=\"");
6871 xmlAttrSerializeContent(buf->buffer, doc, lang);
6872 xmlOutputBufferWriteString(buf, "\"");
6873 } else
6874 if ((xml_lang != NULL) && (lang == NULL)) {
6875 xmlOutputBufferWriteString(buf, " lang=\"");
6876 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
6877 xmlOutputBufferWriteString(buf, "\"");
6878 }
6879}
6880
6881/**
6882 * xhtmlNodeListDumpOutput:
6883 * @buf: the XML buffer output
6884 * @doc: the XHTML document
6885 * @cur: the first node
6886 * @level: the imbrication level for indenting
6887 * @format: is formatting allowed
6888 * @encoding: an optional encoding string
6889 *
6890 * Dump an XML node list, recursive behaviour, children are printed too.
6891 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6892 * or xmlKeepBlanksDefault(0) was called
6893 */
6894static void
6895xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6896 xmlNodePtr cur, int level, int format, const char *encoding) {
6897 int i;
6898
6899 if (cur == NULL) {
6900#ifdef DEBUG_TREE
6901 xmlGenericError(xmlGenericErrorContext,
6902 "xhtmlNodeListDumpOutput : node == NULL\n");
6903#endif
6904 return;
6905 }
6906 while (cur != NULL) {
6907 if ((format) && (xmlIndentTreeOutput) &&
6908 (cur->type == XML_ELEMENT_NODE))
6909 for (i = 0;i < level;i++)
6910 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
6911 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6912 if (format) {
6913 xmlOutputBufferWriteString(buf, "\n");
6914 }
6915 cur = cur->next;
6916 }
6917}
6918
6919/**
6920 * xhtmlNodeDumpOutput:
6921 * @buf: the XML buffer output
6922 * @doc: the XHTML document
6923 * @cur: the current node
6924 * @level: the imbrication level for indenting
6925 * @format: is formatting allowed
6926 * @encoding: an optional encoding string
6927 *
6928 * Dump an XHTML node, recursive behaviour, children are printed too.
6929 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6930 * or xmlKeepBlanksDefault(0) was called
6931 */
6932static void
6933xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6934 int level, int format, const char *encoding) {
6935 int i;
6936 xmlNodePtr tmp;
6937
6938 if (cur == NULL) {
6939#ifdef DEBUG_TREE
6940 xmlGenericError(xmlGenericErrorContext,
6941 "xmlNodeDumpOutput : node == NULL\n");
6942#endif
6943 return;
6944 }
6945 if (cur->type == XML_XINCLUDE_START)
6946 return;
6947 if (cur->type == XML_XINCLUDE_END)
6948 return;
6949 if (cur->type == XML_DTD_NODE) {
6950 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6951 return;
6952 }
6953 if (cur->type == XML_ELEMENT_DECL) {
6954 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6955 return;
6956 }
6957 if (cur->type == XML_ATTRIBUTE_DECL) {
6958 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6959 return;
6960 }
6961 if (cur->type == XML_ENTITY_DECL) {
6962 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6963 return;
6964 }
6965 if (cur->type == XML_TEXT_NODE) {
6966 if (cur->content != NULL) {
6967 if ((cur->name == xmlStringText) ||
6968 (cur->name != xmlStringTextNoenc)) {
6969 xmlChar *buffer;
6970
6971 if (encoding == NULL)
6972 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6973 else
6974 buffer = xmlEncodeSpecialChars(doc, cur->content);
6975 if (buffer != NULL) {
6976 xmlOutputBufferWriteString(buf, (const char *)buffer);
6977 xmlFree(buffer);
6978 }
6979 } else {
6980 /*
6981 * Disable escaping, needed for XSLT
6982 */
6983 xmlOutputBufferWriteString(buf, (const char *) cur->content);
6984 }
6985 }
6986
6987 return;
6988 }
6989 if (cur->type == XML_PI_NODE) {
6990 if (cur->content != NULL) {
6991 xmlOutputBufferWriteString(buf, "<?");
6992 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6993 if (cur->content != NULL) {
6994 xmlOutputBufferWriteString(buf, " ");
6995 xmlOutputBufferWriteString(buf, (const char *)cur->content);
6996 }
6997 xmlOutputBufferWriteString(buf, "?>");
6998 } else {
6999 xmlOutputBufferWriteString(buf, "<?");
7000 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7001 xmlOutputBufferWriteString(buf, "?>");
7002 }
7003 return;
7004 }
7005 if (cur->type == XML_COMMENT_NODE) {
7006 if (cur->content != NULL) {
7007 xmlOutputBufferWriteString(buf, "<!--");
7008 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7009 xmlOutputBufferWriteString(buf, "-->");
7010 }
7011 return;
7012 }
7013 if (cur->type == XML_ENTITY_REF_NODE) {
7014 xmlOutputBufferWriteString(buf, "&");
7015 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7016 xmlOutputBufferWriteString(buf, ";");
7017 return;
7018 }
7019 if (cur->type == XML_CDATA_SECTION_NODE) {
7020 xmlOutputBufferWriteString(buf, "<![CDATA[");
7021 if (cur->content != NULL)
7022 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7023 xmlOutputBufferWriteString(buf, "]]>");
7024 return;
7025 }
7026
7027 if (format == 1) {
7028 tmp = cur->children;
7029 while (tmp != NULL) {
7030 if ((tmp->type == XML_TEXT_NODE) ||
7031 (tmp->type == XML_ENTITY_REF_NODE)) {
7032 format = 0;
7033 break;
7034 }
7035 tmp = tmp->next;
7036 }
7037 }
7038 xmlOutputBufferWriteString(buf, "<");
7039 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7040 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7041 xmlOutputBufferWriteString(buf, ":");
7042 }
7043
7044 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7045 if (cur->nsDef)
7046 xmlNsListDumpOutput(buf, cur->nsDef);
7047 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7048 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7049 /*
7050 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7051 */
7052 xmlOutputBufferWriteString(buf,
7053 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7054 }
7055 if (cur->properties != NULL)
7056 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7057
7058 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7059 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7060 (xhtmlIsEmpty(cur) == 1)) {
7061 /*
7062 * C.2. Empty Elements
7063 */
7064 xmlOutputBufferWriteString(buf, " />");
7065 } else {
7066 /*
7067 * C.3. Element Minimization and Empty Element Content
7068 */
7069 xmlOutputBufferWriteString(buf, "></");
7070 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7071 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7072 xmlOutputBufferWriteString(buf, ":");
7073 }
7074 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7075 xmlOutputBufferWriteString(buf, ">");
7076 }
7077 return;
7078 }
7079 xmlOutputBufferWriteString(buf, ">");
7080 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7081 xmlChar *buffer;
7082
7083 if (encoding == NULL)
7084 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7085 else
7086 buffer = xmlEncodeSpecialChars(doc, cur->content);
7087 if (buffer != NULL) {
7088 xmlOutputBufferWriteString(buf, (const char *)buffer);
7089 xmlFree(buffer);
7090 }
7091 }
7092
7093 /*
7094 * 4.8. Script and Style elements
7095 */
7096 if ((cur->type == XML_ELEMENT_NODE) &&
7097 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7098 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7099 ((cur->ns == NULL) ||
7100 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7101 xmlNodePtr child = cur->children;
7102
7103 while (child != NULL) {
7104 if ((child->type == XML_TEXT_NODE) ||
7105 (child->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard64b35282002-12-04 15:10:40 +00007106 /*
7107 * Apparently CDATA escaping for style just break on IE,
7108 * mozilla and galeon, so ...
7109 */
7110 if (xmlStrEqual(cur->name, BAD_CAST "style") &&
7111 (xmlStrchr(child->content, '<') == NULL) &&
7112 (xmlStrchr(child->content, '>') == NULL) &&
7113 (xmlStrchr(child->content, '&') == NULL)) {
7114 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7115 } else {
7116 xmlOutputBufferWriteString(buf, "<![CDATA[");
7117 if (child->content != NULL)
7118 xmlOutputBufferWriteString(buf,
7119 (const char *)child->content);
7120 xmlOutputBufferWriteString(buf, "]]>");
7121 }
Daniel Veillardd5c2f922002-11-21 14:10:52 +00007122 } else {
7123 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7124 }
7125 child = child->next;
7126 }
7127 } else if (cur->children != NULL) {
7128 if (format) xmlOutputBufferWriteString(buf, "\n");
7129 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7130 (level >= 0?level+1:-1), format, encoding);
7131 if ((xmlIndentTreeOutput) && (format))
7132 for (i = 0;i < level;i++)
7133 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7134 }
7135 xmlOutputBufferWriteString(buf, "</");
7136 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7137 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7138 xmlOutputBufferWriteString(buf, ":");
7139 }
7140
7141 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7142 xmlOutputBufferWriteString(buf, ">");
7143}
7144#endif
7145
Owen Taylor3473f882001-02-23 17:55:21 +00007146/************************************************************************
7147 * *
7148 * Saving functions front-ends *
7149 * *
7150 ************************************************************************/
7151
7152/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007153 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007154 * @out_doc: Document to generate XML text from
7155 * @doc_txt_ptr: Memory pointer for allocated XML text
7156 * @doc_txt_len: Length of the generated XML text
7157 * @txt_encoding: Character encoding to use when generating XML text
7158 * @format: should formatting spaces been added
7159 *
7160 * Dump the current DOM tree into memory using the character encoding specified
7161 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007162 * allocated memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007163 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7164 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007165 */
7166
7167void
7168xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007169 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007170 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007171 int dummy = 0;
7172
7173 xmlCharEncoding doc_charset;
7174 xmlOutputBufferPtr out_buff = NULL;
7175 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7176
7177 if (doc_txt_len == NULL) {
7178 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7179 }
7180
7181 if (doc_txt_ptr == NULL) {
7182 *doc_txt_len = 0;
7183 xmlGenericError(xmlGenericErrorContext,
7184 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7185 return;
7186 }
7187
7188 *doc_txt_ptr = NULL;
7189 *doc_txt_len = 0;
7190
7191 if (out_doc == NULL) {
7192 /* No document, no output */
7193 xmlGenericError(xmlGenericErrorContext,
7194 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7195 return;
7196 }
7197
7198 /*
7199 * Validate the encoding value, if provided.
7200 * This logic is copied from xmlSaveFileEnc.
7201 */
7202
7203 if (txt_encoding == NULL)
7204 txt_encoding = (const char *) out_doc->encoding;
7205 if (txt_encoding != NULL) {
7206 doc_charset = xmlParseCharEncoding(txt_encoding);
7207
7208 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7209 xmlGenericError(xmlGenericErrorContext,
7210 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7211 return;
7212
7213 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7214 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7215 if ( conv_hdlr == NULL ) {
7216 xmlGenericError(xmlGenericErrorContext,
7217 "%s: %s %s '%s'\n",
7218 "xmlDocDumpFormatMemoryEnc",
7219 "Failed to identify encoding handler for",
7220 "character set",
7221 txt_encoding);
7222 return;
7223 }
7224 }
7225 }
7226
7227 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7228 xmlGenericError(xmlGenericErrorContext,
7229 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7230 return;
7231 }
7232
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007233 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007234 xmlOutputBufferFlush(out_buff);
7235 if (out_buff->conv != NULL) {
7236 *doc_txt_len = out_buff->conv->use;
7237 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7238 } else {
7239 *doc_txt_len = out_buff->buffer->use;
7240 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7241 }
7242 (void)xmlOutputBufferClose(out_buff);
7243
7244 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7245 *doc_txt_len = 0;
7246 xmlGenericError(xmlGenericErrorContext,
7247 "xmlDocDumpFormatMemoryEnc: %s\n",
7248 "Failed to allocate memory for document text representation.");
7249 }
7250
7251 return;
7252}
7253
7254/**
7255 * xmlDocDumpMemory:
7256 * @cur: the document
7257 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007258 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007259 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007260 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007261 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007262 */
7263void
7264xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7265 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7266}
7267
7268/**
7269 * xmlDocDumpFormatMemory:
7270 * @cur: the document
7271 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007272 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007273 * @format: should formatting spaces been added
7274 *
7275 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007276 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007277 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007278 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7279 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007280 */
7281void
7282xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7283 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7284}
7285
7286/**
7287 * xmlDocDumpMemoryEnc:
7288 * @out_doc: Document to generate XML text from
7289 * @doc_txt_ptr: Memory pointer for allocated XML text
7290 * @doc_txt_len: Length of the generated XML text
7291 * @txt_encoding: Character encoding to use when generating XML text
7292 *
7293 * Dump the current DOM tree into memory using the character encoding specified
7294 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007295 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007296 */
7297
7298void
7299xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7300 int * doc_txt_len, const char * txt_encoding) {
7301 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007302 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007303}
7304
7305/**
7306 * xmlGetDocCompressMode:
7307 * @doc: the document
7308 *
7309 * get the compression ratio for a document, ZLIB based
7310 * Returns 0 (uncompressed) to 9 (max compression)
7311 */
7312int
7313xmlGetDocCompressMode (xmlDocPtr doc) {
7314 if (doc == NULL) return(-1);
7315 return(doc->compression);
7316}
7317
7318/**
7319 * xmlSetDocCompressMode:
7320 * @doc: the document
7321 * @mode: the compression ratio
7322 *
7323 * set the compression ratio for a document, ZLIB based
7324 * Correct values: 0 (uncompressed) to 9 (max compression)
7325 */
7326void
7327xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7328 if (doc == NULL) return;
7329 if (mode < 0) doc->compression = 0;
7330 else if (mode > 9) doc->compression = 9;
7331 else doc->compression = mode;
7332}
7333
7334/**
7335 * xmlGetCompressMode:
7336 *
7337 * get the default compression mode used, ZLIB based.
7338 * Returns 0 (uncompressed) to 9 (max compression)
7339 */
7340int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007341xmlGetCompressMode(void)
7342{
7343 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007344}
7345
7346/**
7347 * xmlSetCompressMode:
7348 * @mode: the compression ratio
7349 *
7350 * set the default compression mode used, ZLIB based
7351 * Correct values: 0 (uncompressed) to 9 (max compression)
7352 */
7353void
7354xmlSetCompressMode(int mode) {
7355 if (mode < 0) xmlCompressMode = 0;
7356 else if (mode > 9) xmlCompressMode = 9;
7357 else xmlCompressMode = mode;
7358}
7359
7360/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007361 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007362 * @f: the FILE*
7363 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007364 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007365 *
7366 * Dump an XML document to an open FILE.
7367 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007368 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007369 */
7370int
Daniel Veillard9e412302002-06-10 15:59:44 +00007371xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007372 xmlOutputBufferPtr buf;
7373 const char * encoding;
7374 xmlCharEncodingHandlerPtr handler = NULL;
7375 int ret;
7376
7377 if (cur == NULL) {
7378#ifdef DEBUG_TREE
7379 xmlGenericError(xmlGenericErrorContext,
7380 "xmlDocDump : document == NULL\n");
7381#endif
7382 return(-1);
7383 }
7384 encoding = (const char *) cur->encoding;
7385
7386 if (encoding != NULL) {
7387 xmlCharEncoding enc;
7388
7389 enc = xmlParseCharEncoding(encoding);
7390
7391 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7392 xmlGenericError(xmlGenericErrorContext,
7393 "xmlDocDump: document not in UTF8\n");
7394 return(-1);
7395 }
7396 if (enc != XML_CHAR_ENCODING_UTF8) {
7397 handler = xmlFindCharEncodingHandler(encoding);
7398 if (handler == NULL) {
7399 xmlFree((char *) cur->encoding);
7400 cur->encoding = NULL;
7401 }
7402 }
7403 }
7404 buf = xmlOutputBufferCreateFile(f, handler);
7405 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007406 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007407
7408 ret = xmlOutputBufferClose(buf);
7409 return(ret);
7410}
7411
7412/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007413 * xmlDocDump:
7414 * @f: the FILE*
7415 * @cur: the document
7416 *
7417 * Dump an XML document to an open FILE.
7418 *
7419 * returns: the number of bytes written or -1 in case of failure.
7420 */
7421int
7422xmlDocDump(FILE *f, xmlDocPtr cur) {
7423 return(xmlDocFormatDump (f, cur, 0));
7424}
7425
7426/**
Owen Taylor3473f882001-02-23 17:55:21 +00007427 * xmlSaveFileTo:
7428 * @buf: an output I/O buffer
7429 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007430 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007431 *
7432 * Dump an XML document to an I/O buffer.
7433 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007434 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007435 */
7436int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007437xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007438 int ret;
7439
7440 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007441 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007442 ret = xmlOutputBufferClose(buf);
7443 return(ret);
7444}
7445
7446/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007447 * xmlSaveFormatFileTo:
7448 * @buf: an output I/O buffer
7449 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007450 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007451 * @format: should formatting spaces been added
7452 *
7453 * Dump an XML document to an I/O buffer.
7454 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007455 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007456 */
7457int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007458xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007459 int ret;
7460
7461 if (buf == NULL) return(0);
7462 xmlDocContentDumpOutput(buf, cur, encoding, format);
7463 ret = xmlOutputBufferClose(buf);
7464 return(ret);
7465}
7466
7467/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00007468 * xmlSaveFormatFileEnc:
Daniel Veillardf012a642001-07-23 19:10:52 +00007469 * @filename: the filename or URL to output
7470 * @cur: the document being saved
7471 * @encoding: the name of the encoding to use or NULL.
7472 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007473 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00007474 * Dump an XML document to a file or an URL.
7475 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007476 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007477 */
7478int
Daniel Veillardf012a642001-07-23 19:10:52 +00007479xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7480 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007481 xmlOutputBufferPtr buf;
7482 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007483 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007484 int ret;
7485
Daniel Veillardfb25a512002-01-13 20:32:08 +00007486 if (encoding == NULL)
7487 encoding = (const char *) cur->encoding;
7488
Owen Taylor3473f882001-02-23 17:55:21 +00007489 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007490
7491 enc = xmlParseCharEncoding(encoding);
7492 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7493 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007494 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007495 return(-1);
7496 }
7497 if (enc != XML_CHAR_ENCODING_UTF8) {
7498 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007499 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007500 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007501 }
7502 }
7503
Daniel Veillardf012a642001-07-23 19:10:52 +00007504#ifdef HAVE_ZLIB_H
7505 if (cur->compression < 0) cur->compression = xmlCompressMode;
7506#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007507 /*
7508 * save the content to a temp buffer.
7509 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007510 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007511 if (buf == NULL) return(-1);
7512
Daniel Veillardf012a642001-07-23 19:10:52 +00007513 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007514
7515 ret = xmlOutputBufferClose(buf);
7516 return(ret);
7517}
7518
Daniel Veillardf012a642001-07-23 19:10:52 +00007519
7520/**
7521 * xmlSaveFileEnc:
7522 * @filename: the filename (or URL)
7523 * @cur: the document
7524 * @encoding: the name of an encoding (or NULL)
7525 *
7526 * Dump an XML document, converting it to the given encoding
7527 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007528 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007529 */
7530int
7531xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7532 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7533}
7534
Owen Taylor3473f882001-02-23 17:55:21 +00007535/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007536 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007537 * @filename: the filename (or URL)
7538 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007539 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007540 *
7541 * Dump an XML document to a file. Will use compression if
7542 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007543 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007544 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007545 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007546 */
7547int
Daniel Veillard67fee942001-04-26 18:59:03 +00007548xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007549 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007550}
7551
Daniel Veillard67fee942001-04-26 18:59:03 +00007552/**
7553 * xmlSaveFile:
7554 * @filename: the filename (or URL)
7555 * @cur: the document
7556 *
7557 * Dump an XML document to a file. Will use compression if
7558 * compiled in and enabled. If @filename is "-" the stdout file is
7559 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007560 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007561 */
7562int
7563xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007564 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007565}
7566