blob: 575325a2585984f813d368f28bc884df5b123709 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillardd1640922001-12-17 15:30:10 +00002 * tree.c : implementation of access function for an XML tree.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardd5c2f922002-11-21 14:10:52 +00004 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
Owen Taylor3473f882001-02-23 17:55:21 +00007 * See Copyright for the status of this software.
8 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00009 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000010 *
Owen Taylor3473f882001-02-23 17:55:21 +000011 */
12
Daniel Veillard34ce8be2002-03-18 19:37:11 +000013#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000014#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
28#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
Daniel Veillardb8c9be92001-07-09 16:01:19 +000031#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000032#include <libxml/entities.h>
33#include <libxml/valid.h>
34#include <libxml/xmlerror.h>
Daniel Veillardbdb9ba72001-04-11 11:28:06 +000035#include <libxml/parserInternals.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000036#include <libxml/globals.h>
Daniel Veillardd5c2f922002-11-21 14:10:52 +000037#ifdef LIBXML_HTML_ENABLED
38#include <libxml/HTMLtree.h>
39#endif
Owen Taylor3473f882001-02-23 17:55:21 +000040
Daniel Veillard56a4cb82001-03-24 17:00:36 +000041xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
42
43/************************************************************************
44 * *
45 * A few static variables and macros *
46 * *
47 ************************************************************************/
Daniel Veillardd0463562001-10-13 09:15:48 +000048/* #undef xmlStringText */
Daniel Veillard22090732001-07-16 00:06:07 +000049const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000050/* #undef xmlStringTextNoenc */
Daniel Veillard22090732001-07-16 00:06:07 +000051const xmlChar xmlStringTextNoenc[] =
Owen Taylor3473f882001-02-23 17:55:21 +000052 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
Daniel Veillardd0463562001-10-13 09:15:48 +000053/* #undef xmlStringComment */
Daniel Veillard22090732001-07-16 00:06:07 +000054const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
55
Owen Taylor3473f882001-02-23 17:55:21 +000056static int xmlCompressMode = 0;
57static int xmlCheckDTD = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000058
Owen Taylor3473f882001-02-23 17:55:21 +000059#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
60 xmlNodePtr ulccur = (n)->children; \
61 if (ulccur == NULL) { \
62 (n)->last = NULL; \
63 } else { \
64 while (ulccur->next != NULL) { \
65 ulccur->parent = (n); \
66 ulccur = ulccur->next; \
67 } \
68 ulccur->parent = (n); \
69 (n)->last = ulccur; \
70}}
71
72/* #define DEBUG_BUFFER */
73/* #define DEBUG_TREE */
74
75/************************************************************************
76 * *
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +000077 * Functions to move to entities.c once the *
78 * API freeze is smoothen and they can be made public. *
79 * *
80 ************************************************************************/
81#include <libxml/hash.h>
82
83/**
84 * xmlGetEntityFromDtd:
85 * @dtd: A pointer to the DTD to search
86 * @name: The entity name
87 *
88 * Do an entity lookup in the DTD entity hash table and
89 * return the corresponding entity, if found.
90 *
91 * Returns A pointer to the entity structure or NULL if not found.
92 */
93static xmlEntityPtr
94xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
95 xmlEntitiesTablePtr table;
96
97 if((dtd != NULL) && (dtd->entities != NULL)) {
98 table = (xmlEntitiesTablePtr) dtd->entities;
99 return((xmlEntityPtr) xmlHashLookup(table, name));
100 /* return(xmlGetEntityFromTable(table, name)); */
101 }
102 return(NULL);
103}
104/**
105 * xmlGetParameterEntityFromDtd:
106 * @dtd: A pointer to the DTD to search
107 * @name: The entity name
108 *
109 * Do an entity lookup in the DTD pararmeter entity hash table and
110 * return the corresponding entity, if found.
111 *
112 * Returns A pointer to the entity structure or NULL if not found.
113 */
114static xmlEntityPtr
115xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) {
116 xmlEntitiesTablePtr table;
117
118 if ((dtd != NULL) && (dtd->pentities != NULL)) {
119 table = (xmlEntitiesTablePtr) dtd->pentities;
120 return((xmlEntityPtr) xmlHashLookup(table, name));
121 /* return(xmlGetEntityFromTable(table, name)); */
122 }
123 return(NULL);
124}
125
126/************************************************************************
127 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000128 * Allocation and deallocation of basic structures *
129 * *
130 ************************************************************************/
131
132/**
133 * xmlSetBufferAllocationScheme:
134 * @scheme: allocation method to use
135 *
136 * Set the buffer allocation method. Types are
137 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
138 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
139 * improves performance
140 */
141void
142xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
143 xmlBufferAllocScheme = scheme;
144}
145
146/**
147 * xmlGetBufferAllocationScheme:
148 *
149 * Types are
150 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
151 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
152 * improves performance
153 *
154 * Returns the current allocation scheme
155 */
156xmlBufferAllocationScheme
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000157xmlGetBufferAllocationScheme(void) {
Daniel Veillarde043ee12001-04-16 14:08:07 +0000158 return(xmlBufferAllocScheme);
Owen Taylor3473f882001-02-23 17:55:21 +0000159}
160
161/**
162 * xmlNewNs:
163 * @node: the element carrying the namespace
164 * @href: the URI associated
165 * @prefix: the prefix for the namespace
166 *
167 * Creation of a new Namespace. This function will refuse to create
168 * a namespace with a similar prefix than an existing one present on this
169 * node.
170 * We use href==NULL in the case of an element creation where the namespace
171 * was not defined.
Daniel Veillardd1640922001-12-17 15:30:10 +0000172 * Returns a new namespace pointer or NULL
Owen Taylor3473f882001-02-23 17:55:21 +0000173 */
174xmlNsPtr
175xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
176 xmlNsPtr cur;
177
178 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
179 return(NULL);
180
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000181 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")))
182 return(NULL);
183
Owen Taylor3473f882001-02-23 17:55:21 +0000184 /*
185 * Allocate a new Namespace and fill the fields.
186 */
187 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
188 if (cur == NULL) {
189 xmlGenericError(xmlGenericErrorContext,
190 "xmlNewNs : malloc failed\n");
191 return(NULL);
192 }
193 memset(cur, 0, sizeof(xmlNs));
194 cur->type = XML_LOCAL_NAMESPACE;
195
196 if (href != NULL)
197 cur->href = xmlStrdup(href);
198 if (prefix != NULL)
199 cur->prefix = xmlStrdup(prefix);
200
201 /*
202 * Add it at the end to preserve parsing order ...
203 * and checks for existing use of the prefix
204 */
205 if (node != NULL) {
206 if (node->nsDef == NULL) {
207 node->nsDef = cur;
208 } else {
209 xmlNsPtr prev = node->nsDef;
210
211 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
212 (xmlStrEqual(prev->prefix, cur->prefix))) {
213 xmlFreeNs(cur);
214 return(NULL);
215 }
216 while (prev->next != NULL) {
217 prev = prev->next;
218 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
219 (xmlStrEqual(prev->prefix, cur->prefix))) {
220 xmlFreeNs(cur);
221 return(NULL);
222 }
223 }
224 prev->next = cur;
225 }
226 }
227 return(cur);
228}
229
230/**
231 * xmlSetNs:
232 * @node: a node in the document
233 * @ns: a namespace pointer
234 *
235 * Associate a namespace to a node, a posteriori.
236 */
237void
238xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
239 if (node == NULL) {
240#ifdef DEBUG_TREE
241 xmlGenericError(xmlGenericErrorContext,
242 "xmlSetNs: node == NULL\n");
243#endif
244 return;
245 }
246 node->ns = ns;
247}
248
249/**
250 * xmlFreeNs:
251 * @cur: the namespace pointer
252 *
253 * Free up the structures associated to a namespace
254 */
255void
256xmlFreeNs(xmlNsPtr cur) {
257 if (cur == NULL) {
258#ifdef DEBUG_TREE
259 xmlGenericError(xmlGenericErrorContext,
260 "xmlFreeNs : ns == NULL\n");
261#endif
262 return;
263 }
264 if (cur->href != NULL) xmlFree((char *) cur->href);
265 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000266 xmlFree(cur);
267}
268
269/**
270 * xmlFreeNsList:
271 * @cur: the first namespace pointer
272 *
273 * Free up all the structures associated to the chained namespaces.
274 */
275void
276xmlFreeNsList(xmlNsPtr cur) {
277 xmlNsPtr next;
278 if (cur == NULL) {
279#ifdef DEBUG_TREE
280 xmlGenericError(xmlGenericErrorContext,
281 "xmlFreeNsList : ns == NULL\n");
282#endif
283 return;
284 }
285 while (cur != NULL) {
286 next = cur->next;
287 xmlFreeNs(cur);
288 cur = next;
289 }
290}
291
292/**
293 * xmlNewDtd:
294 * @doc: the document pointer
295 * @name: the DTD name
296 * @ExternalID: the external ID
297 * @SystemID: the system ID
298 *
299 * Creation of a new DTD for the external subset. To create an
300 * internal subset, use xmlCreateIntSubset().
301 *
302 * Returns a pointer to the new DTD structure
303 */
304xmlDtdPtr
305xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
306 const xmlChar *ExternalID, const xmlChar *SystemID) {
307 xmlDtdPtr cur;
308
309 if ((doc != NULL) && (doc->extSubset != NULL)) {
310#ifdef DEBUG_TREE
311 xmlGenericError(xmlGenericErrorContext,
312 "xmlNewDtd(%s): document %s already have a DTD %s\n",
313 /* !!! */ (char *) name, doc->name,
314 /* !!! */ (char *)doc->extSubset->name);
315#endif
316 return(NULL);
317 }
318
319 /*
320 * Allocate a new DTD and fill the fields.
321 */
322 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
323 if (cur == NULL) {
324 xmlGenericError(xmlGenericErrorContext,
325 "xmlNewDtd : malloc failed\n");
326 return(NULL);
327 }
328 memset(cur, 0 , sizeof(xmlDtd));
329 cur->type = XML_DTD_NODE;
330
331 if (name != NULL)
332 cur->name = xmlStrdup(name);
333 if (ExternalID != NULL)
334 cur->ExternalID = xmlStrdup(ExternalID);
335 if (SystemID != NULL)
336 cur->SystemID = xmlStrdup(SystemID);
337 if (doc != NULL)
338 doc->extSubset = cur;
339 cur->doc = doc;
340
341 return(cur);
342}
343
344/**
345 * xmlGetIntSubset:
346 * @doc: the document pointer
347 *
348 * Get the internal subset of a document
349 * Returns a pointer to the DTD structure or NULL if not found
350 */
351
352xmlDtdPtr
353xmlGetIntSubset(xmlDocPtr doc) {
354 xmlNodePtr cur;
355
356 if (doc == NULL)
357 return(NULL);
358 cur = doc->children;
359 while (cur != NULL) {
360 if (cur->type == XML_DTD_NODE)
361 return((xmlDtdPtr) cur);
362 cur = cur->next;
363 }
364 return((xmlDtdPtr) doc->intSubset);
365}
366
367/**
368 * xmlCreateIntSubset:
369 * @doc: the document pointer
370 * @name: the DTD name
Daniel Veillarde356c282001-03-10 12:32:04 +0000371 * @ExternalID: the external (PUBLIC) ID
Owen Taylor3473f882001-02-23 17:55:21 +0000372 * @SystemID: the system ID
373 *
374 * Create the internal subset of a document
375 * Returns a pointer to the new DTD structure
376 */
377xmlDtdPtr
378xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
379 const xmlChar *ExternalID, const xmlChar *SystemID) {
380 xmlDtdPtr cur;
381
382 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
383#ifdef DEBUG_TREE
384 xmlGenericError(xmlGenericErrorContext,
385
386 "xmlCreateIntSubset(): document %s already have an internal subset\n",
387 doc->name);
388#endif
389 return(NULL);
390 }
391
392 /*
393 * Allocate a new DTD and fill the fields.
394 */
395 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
396 if (cur == NULL) {
397 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000398 "xmlCreateIntSubset : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000399 return(NULL);
400 }
401 memset(cur, 0, sizeof(xmlDtd));
402 cur->type = XML_DTD_NODE;
403
404 if (name != NULL)
405 cur->name = xmlStrdup(name);
406 if (ExternalID != NULL)
407 cur->ExternalID = xmlStrdup(ExternalID);
408 if (SystemID != NULL)
409 cur->SystemID = xmlStrdup(SystemID);
410 if (doc != NULL) {
411 doc->intSubset = cur;
412 cur->parent = doc;
413 cur->doc = doc;
414 if (doc->children == NULL) {
415 doc->children = (xmlNodePtr) cur;
416 doc->last = (xmlNodePtr) cur;
417 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000418 if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillarde356c282001-03-10 12:32:04 +0000419 xmlNodePtr prev;
420
Owen Taylor3473f882001-02-23 17:55:21 +0000421 prev = doc->children;
422 prev->prev = (xmlNodePtr) cur;
423 cur->next = prev;
424 doc->children = (xmlNodePtr) cur;
425 } else {
Daniel Veillarde356c282001-03-10 12:32:04 +0000426 xmlNodePtr next;
427
428 next = doc->children;
429 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
430 next = next->next;
431 if (next == NULL) {
432 cur->prev = doc->last;
433 cur->prev->next = (xmlNodePtr) cur;
434 cur->next = NULL;
435 doc->last = (xmlNodePtr) cur;
436 } else {
437 cur->next = next;
438 cur->prev = next->prev;
439 if (cur->prev == NULL)
440 doc->children = (xmlNodePtr) cur;
441 else
442 cur->prev->next = (xmlNodePtr) cur;
443 next->prev = (xmlNodePtr) cur;
444 }
Owen Taylor3473f882001-02-23 17:55:21 +0000445 }
446 }
447 }
448 return(cur);
449}
450
451/**
452 * xmlFreeDtd:
453 * @cur: the DTD structure to free up
454 *
455 * Free a DTD structure.
456 */
457void
458xmlFreeDtd(xmlDtdPtr cur) {
459 if (cur == NULL) {
460#ifdef DEBUG_TREE
461 xmlGenericError(xmlGenericErrorContext,
462 "xmlFreeDtd : DTD == NULL\n");
463#endif
464 return;
465 }
466 if (cur->children != NULL) {
467 xmlNodePtr next, c = cur->children;
468
469 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000470 * Cleanup all the DTD comments they are not in the DTD
Owen Taylor3473f882001-02-23 17:55:21 +0000471 * indexes.
472 */
473 while (c != NULL) {
474 next = c->next;
475 if (c->type == XML_COMMENT_NODE) {
476 xmlUnlinkNode(c);
477 xmlFreeNode(c);
478 }
479 c = next;
480 }
481 }
482 if (cur->name != NULL) xmlFree((char *) cur->name);
483 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
484 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
485 /* TODO !!! */
486 if (cur->notations != NULL)
487 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
488
489 if (cur->elements != NULL)
490 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
491 if (cur->attributes != NULL)
492 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
493 if (cur->entities != NULL)
494 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
495 if (cur->pentities != NULL)
496 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
497
Owen Taylor3473f882001-02-23 17:55:21 +0000498 xmlFree(cur);
499}
500
501/**
502 * xmlNewDoc:
503 * @version: xmlChar string giving the version of XML "1.0"
504 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000505 * Creates a new XML document
506 *
Owen Taylor3473f882001-02-23 17:55:21 +0000507 * Returns a new document
508 */
509xmlDocPtr
510xmlNewDoc(const xmlChar *version) {
511 xmlDocPtr cur;
512
513 if (version == NULL)
514 version = (const xmlChar *) "1.0";
515
516 /*
517 * Allocate a new document and fill the fields.
518 */
519 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
520 if (cur == NULL) {
521 xmlGenericError(xmlGenericErrorContext,
522 "xmlNewDoc : malloc failed\n");
523 return(NULL);
524 }
525 memset(cur, 0, sizeof(xmlDoc));
526 cur->type = XML_DOCUMENT_NODE;
527
528 cur->version = xmlStrdup(version);
529 cur->standalone = -1;
530 cur->compression = -1; /* not initialized */
531 cur->doc = cur;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000532 cur->charset = XML_CHAR_ENCODING_UTF8;
Owen Taylor3473f882001-02-23 17:55:21 +0000533 return(cur);
534}
535
536/**
537 * xmlFreeDoc:
538 * @cur: pointer to the document
Owen Taylor3473f882001-02-23 17:55:21 +0000539 *
540 * Free up all the structures used by a document, tree included.
541 */
542void
543xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillarda9142e72001-06-19 11:07:54 +0000544 xmlDtdPtr extSubset, intSubset;
545
Owen Taylor3473f882001-02-23 17:55:21 +0000546 if (cur == NULL) {
547#ifdef DEBUG_TREE
548 xmlGenericError(xmlGenericErrorContext,
549 "xmlFreeDoc : document == NULL\n");
550#endif
551 return;
552 }
Daniel Veillard76d66f42001-05-16 21:05:17 +0000553 /*
554 * Do this before freeing the children list to avoid ID lookups
555 */
556 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
557 cur->ids = NULL;
558 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
559 cur->refs = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000560 extSubset = cur->extSubset;
561 intSubset = cur->intSubset;
Daniel Veillard5997aca2002-03-18 18:36:20 +0000562 if (intSubset == extSubset)
563 extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000564 if (extSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000565 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000566 cur->extSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000567 xmlFreeDtd(extSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000568 }
Daniel Veillarda9142e72001-06-19 11:07:54 +0000569 if (intSubset != NULL) {
Daniel Veillard76d66f42001-05-16 21:05:17 +0000570 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000571 cur->intSubset = NULL;
Daniel Veillarda9142e72001-06-19 11:07:54 +0000572 xmlFreeDtd(intSubset);
Daniel Veillard76d66f42001-05-16 21:05:17 +0000573 }
574
575 if (cur->children != NULL) xmlFreeNodeList(cur->children);
576
Owen Taylor3473f882001-02-23 17:55:21 +0000577 if (cur->version != NULL) xmlFree((char *) cur->version);
578 if (cur->name != NULL) xmlFree((char *) cur->name);
579 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Owen Taylor3473f882001-02-23 17:55:21 +0000580 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Owen Taylor3473f882001-02-23 17:55:21 +0000581 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Owen Taylor3473f882001-02-23 17:55:21 +0000582 xmlFree(cur);
583}
584
585/**
586 * xmlStringLenGetNodeList:
587 * @doc: the document
588 * @value: the value of the text
589 * @len: the length of the string value
590 *
591 * Parse the value string and build the node list associated. Should
592 * produce a flat tree with only TEXTs and ENTITY_REFs.
593 * Returns a pointer to the first child
594 */
595xmlNodePtr
596xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
597 xmlNodePtr ret = NULL, last = NULL;
598 xmlNodePtr node;
599 xmlChar *val;
600 const xmlChar *cur = value;
601 const xmlChar *q;
602 xmlEntityPtr ent;
603
604 if (value == NULL) return(NULL);
605
606 q = cur;
607 while ((*cur != 0) && (cur - value < len)) {
608 if (*cur == '&') {
609 /*
610 * Save the current text.
611 */
612 if (cur != q) {
613 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
614 xmlNodeAddContentLen(last, q, cur - q);
615 } else {
616 node = xmlNewDocTextLen(doc, q, cur - q);
617 if (node == NULL) return(ret);
618 if (last == NULL)
619 last = ret = node;
620 else {
621 last->next = node;
622 node->prev = last;
623 last = node;
624 }
625 }
626 }
627 /*
628 * Read the entity string
629 */
630 cur++;
631 q = cur;
632 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
633 if ((*cur == 0) || (cur - value >= len)) {
634#ifdef DEBUG_TREE
635 xmlGenericError(xmlGenericErrorContext,
636 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
637#endif
638 return(ret);
639 }
640 if (cur != q) {
641 /*
642 * Predefined entities don't generate nodes
643 */
644 val = xmlStrndup(q, cur - q);
645 ent = xmlGetDocEntity(doc, val);
646 if ((ent != NULL) &&
647 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
648 if (last == NULL) {
649 node = xmlNewDocText(doc, ent->content);
650 last = ret = node;
651 } else
652 xmlNodeAddContent(last, ent->content);
653
654 } else {
655 /*
656 * Create a new REFERENCE_REF node
657 */
658 node = xmlNewReference(doc, val);
659 if (node == NULL) {
660 if (val != NULL) xmlFree(val);
661 return(ret);
662 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000663 else if ((ent != NULL) && (ent->children == NULL)) {
664 xmlNodePtr tmp;
665
666 ent->children =
667 xmlStringGetNodeList(doc, (const xmlChar*)node->content);
668 tmp = ent->children;
669 while (tmp) {
670 tmp->parent = (xmlNodePtr)ent;
671 tmp = tmp->next;
672 }
673 }
Owen Taylor3473f882001-02-23 17:55:21 +0000674 if (last == NULL)
675 last = ret = node;
676 else {
677 last->next = node;
678 node->prev = last;
679 last = node;
680 }
681 }
682 xmlFree(val);
683 }
684 cur++;
685 q = cur;
686 } else
687 cur++;
688 }
689 if (cur != q) {
690 /*
691 * Handle the last piece of text.
692 */
693 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
694 xmlNodeAddContentLen(last, q, cur - q);
695 } else {
696 node = xmlNewDocTextLen(doc, q, cur - q);
697 if (node == NULL) return(ret);
698 if (last == NULL)
699 last = ret = node;
700 else {
701 last->next = node;
702 node->prev = last;
703 last = node;
704 }
705 }
706 }
707 return(ret);
708}
709
710/**
711 * xmlStringGetNodeList:
712 * @doc: the document
713 * @value: the value of the attribute
714 *
715 * Parse the value string and build the node list associated. Should
716 * produce a flat tree with only TEXTs and ENTITY_REFs.
717 * Returns a pointer to the first child
718 */
719xmlNodePtr
720xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
721 xmlNodePtr ret = NULL, last = NULL;
722 xmlNodePtr node;
723 xmlChar *val;
724 const xmlChar *cur = value;
725 const xmlChar *q;
726 xmlEntityPtr ent;
727
728 if (value == NULL) return(NULL);
729
730 q = cur;
731 while (*cur != 0) {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000732 if (cur[0] == '&') {
733 int charval = 0;
734 xmlChar tmp;
735
Owen Taylor3473f882001-02-23 17:55:21 +0000736 /*
737 * Save the current text.
738 */
739 if (cur != q) {
740 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
741 xmlNodeAddContentLen(last, q, cur - q);
742 } else {
743 node = xmlNewDocTextLen(doc, q, cur - q);
744 if (node == NULL) return(ret);
745 if (last == NULL)
746 last = ret = node;
747 else {
748 last->next = node;
749 node->prev = last;
750 last = node;
751 }
752 }
753 }
Owen Taylor3473f882001-02-23 17:55:21 +0000754 q = cur;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000755 if ((cur[1] == '#') && (cur[2] == 'x')) {
756 cur += 3;
757 tmp = *cur;
758 while (tmp != ';') { /* Non input consuming loop */
759 if ((tmp >= '0') && (tmp <= '9'))
760 charval = charval * 16 + (tmp - '0');
761 else if ((tmp >= 'a') && (tmp <= 'f'))
762 charval = charval * 16 + (tmp - 'a') + 10;
763 else if ((tmp >= 'A') && (tmp <= 'F'))
764 charval = charval * 16 + (tmp - 'A') + 10;
Owen Taylor3473f882001-02-23 17:55:21 +0000765 else {
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000766 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000767 "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000768 charval = 0;
769 break;
770 }
771 cur++;
772 tmp = *cur;
773 }
774 if (tmp == ';')
775 cur++;
776 q = cur;
777 } else if (cur[1] == '#') {
778 cur += 2;
779 tmp = *cur;
780 while (tmp != ';') { /* Non input consuming loops */
781 if ((tmp >= '0') && (tmp <= '9'))
782 charval = charval * 10 + (tmp - '0');
783 else {
784 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +0000785 "xmlStringGetNodeList: invalid decimal charvalue\n");
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000786 charval = 0;
787 break;
788 }
789 cur++;
790 tmp = *cur;
791 }
792 if (tmp == ';')
793 cur++;
794 q = cur;
795 } else {
796 /*
797 * Read the entity string
798 */
799 cur++;
800 q = cur;
801 while ((*cur != 0) && (*cur != ';')) cur++;
802 if (*cur == 0) {
803#ifdef DEBUG_TREE
804 xmlGenericError(xmlGenericErrorContext,
805 "xmlStringGetNodeList: unterminated entity %30s\n", q);
806#endif
807 return(ret);
808 }
809 if (cur != q) {
810 /*
811 * Predefined entities don't generate nodes
812 */
813 val = xmlStrndup(q, cur - q);
814 ent = xmlGetDocEntity(doc, val);
815 if ((ent != NULL) &&
816 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
817 if (last == NULL) {
818 node = xmlNewDocText(doc, ent->content);
819 last = ret = node;
Daniel Veillard6f42c132002-01-06 23:05:13 +0000820 } else if (last->type != XML_TEXT_NODE) {
821 node = xmlNewDocText(doc, ent->content);
822 last = xmlAddNextSibling(last, node);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000823 } else
824 xmlNodeAddContent(last, ent->content);
825
826 } else {
827 /*
828 * Create a new REFERENCE_REF node
829 */
830 node = xmlNewReference(doc, val);
831 if (node == NULL) {
832 if (val != NULL) xmlFree(val);
833 return(ret);
834 }
Daniel Veillardbf8dae82002-04-18 16:39:10 +0000835 else if ((ent != NULL) && (ent->children == NULL)) {
836 xmlNodePtr temp;
837
838 ent->children = xmlStringGetNodeList(doc,
839 (const xmlChar*)node->content);
840 temp = ent->children;
841 while (temp) {
842 temp->parent = (xmlNodePtr)ent;
843 temp = temp->next;
844 }
845 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000846 if (last == NULL) {
847 last = ret = node;
848 } else {
849 last = xmlAddNextSibling(last, node);
850 }
851 }
852 xmlFree(val);
853 }
854 cur++;
855 q = cur;
856 }
857 if (charval != 0) {
858 xmlChar buf[10];
859 int len;
860
861 len = xmlCopyCharMultiByte(buf, charval);
862 buf[len] = 0;
863 node = xmlNewDocText(doc, buf);
864 if (node != NULL) {
865 if (last == NULL) {
866 last = ret = node;
867 } else {
868 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000869 }
870 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000871
872 charval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000873 }
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000874 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000875 cur++;
876 }
Daniel Veillard75bea542001-05-11 17:41:21 +0000877 if ((cur != q) || (ret == NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +0000878 /*
879 * Handle the last piece of text.
880 */
881 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
882 xmlNodeAddContentLen(last, q, cur - q);
883 } else {
884 node = xmlNewDocTextLen(doc, q, cur - q);
885 if (node == NULL) return(ret);
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000886 if (last == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000887 last = ret = node;
Daniel Veillardbdb9ba72001-04-11 11:28:06 +0000888 } else {
889 last = xmlAddNextSibling(last, node);
Owen Taylor3473f882001-02-23 17:55:21 +0000890 }
891 }
892 }
893 return(ret);
894}
895
896/**
897 * xmlNodeListGetString:
898 * @doc: the document
899 * @list: a Node list
900 * @inLine: should we replace entity contents or show their external form
901 *
902 * Returns the string equivalent to the text contained in the Node list
903 * made of TEXTs and ENTITY_REFs
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000904 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000905 */
906xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000907xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine)
908{
Owen Taylor3473f882001-02-23 17:55:21 +0000909 xmlNodePtr node = list;
910 xmlChar *ret = NULL;
911 xmlEntityPtr ent;
912
Daniel Veillard7646b182002-04-20 06:41:40 +0000913 if (list == NULL)
914 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000915
916 while (node != NULL) {
917 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000918 (node->type == XML_CDATA_SECTION_NODE)) {
919 if (inLine) {
920 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +0000921 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +0000922 xmlChar *buffer;
Owen Taylor3473f882001-02-23 17:55:21 +0000923
Daniel Veillard7646b182002-04-20 06:41:40 +0000924 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
925 if (buffer != NULL) {
926 ret = xmlStrcat(ret, buffer);
927 xmlFree(buffer);
928 }
929 }
930 } else if (node->type == XML_ENTITY_REF_NODE) {
931 if (inLine) {
932 ent = xmlGetDocEntity(doc, node->name);
933 if (ent != NULL) {
934 xmlChar *buffer;
935
936 /* an entity content can be any "well balanced chunk",
937 * i.e. the result of the content [43] production:
938 * http://www.w3.org/TR/REC-xml#NT-content.
939 * So it can contain text, CDATA section or nested
940 * entity reference nodes (among others).
941 * -> we recursive call xmlNodeListGetString()
942 * which handles these types */
943 buffer = xmlNodeListGetString(doc, ent->children, 1);
944 if (buffer != NULL) {
945 ret = xmlStrcat(ret, buffer);
946 xmlFree(buffer);
947 }
948 } else {
949 ret = xmlStrcat(ret, node->content);
950 }
951 } else {
952 xmlChar buf[2];
953
954 buf[0] = '&';
955 buf[1] = 0;
956 ret = xmlStrncat(ret, buf, 1);
957 ret = xmlStrcat(ret, node->name);
958 buf[0] = ';';
959 buf[1] = 0;
960 ret = xmlStrncat(ret, buf, 1);
961 }
962 }
963#if 0
964 else {
965 xmlGenericError(xmlGenericErrorContext,
966 "xmlGetNodeListString : invalid node type %d\n",
967 node->type);
968 }
969#endif
970 node = node->next;
971 }
972 return (ret);
973}
Owen Taylor3473f882001-02-23 17:55:21 +0000974/**
975 * xmlNodeListGetRawString:
976 * @doc: the document
977 * @list: a Node list
978 * @inLine: should we replace entity contents or show their external form
979 *
980 * Returns the string equivalent to the text contained in the Node list
981 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
982 * this function doesn't do any character encoding handling.
983 *
Daniel Veillardbd9afb52002-09-25 22:25:35 +0000984 * Returns a pointer to the string copy, the caller must free it with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +0000985 */
986xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +0000987xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine)
988{
Owen Taylor3473f882001-02-23 17:55:21 +0000989 xmlNodePtr node = list;
990 xmlChar *ret = NULL;
991 xmlEntityPtr ent;
992
Daniel Veillard7646b182002-04-20 06:41:40 +0000993 if (list == NULL)
994 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000995
996 while (node != NULL) {
Daniel Veillard7db37732001-07-12 01:20:08 +0000997 if ((node->type == XML_TEXT_NODE) ||
Daniel Veillard7646b182002-04-20 06:41:40 +0000998 (node->type == XML_CDATA_SECTION_NODE)) {
999 if (inLine) {
1000 ret = xmlStrcat(ret, node->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001001 } else {
Daniel Veillard7646b182002-04-20 06:41:40 +00001002 xmlChar *buffer;
1003
1004 buffer = xmlEncodeSpecialChars(doc, node->content);
1005 if (buffer != NULL) {
1006 ret = xmlStrcat(ret, buffer);
1007 xmlFree(buffer);
1008 }
1009 }
1010 } else if (node->type == XML_ENTITY_REF_NODE) {
1011 if (inLine) {
1012 ent = xmlGetDocEntity(doc, node->name);
1013 if (ent != NULL) {
1014 xmlChar *buffer;
1015
1016 /* an entity content can be any "well balanced chunk",
1017 * i.e. the result of the content [43] production:
1018 * http://www.w3.org/TR/REC-xml#NT-content.
1019 * So it can contain text, CDATA section or nested
1020 * entity reference nodes (among others).
1021 * -> we recursive call xmlNodeListGetRawString()
1022 * which handles these types */
1023 buffer =
1024 xmlNodeListGetRawString(doc, ent->children, 1);
1025 if (buffer != NULL) {
1026 ret = xmlStrcat(ret, buffer);
1027 xmlFree(buffer);
1028 }
1029 } else {
1030 ret = xmlStrcat(ret, node->content);
1031 }
1032 } else {
1033 xmlChar buf[2];
1034
1035 buf[0] = '&';
1036 buf[1] = 0;
1037 ret = xmlStrncat(ret, buf, 1);
1038 ret = xmlStrcat(ret, node->name);
1039 buf[0] = ';';
1040 buf[1] = 0;
1041 ret = xmlStrncat(ret, buf, 1);
1042 }
1043 }
Owen Taylor3473f882001-02-23 17:55:21 +00001044#if 0
Daniel Veillard7646b182002-04-20 06:41:40 +00001045 else {
1046 xmlGenericError(xmlGenericErrorContext,
1047 "xmlGetNodeListString : invalid node type %d\n",
1048 node->type);
1049 }
Owen Taylor3473f882001-02-23 17:55:21 +00001050#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00001051 node = node->next;
Owen Taylor3473f882001-02-23 17:55:21 +00001052 }
Daniel Veillard7646b182002-04-20 06:41:40 +00001053 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001054}
1055
1056/**
1057 * xmlNewProp:
1058 * @node: the holding node
1059 * @name: the name of the attribute
1060 * @value: the value of the attribute
1061 *
1062 * Create a new property carried by a node.
1063 * Returns a pointer to the attribute
1064 */
1065xmlAttrPtr
1066xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1067 xmlAttrPtr cur;
1068 xmlDocPtr doc = NULL;
1069
1070 if (name == NULL) {
1071#ifdef DEBUG_TREE
1072 xmlGenericError(xmlGenericErrorContext,
1073 "xmlNewProp : name == NULL\n");
1074#endif
1075 return(NULL);
1076 }
1077
1078 /*
1079 * Allocate a new property and fill the fields.
1080 */
1081 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1082 if (cur == NULL) {
1083 xmlGenericError(xmlGenericErrorContext,
1084 "xmlNewProp : malloc failed\n");
1085 return(NULL);
1086 }
1087 memset(cur, 0, sizeof(xmlAttr));
1088 cur->type = XML_ATTRIBUTE_NODE;
1089
1090 cur->parent = node;
1091 if (node != NULL) {
1092 doc = node->doc;
1093 cur->doc = doc;
1094 }
1095 cur->name = xmlStrdup(name);
1096 if (value != NULL) {
1097 xmlChar *buffer;
1098 xmlNodePtr tmp;
1099
1100 buffer = xmlEncodeEntitiesReentrant(doc, value);
1101 cur->children = xmlStringGetNodeList(doc, buffer);
1102 cur->last = NULL;
1103 tmp = cur->children;
1104 while (tmp != NULL) {
1105 tmp->parent = (xmlNodePtr) cur;
1106 tmp->doc = doc;
1107 if (tmp->next == NULL)
1108 cur->last = tmp;
1109 tmp = tmp->next;
1110 }
1111 xmlFree(buffer);
1112 }
1113
1114 /*
1115 * Add it at the end to preserve parsing order ...
1116 */
1117 if (node != NULL) {
1118 if (node->properties == NULL) {
1119 node->properties = cur;
1120 } else {
1121 xmlAttrPtr prev = node->properties;
1122
1123 while (prev->next != NULL) prev = prev->next;
1124 prev->next = cur;
1125 cur->prev = prev;
1126 }
1127 }
1128 return(cur);
1129}
1130
1131/**
1132 * xmlNewNsProp:
1133 * @node: the holding node
1134 * @ns: the namespace
1135 * @name: the name of the attribute
1136 * @value: the value of the attribute
1137 *
1138 * Create a new property tagged with a namespace and carried by a node.
1139 * Returns a pointer to the attribute
1140 */
1141xmlAttrPtr
1142xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1143 const xmlChar *value) {
1144 xmlAttrPtr cur;
Daniel Veillarda682b212001-06-07 19:59:42 +00001145 xmlDocPtr doc = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001146
1147 if (name == NULL) {
1148#ifdef DEBUG_TREE
1149 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001150 "xmlNewNsProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001151#endif
1152 return(NULL);
1153 }
1154
1155 /*
1156 * Allocate a new property and fill the fields.
1157 */
1158 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1159 if (cur == NULL) {
1160 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001161 "xmlNewNsProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001162 return(NULL);
1163 }
1164 memset(cur, 0, sizeof(xmlAttr));
1165 cur->type = XML_ATTRIBUTE_NODE;
1166
1167 cur->parent = node;
Daniel Veillarda682b212001-06-07 19:59:42 +00001168 if (node != NULL) {
1169 doc = node->doc;
1170 cur->doc = doc;
1171 }
Owen Taylor3473f882001-02-23 17:55:21 +00001172 cur->ns = ns;
1173 cur->name = xmlStrdup(name);
1174 if (value != NULL) {
1175 xmlChar *buffer;
1176 xmlNodePtr tmp;
1177
Daniel Veillarda682b212001-06-07 19:59:42 +00001178 buffer = xmlEncodeEntitiesReentrant(doc, value);
1179 cur->children = xmlStringGetNodeList(doc, buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00001180 cur->last = NULL;
1181 tmp = cur->children;
1182 while (tmp != NULL) {
1183 tmp->parent = (xmlNodePtr) cur;
1184 if (tmp->next == NULL)
1185 cur->last = tmp;
1186 tmp = tmp->next;
1187 }
1188 xmlFree(buffer);
1189 }
1190
1191 /*
1192 * Add it at the end to preserve parsing order ...
1193 */
1194 if (node != NULL) {
1195 if (node->properties == NULL) {
1196 node->properties = cur;
1197 } else {
1198 xmlAttrPtr prev = node->properties;
1199
1200 while (prev->next != NULL) prev = prev->next;
1201 prev->next = cur;
1202 cur->prev = prev;
1203 }
1204 }
1205 return(cur);
1206}
1207
1208/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001209 * xmlNewNsPropEatName:
1210 * @node: the holding node
1211 * @ns: the namespace
1212 * @name: the name of the attribute
1213 * @value: the value of the attribute
1214 *
1215 * Create a new property tagged with a namespace and carried by a node.
1216 * Returns a pointer to the attribute
1217 */
1218xmlAttrPtr
1219xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1220 const xmlChar *value) {
1221 xmlAttrPtr cur;
1222 xmlDocPtr doc = NULL;
1223
1224 if (name == NULL) {
1225#ifdef DEBUG_TREE
1226 xmlGenericError(xmlGenericErrorContext,
1227 "xmlNewNsPropEatName : name == NULL\n");
1228#endif
1229 return(NULL);
1230 }
1231
1232 /*
1233 * Allocate a new property and fill the fields.
1234 */
1235 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1236 if (cur == NULL) {
1237 xmlGenericError(xmlGenericErrorContext,
1238 "xmlNewNsPropEatName : malloc failed\n");
1239 return(NULL);
1240 }
1241 memset(cur, 0, sizeof(xmlAttr));
1242 cur->type = XML_ATTRIBUTE_NODE;
1243
1244 cur->parent = node;
1245 if (node != NULL) {
1246 doc = node->doc;
1247 cur->doc = doc;
1248 }
1249 cur->ns = ns;
1250 cur->name = name;
1251 if (value != NULL) {
1252 xmlChar *buffer;
1253 xmlNodePtr tmp;
1254
1255 buffer = xmlEncodeEntitiesReentrant(doc, value);
1256 cur->children = xmlStringGetNodeList(doc, buffer);
1257 cur->last = NULL;
1258 tmp = cur->children;
1259 while (tmp != NULL) {
1260 tmp->parent = (xmlNodePtr) cur;
1261 if (tmp->next == NULL)
1262 cur->last = tmp;
1263 tmp = tmp->next;
1264 }
1265 xmlFree(buffer);
1266 }
1267
1268 /*
1269 * Add it at the end to preserve parsing order ...
1270 */
1271 if (node != NULL) {
1272 if (node->properties == NULL) {
1273 node->properties = cur;
1274 } else {
1275 xmlAttrPtr prev = node->properties;
1276
1277 while (prev->next != NULL) prev = prev->next;
1278 prev->next = cur;
1279 cur->prev = prev;
1280 }
1281 }
1282 return(cur);
1283}
1284
1285/**
Owen Taylor3473f882001-02-23 17:55:21 +00001286 * xmlNewDocProp:
1287 * @doc: the document
1288 * @name: the name of the attribute
1289 * @value: the value of the attribute
1290 *
1291 * Create a new property carried by a document.
1292 * Returns a pointer to the attribute
1293 */
1294xmlAttrPtr
1295xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1296 xmlAttrPtr cur;
1297
1298 if (name == NULL) {
1299#ifdef DEBUG_TREE
1300 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001301 "xmlNewDocProp : name == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001302#endif
1303 return(NULL);
1304 }
1305
1306 /*
1307 * Allocate a new property and fill the fields.
1308 */
1309 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1310 if (cur == NULL) {
1311 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001312 "xmlNewDocProp : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001313 return(NULL);
1314 }
1315 memset(cur, 0, sizeof(xmlAttr));
1316 cur->type = XML_ATTRIBUTE_NODE;
1317
1318 cur->name = xmlStrdup(name);
1319 cur->doc = doc;
1320 if (value != NULL) {
1321 xmlNodePtr tmp;
1322
1323 cur->children = xmlStringGetNodeList(doc, value);
1324 cur->last = NULL;
1325
1326 tmp = cur->children;
1327 while (tmp != NULL) {
1328 tmp->parent = (xmlNodePtr) cur;
1329 if (tmp->next == NULL)
1330 cur->last = tmp;
1331 tmp = tmp->next;
1332 }
1333 }
1334 return(cur);
1335}
1336
1337/**
1338 * xmlFreePropList:
1339 * @cur: the first property in the list
1340 *
1341 * Free a property and all its siblings, all the children are freed too.
1342 */
1343void
1344xmlFreePropList(xmlAttrPtr cur) {
1345 xmlAttrPtr next;
1346 if (cur == NULL) {
1347#ifdef DEBUG_TREE
1348 xmlGenericError(xmlGenericErrorContext,
1349 "xmlFreePropList : property == NULL\n");
1350#endif
1351 return;
1352 }
1353 while (cur != NULL) {
1354 next = cur->next;
1355 xmlFreeProp(cur);
1356 cur = next;
1357 }
1358}
1359
1360/**
1361 * xmlFreeProp:
1362 * @cur: an attribute
1363 *
1364 * Free one attribute, all the content is freed too
1365 */
1366void
1367xmlFreeProp(xmlAttrPtr cur) {
1368 if (cur == NULL) {
1369#ifdef DEBUG_TREE
1370 xmlGenericError(xmlGenericErrorContext,
1371 "xmlFreeProp : property == NULL\n");
1372#endif
1373 return;
1374 }
1375 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillard76d66f42001-05-16 21:05:17 +00001376 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
1377 ((cur->parent->doc->intSubset != NULL) ||
1378 (cur->parent->doc->extSubset != NULL))) {
1379 if (xmlIsID(cur->parent->doc, cur->parent, cur))
1380 xmlRemoveID(cur->parent->doc, cur);
1381 }
Owen Taylor3473f882001-02-23 17:55:21 +00001382 if (cur->name != NULL) xmlFree((char *) cur->name);
1383 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Owen Taylor3473f882001-02-23 17:55:21 +00001384 xmlFree(cur);
1385}
1386
1387/**
1388 * xmlRemoveProp:
1389 * @cur: an attribute
1390 *
1391 * Unlink and free one attribute, all the content is freed too
1392 * Note this doesn't work for namespace definition attributes
1393 *
1394 * Returns 0 if success and -1 in case of error.
1395 */
1396int
1397xmlRemoveProp(xmlAttrPtr cur) {
1398 xmlAttrPtr tmp;
1399 if (cur == NULL) {
1400#ifdef DEBUG_TREE
1401 xmlGenericError(xmlGenericErrorContext,
1402 "xmlRemoveProp : cur == NULL\n");
1403#endif
1404 return(-1);
1405 }
1406 if (cur->parent == NULL) {
1407#ifdef DEBUG_TREE
1408 xmlGenericError(xmlGenericErrorContext,
1409 "xmlRemoveProp : cur->parent == NULL\n");
1410#endif
1411 return(-1);
1412 }
1413 tmp = cur->parent->properties;
1414 if (tmp == cur) {
1415 cur->parent->properties = cur->next;
1416 xmlFreeProp(cur);
1417 return(0);
1418 }
1419 while (tmp != NULL) {
1420 if (tmp->next == cur) {
1421 tmp->next = cur->next;
1422 if (tmp->next != NULL)
1423 tmp->next->prev = tmp;
1424 xmlFreeProp(cur);
1425 return(0);
1426 }
1427 tmp = tmp->next;
1428 }
1429#ifdef DEBUG_TREE
1430 xmlGenericError(xmlGenericErrorContext,
1431 "xmlRemoveProp : attribute not owned by its node\n");
1432#endif
1433 return(-1);
1434}
1435
1436/**
1437 * xmlNewPI:
1438 * @name: the processing instruction name
1439 * @content: the PI content
1440 *
1441 * Creation of a processing instruction element.
1442 * Returns a pointer to the new node object.
1443 */
1444xmlNodePtr
1445xmlNewPI(const xmlChar *name, const xmlChar *content) {
1446 xmlNodePtr cur;
1447
1448 if (name == NULL) {
1449#ifdef DEBUG_TREE
1450 xmlGenericError(xmlGenericErrorContext,
1451 "xmlNewPI : name == NULL\n");
1452#endif
1453 return(NULL);
1454 }
1455
1456 /*
1457 * Allocate a new node and fill the fields.
1458 */
1459 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1460 if (cur == NULL) {
1461 xmlGenericError(xmlGenericErrorContext,
1462 "xmlNewPI : malloc failed\n");
1463 return(NULL);
1464 }
1465 memset(cur, 0, sizeof(xmlNode));
1466 cur->type = XML_PI_NODE;
1467
1468 cur->name = xmlStrdup(name);
1469 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001470 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001471 }
1472 return(cur);
1473}
1474
1475/**
1476 * xmlNewNode:
1477 * @ns: namespace if any
1478 * @name: the node name
1479 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001480 * Creation of a new node element. @ns is optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001481 *
1482 * Returns a pointer to the new node object.
1483 */
1484xmlNodePtr
1485xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
1486 xmlNodePtr cur;
1487
1488 if (name == NULL) {
1489#ifdef DEBUG_TREE
1490 xmlGenericError(xmlGenericErrorContext,
1491 "xmlNewNode : name == NULL\n");
1492#endif
1493 return(NULL);
1494 }
1495
1496 /*
1497 * Allocate a new node and fill the fields.
1498 */
1499 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1500 if (cur == NULL) {
1501 xmlGenericError(xmlGenericErrorContext,
1502 "xmlNewNode : malloc failed\n");
1503 return(NULL);
1504 }
1505 memset(cur, 0, sizeof(xmlNode));
1506 cur->type = XML_ELEMENT_NODE;
1507
1508 cur->name = xmlStrdup(name);
1509 cur->ns = ns;
1510 return(cur);
1511}
1512
1513/**
Daniel Veillard46de64e2002-05-29 08:21:33 +00001514 * xmlNewNodeEatName:
1515 * @ns: namespace if any
1516 * @name: the node name
1517 *
1518 * Creation of a new node element. @ns is optional (NULL).
1519 *
1520 * Returns a pointer to the new node object.
1521 */
1522xmlNodePtr
1523xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
1524 xmlNodePtr cur;
1525
1526 if (name == NULL) {
1527#ifdef DEBUG_TREE
1528 xmlGenericError(xmlGenericErrorContext,
1529 "xmlNewNode : name == NULL\n");
1530#endif
1531 return(NULL);
1532 }
1533
1534 /*
1535 * Allocate a new node and fill the fields.
1536 */
1537 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1538 if (cur == NULL) {
1539 xmlGenericError(xmlGenericErrorContext,
1540 "xmlNewNode : malloc failed\n");
1541 return(NULL);
1542 }
1543 memset(cur, 0, sizeof(xmlNode));
1544 cur->type = XML_ELEMENT_NODE;
1545
1546 cur->name = name;
1547 cur->ns = ns;
1548 return(cur);
1549}
1550
1551/**
Owen Taylor3473f882001-02-23 17:55:21 +00001552 * xmlNewDocNode:
1553 * @doc: the document
1554 * @ns: namespace if any
1555 * @name: the node name
1556 * @content: the XML text content if any
1557 *
1558 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001559 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001560 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1561 * references, but XML special chars need to be escaped first by using
1562 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1563 * need entities support.
1564 *
1565 * Returns a pointer to the new node object.
1566 */
1567xmlNodePtr
1568xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
1569 const xmlChar *name, const xmlChar *content) {
1570 xmlNodePtr cur;
1571
1572 cur = xmlNewNode(ns, name);
1573 if (cur != NULL) {
1574 cur->doc = doc;
1575 if (content != NULL) {
1576 cur->children = xmlStringGetNodeList(doc, content);
1577 UPDATE_LAST_CHILD_AND_PARENT(cur)
1578 }
1579 }
1580 return(cur);
1581}
1582
Daniel Veillard46de64e2002-05-29 08:21:33 +00001583/**
1584 * xmlNewDocNodeEatName:
1585 * @doc: the document
1586 * @ns: namespace if any
1587 * @name: the node name
1588 * @content: the XML text content if any
1589 *
1590 * Creation of a new node element within a document. @ns and @content
1591 * are optional (NULL).
1592 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1593 * references, but XML special chars need to be escaped first by using
1594 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1595 * need entities support.
1596 *
1597 * Returns a pointer to the new node object.
1598 */
1599xmlNodePtr
1600xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
1601 xmlChar *name, const xmlChar *content) {
1602 xmlNodePtr cur;
1603
1604 cur = xmlNewNodeEatName(ns, name);
1605 if (cur != NULL) {
1606 cur->doc = doc;
1607 if (content != NULL) {
1608 cur->children = xmlStringGetNodeList(doc, content);
1609 UPDATE_LAST_CHILD_AND_PARENT(cur)
1610 }
1611 }
1612 return(cur);
1613}
1614
Owen Taylor3473f882001-02-23 17:55:21 +00001615
1616/**
1617 * xmlNewDocRawNode:
1618 * @doc: the document
1619 * @ns: namespace if any
1620 * @name: the node name
1621 * @content: the text content if any
1622 *
1623 * Creation of a new node element within a document. @ns and @content
Daniel Veillardd1640922001-12-17 15:30:10 +00001624 * are optional (NULL).
Owen Taylor3473f882001-02-23 17:55:21 +00001625 *
1626 * Returns a pointer to the new node object.
1627 */
1628xmlNodePtr
1629xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1630 const xmlChar *name, const xmlChar *content) {
1631 xmlNodePtr cur;
1632
1633 cur = xmlNewNode(ns, name);
1634 if (cur != NULL) {
1635 cur->doc = doc;
1636 if (content != NULL) {
1637 cur->children = xmlNewDocText(doc, content);
1638 UPDATE_LAST_CHILD_AND_PARENT(cur)
1639 }
1640 }
1641 return(cur);
1642}
1643
1644/**
1645 * xmlNewDocFragment:
1646 * @doc: the document owning the fragment
1647 *
1648 * Creation of a new Fragment node.
1649 * Returns a pointer to the new node object.
1650 */
1651xmlNodePtr
1652xmlNewDocFragment(xmlDocPtr doc) {
1653 xmlNodePtr cur;
1654
1655 /*
1656 * Allocate a new DocumentFragment node and fill the fields.
1657 */
1658 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1659 if (cur == NULL) {
1660 xmlGenericError(xmlGenericErrorContext,
1661 "xmlNewDocFragment : malloc failed\n");
1662 return(NULL);
1663 }
1664 memset(cur, 0, sizeof(xmlNode));
1665 cur->type = XML_DOCUMENT_FRAG_NODE;
1666
1667 cur->doc = doc;
1668 return(cur);
1669}
1670
1671/**
1672 * xmlNewText:
1673 * @content: the text content
1674 *
1675 * Creation of a new text node.
1676 * Returns a pointer to the new node object.
1677 */
1678xmlNodePtr
1679xmlNewText(const xmlChar *content) {
1680 xmlNodePtr cur;
1681
1682 /*
1683 * Allocate a new node and fill the fields.
1684 */
1685 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1686 if (cur == NULL) {
1687 xmlGenericError(xmlGenericErrorContext,
1688 "xmlNewText : malloc failed\n");
1689 return(NULL);
1690 }
1691 memset(cur, 0, sizeof(xmlNode));
1692 cur->type = XML_TEXT_NODE;
1693
1694 cur->name = xmlStringText;
1695 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001696 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001697 }
1698 return(cur);
1699}
1700
1701/**
1702 * xmlNewTextChild:
1703 * @parent: the parent node
1704 * @ns: a namespace if any
1705 * @name: the name of the child
1706 * @content: the text content of the child if any.
1707 *
1708 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00001709 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00001710 * a child TEXT node will be created containing the string content.
1711 *
1712 * Returns a pointer to the new node object.
1713 */
1714xmlNodePtr
1715xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1716 const xmlChar *name, const xmlChar *content) {
1717 xmlNodePtr cur, prev;
1718
1719 if (parent == NULL) {
1720#ifdef DEBUG_TREE
1721 xmlGenericError(xmlGenericErrorContext,
1722 "xmlNewTextChild : parent == NULL\n");
1723#endif
1724 return(NULL);
1725 }
1726
1727 if (name == NULL) {
1728#ifdef DEBUG_TREE
1729 xmlGenericError(xmlGenericErrorContext,
1730 "xmlNewTextChild : name == NULL\n");
1731#endif
1732 return(NULL);
1733 }
1734
1735 /*
1736 * Allocate a new node
1737 */
1738 if (ns == NULL)
1739 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1740 else
1741 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1742 if (cur == NULL) return(NULL);
1743
1744 /*
1745 * add the new element at the end of the children list.
1746 */
1747 cur->type = XML_ELEMENT_NODE;
1748 cur->parent = parent;
1749 cur->doc = parent->doc;
1750 if (parent->children == NULL) {
1751 parent->children = cur;
1752 parent->last = cur;
1753 } else {
1754 prev = parent->last;
1755 prev->next = cur;
1756 cur->prev = prev;
1757 parent->last = cur;
1758 }
1759
1760 return(cur);
1761}
1762
1763/**
1764 * xmlNewCharRef:
1765 * @doc: the document
1766 * @name: the char ref string, starting with # or "&# ... ;"
1767 *
1768 * Creation of a new character reference node.
1769 * Returns a pointer to the new node object.
1770 */
1771xmlNodePtr
1772xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1773 xmlNodePtr cur;
1774
1775 /*
1776 * Allocate a new node and fill the fields.
1777 */
1778 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1779 if (cur == NULL) {
1780 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001781 "xmlNewCharRef : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001782 return(NULL);
1783 }
1784 memset(cur, 0, sizeof(xmlNode));
1785 cur->type = XML_ENTITY_REF_NODE;
1786
1787 cur->doc = doc;
1788 if (name[0] == '&') {
1789 int len;
1790 name++;
1791 len = xmlStrlen(name);
1792 if (name[len - 1] == ';')
1793 cur->name = xmlStrndup(name, len - 1);
1794 else
1795 cur->name = xmlStrndup(name, len);
1796 } else
1797 cur->name = xmlStrdup(name);
1798 return(cur);
1799}
1800
1801/**
1802 * xmlNewReference:
1803 * @doc: the document
1804 * @name: the reference name, or the reference string with & and ;
1805 *
1806 * Creation of a new reference node.
1807 * Returns a pointer to the new node object.
1808 */
1809xmlNodePtr
1810xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
1811 xmlNodePtr cur;
1812 xmlEntityPtr ent;
1813
1814 /*
1815 * Allocate a new node and fill the fields.
1816 */
1817 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1818 if (cur == NULL) {
1819 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001820 "xmlNewReference : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001821 return(NULL);
1822 }
1823 memset(cur, 0, sizeof(xmlNode));
1824 cur->type = XML_ENTITY_REF_NODE;
1825
1826 cur->doc = doc;
1827 if (name[0] == '&') {
1828 int len;
1829 name++;
1830 len = xmlStrlen(name);
1831 if (name[len - 1] == ';')
1832 cur->name = xmlStrndup(name, len - 1);
1833 else
1834 cur->name = xmlStrndup(name, len);
1835 } else
1836 cur->name = xmlStrdup(name);
1837
1838 ent = xmlGetDocEntity(doc, cur->name);
1839 if (ent != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001840 cur->content = ent->content;
Owen Taylor3473f882001-02-23 17:55:21 +00001841 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001842 * The parent pointer in entity is a DTD pointer and thus is NOT
Owen Taylor3473f882001-02-23 17:55:21 +00001843 * updated. Not sure if this is 100% correct.
1844 * -George
1845 */
1846 cur->children = (xmlNodePtr) ent;
1847 cur->last = (xmlNodePtr) ent;
1848 }
1849 return(cur);
1850}
1851
1852/**
1853 * xmlNewDocText:
1854 * @doc: the document
1855 * @content: the text content
1856 *
1857 * Creation of a new text node within a document.
1858 * Returns a pointer to the new node object.
1859 */
1860xmlNodePtr
1861xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
1862 xmlNodePtr cur;
1863
1864 cur = xmlNewText(content);
1865 if (cur != NULL) cur->doc = doc;
1866 return(cur);
1867}
1868
1869/**
1870 * xmlNewTextLen:
1871 * @content: the text content
1872 * @len: the text len.
1873 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001874 * Creation of a new text node with an extra parameter for the content's length
Owen Taylor3473f882001-02-23 17:55:21 +00001875 * Returns a pointer to the new node object.
1876 */
1877xmlNodePtr
1878xmlNewTextLen(const xmlChar *content, int len) {
1879 xmlNodePtr cur;
1880
1881 /*
1882 * Allocate a new node and fill the fields.
1883 */
1884 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1885 if (cur == NULL) {
1886 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00001887 "xmlNewTextLen : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001888 return(NULL);
1889 }
1890 memset(cur, 0, sizeof(xmlNode));
1891 cur->type = XML_TEXT_NODE;
1892
1893 cur->name = xmlStringText;
1894 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001895 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001896 }
1897 return(cur);
1898}
1899
1900/**
1901 * xmlNewDocTextLen:
1902 * @doc: the document
1903 * @content: the text content
1904 * @len: the text len.
1905 *
Daniel Veillard60087f32001-10-10 09:45:09 +00001906 * Creation of a new text node with an extra content length parameter. The
Owen Taylor3473f882001-02-23 17:55:21 +00001907 * text node pertain to a given document.
1908 * Returns a pointer to the new node object.
1909 */
1910xmlNodePtr
1911xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
1912 xmlNodePtr cur;
1913
1914 cur = xmlNewTextLen(content, len);
1915 if (cur != NULL) cur->doc = doc;
1916 return(cur);
1917}
1918
1919/**
1920 * xmlNewComment:
1921 * @content: the comment content
1922 *
1923 * Creation of a new node containing a comment.
1924 * Returns a pointer to the new node object.
1925 */
1926xmlNodePtr
1927xmlNewComment(const xmlChar *content) {
1928 xmlNodePtr cur;
1929
1930 /*
1931 * Allocate a new node and fill the fields.
1932 */
1933 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1934 if (cur == NULL) {
1935 xmlGenericError(xmlGenericErrorContext,
1936 "xmlNewComment : malloc failed\n");
1937 return(NULL);
1938 }
1939 memset(cur, 0, sizeof(xmlNode));
1940 cur->type = XML_COMMENT_NODE;
1941
1942 cur->name = xmlStringComment;
1943 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001944 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001945 }
1946 return(cur);
1947}
1948
1949/**
1950 * xmlNewCDataBlock:
1951 * @doc: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00001952 * @content: the CDATA block content content
Owen Taylor3473f882001-02-23 17:55:21 +00001953 * @len: the length of the block
1954 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001955 * Creation of a new node containing a CDATA block.
Owen Taylor3473f882001-02-23 17:55:21 +00001956 * Returns a pointer to the new node object.
1957 */
1958xmlNodePtr
1959xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
1960 xmlNodePtr cur;
1961
1962 /*
1963 * Allocate a new node and fill the fields.
1964 */
1965 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1966 if (cur == NULL) {
1967 xmlGenericError(xmlGenericErrorContext,
1968 "xmlNewCDataBlock : malloc failed\n");
1969 return(NULL);
1970 }
1971 memset(cur, 0, sizeof(xmlNode));
1972 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001973 cur->doc = doc;
Owen Taylor3473f882001-02-23 17:55:21 +00001974
1975 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001976 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00001977 }
1978 return(cur);
1979}
1980
1981/**
1982 * xmlNewDocComment:
1983 * @doc: the document
1984 * @content: the comment content
1985 *
Daniel Veillardd1640922001-12-17 15:30:10 +00001986 * Creation of a new node containing a comment within a document.
Owen Taylor3473f882001-02-23 17:55:21 +00001987 * Returns a pointer to the new node object.
1988 */
1989xmlNodePtr
1990xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
1991 xmlNodePtr cur;
1992
1993 cur = xmlNewComment(content);
1994 if (cur != NULL) cur->doc = doc;
1995 return(cur);
1996}
1997
1998/**
1999 * xmlSetTreeDoc:
2000 * @tree: the top element
2001 * @doc: the document
2002 *
2003 * update all nodes under the tree to point to the right document
2004 */
2005void
2006xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
Daniel Veillard19e96c32001-07-09 10:32:59 +00002007 xmlAttrPtr prop;
2008
Owen Taylor3473f882001-02-23 17:55:21 +00002009 if (tree == NULL)
2010 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002011 if (tree->doc != doc) {
Daniel Veillard36065812002-01-24 15:02:46 +00002012 if(tree->type == XML_ELEMENT_NODE) {
2013 prop = tree->properties;
2014 while (prop != NULL) {
2015 prop->doc = doc;
2016 xmlSetListDoc(prop->children, doc);
2017 prop = prop->next;
2018 }
Daniel Veillard19e96c32001-07-09 10:32:59 +00002019 }
Owen Taylor3473f882001-02-23 17:55:21 +00002020 if (tree->children != NULL)
2021 xmlSetListDoc(tree->children, doc);
2022 tree->doc = doc;
2023 }
2024}
2025
2026/**
2027 * xmlSetListDoc:
Daniel Veillardd1640922001-12-17 15:30:10 +00002028 * @list: the first element
Owen Taylor3473f882001-02-23 17:55:21 +00002029 * @doc: the document
2030 *
2031 * update all nodes in the list to point to the right document
2032 */
2033void
2034xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2035 xmlNodePtr cur;
2036
2037 if (list == NULL)
2038 return;
2039 cur = list;
2040 while (cur != NULL) {
2041 if (cur->doc != doc)
2042 xmlSetTreeDoc(cur, doc);
2043 cur = cur->next;
2044 }
2045}
2046
2047
2048/**
2049 * xmlNewChild:
2050 * @parent: the parent node
2051 * @ns: a namespace if any
2052 * @name: the name of the child
2053 * @content: the XML content of the child if any.
2054 *
2055 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardd1640922001-12-17 15:30:10 +00002056 * @ns and @content parameters are optional (NULL). If content is non NULL,
Owen Taylor3473f882001-02-23 17:55:21 +00002057 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2058 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2059 * references, but XML special chars need to be escaped first by using
2060 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
2061 * support is not needed.
2062 *
2063 * Returns a pointer to the new node object.
2064 */
2065xmlNodePtr
2066xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2067 const xmlChar *name, const xmlChar *content) {
2068 xmlNodePtr cur, prev;
2069
2070 if (parent == NULL) {
2071#ifdef DEBUG_TREE
2072 xmlGenericError(xmlGenericErrorContext,
2073 "xmlNewChild : parent == NULL\n");
2074#endif
2075 return(NULL);
2076 }
2077
2078 if (name == NULL) {
2079#ifdef DEBUG_TREE
2080 xmlGenericError(xmlGenericErrorContext,
2081 "xmlNewChild : name == NULL\n");
2082#endif
2083 return(NULL);
2084 }
2085
2086 /*
2087 * Allocate a new node
2088 */
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002089 if (parent->type == XML_ELEMENT_NODE) {
2090 if (ns == NULL)
2091 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2092 else
2093 cur = xmlNewDocNode(parent->doc, ns, name, content);
2094 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2095 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2096 if (ns == NULL)
2097 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2098 else
2099 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
Daniel Veillard7e3f1402002-10-28 18:52:57 +00002100 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2101 cur = xmlNewDocNode( parent->doc, ns, name, content);
Daniel Veillard36eea2d2002-02-04 00:17:01 +00002102 } else {
2103 return(NULL);
2104 }
Owen Taylor3473f882001-02-23 17:55:21 +00002105 if (cur == NULL) return(NULL);
2106
2107 /*
2108 * add the new element at the end of the children list.
2109 */
2110 cur->type = XML_ELEMENT_NODE;
2111 cur->parent = parent;
2112 cur->doc = parent->doc;
2113 if (parent->children == NULL) {
2114 parent->children = cur;
2115 parent->last = cur;
2116 } else {
2117 prev = parent->last;
2118 prev->next = cur;
2119 cur->prev = prev;
2120 parent->last = cur;
2121 }
2122
2123 return(cur);
2124}
2125
2126/**
2127 * xmlAddNextSibling:
2128 * @cur: the child node
2129 * @elem: the new node
2130 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002131 * Add a new node @elem as the next sibling of @cur
2132 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002133 * first unlinked from its existing context.
2134 * As a result of text merging @elem may be freed.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002135 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2136 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002137 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002138 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002139 */
2140xmlNodePtr
2141xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
2142 if (cur == NULL) {
2143#ifdef DEBUG_TREE
2144 xmlGenericError(xmlGenericErrorContext,
2145 "xmlAddNextSibling : cur == NULL\n");
2146#endif
2147 return(NULL);
2148 }
2149 if (elem == NULL) {
2150#ifdef DEBUG_TREE
2151 xmlGenericError(xmlGenericErrorContext,
2152 "xmlAddNextSibling : elem == NULL\n");
2153#endif
2154 return(NULL);
2155 }
2156
2157 xmlUnlinkNode(elem);
2158
2159 if (elem->type == XML_TEXT_NODE) {
2160 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002161 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002162 xmlFreeNode(elem);
2163 return(cur);
2164 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002165 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
2166 (cur->name == cur->next->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002167 xmlChar *tmp;
2168
2169 tmp = xmlStrdup(elem->content);
2170 tmp = xmlStrcat(tmp, cur->next->content);
2171 xmlNodeSetContent(cur->next, tmp);
2172 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002173 xmlFreeNode(elem);
2174 return(cur->next);
2175 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002176 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2177 /* check if an attribute with the same name exists */
2178 xmlAttrPtr attr;
2179
2180 if (elem->ns == NULL)
2181 attr = xmlHasProp(cur->parent, elem->name);
2182 else
2183 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2184 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2185 /* different instance, destroy it (attributes must be unique) */
2186 xmlFreeProp(attr);
2187 }
Owen Taylor3473f882001-02-23 17:55:21 +00002188 }
2189
2190 if (elem->doc != cur->doc) {
2191 xmlSetTreeDoc(elem, cur->doc);
2192 }
2193 elem->parent = cur->parent;
2194 elem->prev = cur;
2195 elem->next = cur->next;
2196 cur->next = elem;
2197 if (elem->next != NULL)
2198 elem->next->prev = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002199 if ((elem->parent != NULL) && (elem->parent->last == cur) && (elem->type != XML_ATTRIBUTE_NODE))
Owen Taylor3473f882001-02-23 17:55:21 +00002200 elem->parent->last = elem;
2201 return(elem);
2202}
2203
2204/**
2205 * xmlAddPrevSibling:
2206 * @cur: the child node
2207 * @elem: the new node
2208 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002209 * Add a new node @elem as the previous sibling of @cur
Owen Taylor3473f882001-02-23 17:55:21 +00002210 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002211 * If the new node was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002212 * first unlinked from its existing context.
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002213 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2214 * If there is an attribute with equal name, it is first destroyed.
Owen Taylor3473f882001-02-23 17:55:21 +00002215 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002216 * Returns the new node or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002217 */
2218xmlNodePtr
2219xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
2220 if (cur == NULL) {
2221#ifdef DEBUG_TREE
2222 xmlGenericError(xmlGenericErrorContext,
2223 "xmlAddPrevSibling : cur == NULL\n");
2224#endif
2225 return(NULL);
2226 }
2227 if (elem == NULL) {
2228#ifdef DEBUG_TREE
2229 xmlGenericError(xmlGenericErrorContext,
2230 "xmlAddPrevSibling : elem == NULL\n");
2231#endif
2232 return(NULL);
2233 }
2234
2235 xmlUnlinkNode(elem);
2236
2237 if (elem->type == XML_TEXT_NODE) {
2238 if (cur->type == XML_TEXT_NODE) {
Owen Taylor3473f882001-02-23 17:55:21 +00002239 xmlChar *tmp;
2240
2241 tmp = xmlStrdup(elem->content);
2242 tmp = xmlStrcat(tmp, cur->content);
2243 xmlNodeSetContent(cur, tmp);
2244 xmlFree(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00002245 xmlFreeNode(elem);
2246 return(cur);
2247 }
Daniel Veillard9e1c72d2001-08-31 20:03:19 +00002248 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
2249 (cur->name == cur->prev->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002250 xmlNodeAddContent(cur->prev, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002251 xmlFreeNode(elem);
2252 return(cur->prev);
2253 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002254 } else if (elem->type == XML_ATTRIBUTE_NODE) {
2255 /* check if an attribute with the same name exists */
2256 xmlAttrPtr attr;
2257
2258 if (elem->ns == NULL)
2259 attr = xmlHasProp(cur->parent, elem->name);
2260 else
2261 attr = xmlHasNsProp(cur->parent, elem->name, elem->ns->href);
2262 if ((attr != NULL) && (attr != (xmlAttrPtr) elem)) {
2263 /* different instance, destroy it (attributes must be unique) */
2264 xmlFreeProp(attr);
2265 }
Owen Taylor3473f882001-02-23 17:55:21 +00002266 }
2267
2268 if (elem->doc != cur->doc) {
2269 xmlSetTreeDoc(elem, cur->doc);
2270 }
2271 elem->parent = cur->parent;
2272 elem->next = cur;
2273 elem->prev = cur->prev;
2274 cur->prev = elem;
2275 if (elem->prev != NULL)
2276 elem->prev->next = elem;
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002277 if (elem->parent != NULL) {
2278 if (elem->type == XML_ATTRIBUTE_NODE) {
2279 if (elem->parent->properties == (xmlAttrPtr) cur) {
2280 elem->parent->properties = (xmlAttrPtr) elem;
2281 }
2282 } else {
2283 if (elem->parent->children == cur) {
2284 elem->parent->children = elem;
2285 }
2286 }
2287 }
Owen Taylor3473f882001-02-23 17:55:21 +00002288 return(elem);
2289}
2290
2291/**
2292 * xmlAddSibling:
2293 * @cur: the child node
2294 * @elem: the new node
2295 *
2296 * Add a new element @elem to the list of siblings of @cur
2297 * merging adjacent TEXT nodes (@elem may be freed)
2298 * If the new element was already inserted in a document it is
2299 * first unlinked from its existing context.
2300 *
2301 * Returns the new element or NULL in case of error.
2302 */
2303xmlNodePtr
2304xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
2305 xmlNodePtr parent;
2306
2307 if (cur == NULL) {
2308#ifdef DEBUG_TREE
2309 xmlGenericError(xmlGenericErrorContext,
2310 "xmlAddSibling : cur == NULL\n");
2311#endif
2312 return(NULL);
2313 }
2314
2315 if (elem == NULL) {
2316#ifdef DEBUG_TREE
2317 xmlGenericError(xmlGenericErrorContext,
2318 "xmlAddSibling : elem == NULL\n");
2319#endif
2320 return(NULL);
2321 }
2322
2323 /*
2324 * Constant time is we can rely on the ->parent->last to find
2325 * the last sibling.
2326 */
2327 if ((cur->parent != NULL) &&
2328 (cur->parent->children != NULL) &&
2329 (cur->parent->last != NULL) &&
2330 (cur->parent->last->next == NULL)) {
2331 cur = cur->parent->last;
2332 } else {
2333 while (cur->next != NULL) cur = cur->next;
2334 }
2335
2336 xmlUnlinkNode(elem);
2337
2338 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002339 xmlNodeAddContent(cur, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002340 xmlFreeNode(elem);
2341 return(cur);
2342 }
2343
2344 if (elem->doc != cur->doc) {
2345 xmlSetTreeDoc(elem, cur->doc);
2346 }
2347 parent = cur->parent;
2348 elem->prev = cur;
2349 elem->next = NULL;
2350 elem->parent = parent;
2351 cur->next = elem;
2352 if (parent != NULL)
2353 parent->last = elem;
2354
2355 return(elem);
2356}
2357
2358/**
2359 * xmlAddChildList:
2360 * @parent: the parent node
2361 * @cur: the first node in the list
2362 *
2363 * Add a list of node at the end of the child list of the parent
2364 * merging adjacent TEXT nodes (@cur may be freed)
2365 *
2366 * Returns the last child or NULL in case of error.
2367 */
2368xmlNodePtr
2369xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2370 xmlNodePtr prev;
2371
2372 if (parent == NULL) {
2373#ifdef DEBUG_TREE
2374 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002375 "xmlAddChildList : parent == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002376#endif
2377 return(NULL);
2378 }
2379
2380 if (cur == NULL) {
2381#ifdef DEBUG_TREE
2382 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00002383 "xmlAddChildList : child == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002384#endif
2385 return(NULL);
2386 }
2387
2388 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2389 (cur->doc != parent->doc)) {
2390#ifdef DEBUG_TREE
2391 xmlGenericError(xmlGenericErrorContext,
2392 "Elements moved to a different document\n");
2393#endif
2394 }
2395
2396 /*
2397 * add the first element at the end of the children list.
2398 */
2399 if (parent->children == NULL) {
2400 parent->children = cur;
2401 } else {
2402 /*
2403 * If cur and parent->last both are TEXT nodes, then merge them.
2404 */
2405 if ((cur->type == XML_TEXT_NODE) &&
2406 (parent->last->type == XML_TEXT_NODE) &&
2407 (cur->name == parent->last->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002408 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002409 /*
2410 * if it's the only child, nothing more to be done.
2411 */
2412 if (cur->next == NULL) {
2413 xmlFreeNode(cur);
2414 return(parent->last);
2415 }
2416 prev = cur;
2417 cur = cur->next;
2418 xmlFreeNode(prev);
2419 }
2420 prev = parent->last;
2421 prev->next = cur;
2422 cur->prev = prev;
2423 }
2424 while (cur->next != NULL) {
2425 cur->parent = parent;
2426 if (cur->doc != parent->doc) {
2427 xmlSetTreeDoc(cur, parent->doc);
2428 }
2429 cur = cur->next;
2430 }
2431 cur->parent = parent;
2432 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2433 parent->last = cur;
2434
2435 return(cur);
2436}
2437
2438/**
2439 * xmlAddChild:
2440 * @parent: the parent node
2441 * @cur: the child node
2442 *
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002443 * Add a new node to @parent, at the end of the child (or property) list
Owen Taylor3473f882001-02-23 17:55:21 +00002444 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002445 * If the new node was already inserted in a document it is
2446 * first unlinked from its existing context.
2447 * If the new node is ATTRIBUTE, it is added into properties instead of children.
2448 * If there is an attribute with equal name, it is first destroyed.
2449 *
Owen Taylor3473f882001-02-23 17:55:21 +00002450 * Returns the child or NULL in case of error.
2451 */
2452xmlNodePtr
2453xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
2454 xmlNodePtr prev;
2455
2456 if (parent == NULL) {
2457#ifdef DEBUG_TREE
2458 xmlGenericError(xmlGenericErrorContext,
2459 "xmlAddChild : parent == NULL\n");
2460#endif
2461 return(NULL);
2462 }
2463
2464 if (cur == NULL) {
2465#ifdef DEBUG_TREE
2466 xmlGenericError(xmlGenericErrorContext,
2467 "xmlAddChild : child == NULL\n");
2468#endif
2469 return(NULL);
2470 }
2471
Owen Taylor3473f882001-02-23 17:55:21 +00002472 /*
2473 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
Owen Taylor3473f882001-02-23 17:55:21 +00002474 * cur is then freed.
2475 */
2476 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002477 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002478 (parent->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002479 xmlNodeAddContent(parent, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002480 xmlFreeNode(cur);
2481 return(parent);
2482 }
2483 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2484 (parent->last->name == cur->name)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002485 xmlNodeAddContent(parent->last, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00002486 xmlFreeNode(cur);
2487 return(parent->last);
2488 }
2489 }
2490
2491 /*
2492 * add the new element at the end of the children list.
2493 */
2494 cur->parent = parent;
2495 if (cur->doc != parent->doc) {
2496 xmlSetTreeDoc(cur, parent->doc);
2497 }
2498
2499 /*
Daniel Veillard7db37732001-07-12 01:20:08 +00002500 * Coalescing
Owen Taylor3473f882001-02-23 17:55:21 +00002501 */
Daniel Veillard7db37732001-07-12 01:20:08 +00002502 if ((parent->type == XML_TEXT_NODE) &&
Owen Taylor3473f882001-02-23 17:55:21 +00002503 (parent->content != NULL)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002504 xmlNodeAddContent(parent, cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002505 xmlFreeNode(cur);
2506 return(parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002507 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002508 if (cur->type == XML_ATTRIBUTE_NODE) {
2509 if (parent->properties == NULL) {
2510 parent->properties = (xmlAttrPtr) cur;
2511 } else {
2512 /* check if an attribute with the same name exists */
2513 xmlAttrPtr lastattr;
Owen Taylor3473f882001-02-23 17:55:21 +00002514
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002515 if (cur->ns == NULL)
2516 lastattr = xmlHasProp(parent, cur->name);
2517 else
2518 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
2519 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur)) {
2520 /* different instance, destroy it (attributes must be unique) */
2521 xmlFreeProp(lastattr);
2522 }
2523 /* find the end */
2524 lastattr = parent->properties;
2525 while (lastattr->next != NULL) {
2526 lastattr = lastattr->next;
2527 }
2528 lastattr->next = (xmlAttrPtr) cur;
2529 ((xmlAttrPtr) cur)->prev = lastattr;
2530 }
2531 } else {
2532 if (parent->children == NULL) {
2533 parent->children = cur;
2534 parent->last = cur;
2535 } else {
2536 prev = parent->last;
2537 prev->next = cur;
2538 cur->prev = prev;
2539 parent->last = cur;
2540 }
2541 }
Owen Taylor3473f882001-02-23 17:55:21 +00002542 return(cur);
2543}
2544
2545/**
2546 * xmlGetLastChild:
2547 * @parent: the parent node
2548 *
2549 * Search the last child of a node.
2550 * Returns the last child or NULL if none.
2551 */
2552xmlNodePtr
2553xmlGetLastChild(xmlNodePtr parent) {
2554 if (parent == NULL) {
2555#ifdef DEBUG_TREE
2556 xmlGenericError(xmlGenericErrorContext,
2557 "xmlGetLastChild : parent == NULL\n");
2558#endif
2559 return(NULL);
2560 }
2561 return(parent->last);
2562}
2563
2564/**
2565 * xmlFreeNodeList:
2566 * @cur: the first node in the list
2567 *
2568 * Free a node and all its siblings, this is a recursive behaviour, all
2569 * the children are freed too.
2570 */
2571void
2572xmlFreeNodeList(xmlNodePtr cur) {
2573 xmlNodePtr next;
2574 if (cur == NULL) {
2575#ifdef DEBUG_TREE
2576 xmlGenericError(xmlGenericErrorContext,
2577 "xmlFreeNodeList : node == NULL\n");
2578#endif
2579 return;
2580 }
Daniel Veillarde6a55192002-01-14 17:11:53 +00002581 if (cur->type == XML_NAMESPACE_DECL) {
2582 xmlFreeNsList((xmlNsPtr) cur);
2583 return;
2584 }
Owen Taylor3473f882001-02-23 17:55:21 +00002585 while (cur != NULL) {
2586 next = cur->next;
Daniel Veillard02141ea2001-04-30 11:46:40 +00002587 /* unroll to speed up freeing the document */
2588 if (cur->type != XML_DTD_NODE) {
2589 if ((cur->children != NULL) &&
2590 (cur->type != XML_ENTITY_REF_NODE))
2591 xmlFreeNodeList(cur->children);
2592 if (cur->properties != NULL)
2593 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002594 if ((cur->type != XML_ELEMENT_NODE) &&
2595 (cur->type != XML_XINCLUDE_START) &&
2596 (cur->type != XML_XINCLUDE_END) &&
2597 (cur->type != XML_ENTITY_REF_NODE)) {
Daniel Veillard02141ea2001-04-30 11:46:40 +00002598 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002599 }
2600 if (((cur->type == XML_ELEMENT_NODE) ||
2601 (cur->type == XML_XINCLUDE_START) ||
2602 (cur->type == XML_XINCLUDE_END)) &&
2603 (cur->nsDef != NULL))
2604 xmlFreeNsList(cur->nsDef);
2605
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002606 /*
2607 * When a node is a text node or a comment, it uses a global static
2608 * variable for the name of the node.
2609 *
2610 * The xmlStrEqual comparisons need to be done when (happened with
2611 * XML::libXML and XML::libXSLT) the library is included twice
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002612 * statically in the binary and a tree allocated by one occurrence
Daniel Veillardd1640922001-12-17 15:30:10 +00002613 * of the lib gets freed by the other occurrence, in this case
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002614 * the string addresses compare are not sufficient.
2615 */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002616 if ((cur->name != NULL) &&
2617 (cur->name != xmlStringText) &&
2618 (cur->name != xmlStringTextNoenc) &&
Daniel Veillard9cc6dc62001-06-11 08:09:20 +00002619 (cur->name != xmlStringComment)) {
2620 if (cur->type == XML_TEXT_NODE) {
2621 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2622 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2623 xmlFree((char *) cur->name);
2624 } else if (cur->type == XML_COMMENT_NODE) {
2625 if (!xmlStrEqual(cur->name, xmlStringComment))
2626 xmlFree((char *) cur->name);
2627 } else
2628 xmlFree((char *) cur->name);
2629 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002630 /* TODO : derecursivate this function */
Daniel Veillard02141ea2001-04-30 11:46:40 +00002631 xmlFree(cur);
2632 }
Owen Taylor3473f882001-02-23 17:55:21 +00002633 cur = next;
2634 }
2635}
2636
2637/**
2638 * xmlFreeNode:
2639 * @cur: the node
2640 *
2641 * Free a node, this is a recursive behaviour, all the children are freed too.
2642 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
2643 */
2644void
2645xmlFreeNode(xmlNodePtr cur) {
2646 if (cur == NULL) {
2647#ifdef DEBUG_TREE
2648 xmlGenericError(xmlGenericErrorContext,
2649 "xmlFreeNode : node == NULL\n");
2650#endif
2651 return;
2652 }
Daniel Veillard02141ea2001-04-30 11:46:40 +00002653 /* use xmlFreeDtd for DTD nodes */
Daniel Veillarde6a55192002-01-14 17:11:53 +00002654 if (cur->type == XML_DTD_NODE) {
2655 xmlFreeDtd((xmlDtdPtr) cur);
Owen Taylor3473f882001-02-23 17:55:21 +00002656 return;
Daniel Veillarde6a55192002-01-14 17:11:53 +00002657 }
2658 if (cur->type == XML_NAMESPACE_DECL) {
2659 xmlFreeNs((xmlNsPtr) cur);
2660 return;
2661 }
Daniel Veillarda70d62f2002-11-07 14:18:03 +00002662 if (cur->type == XML_ATTRIBUTE_NODE) {
2663 xmlFreeProp((xmlAttrPtr) cur);
2664 return;
2665 }
Owen Taylor3473f882001-02-23 17:55:21 +00002666 if ((cur->children != NULL) &&
2667 (cur->type != XML_ENTITY_REF_NODE))
2668 xmlFreeNodeList(cur->children);
Daniel Veillard02141ea2001-04-30 11:46:40 +00002669 if (cur->properties != NULL)
2670 xmlFreePropList(cur->properties);
Daniel Veillard7db37732001-07-12 01:20:08 +00002671 if ((cur->type != XML_ELEMENT_NODE) &&
2672 (cur->content != NULL) &&
2673 (cur->type != XML_ENTITY_REF_NODE) &&
2674 (cur->type != XML_XINCLUDE_END) &&
2675 (cur->type != XML_XINCLUDE_START)) {
Daniel Veillard7db37732001-07-12 01:20:08 +00002676 xmlFree(cur->content);
Daniel Veillard7db37732001-07-12 01:20:08 +00002677 }
2678
Daniel Veillardacd370f2001-06-09 17:17:51 +00002679 /*
2680 * When a node is a text node or a comment, it uses a global static
2681 * variable for the name of the node.
2682 *
2683 * The xmlStrEqual comparisons need to be done when (happened with
2684 * XML::libXML and XML::libXSLT) the library is included twice statically
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002685 * in the binary and a tree allocated by one occurence of the lib gets
Daniel Veillardd1640922001-12-17 15:30:10 +00002686 * freed by the other occurrence, in this case the string addresses compare
Daniel Veillardacd370f2001-06-09 17:17:51 +00002687 * are not sufficient.
2688 */
Owen Taylor3473f882001-02-23 17:55:21 +00002689 if ((cur->name != NULL) &&
2690 (cur->name != xmlStringText) &&
2691 (cur->name != xmlStringTextNoenc) &&
Daniel Veillardacd370f2001-06-09 17:17:51 +00002692 (cur->name != xmlStringComment)) {
2693 if (cur->type == XML_TEXT_NODE) {
2694 if ((!xmlStrEqual(cur->name, xmlStringText)) &&
2695 (!xmlStrEqual(cur->name, xmlStringTextNoenc)))
2696 xmlFree((char *) cur->name);
2697 } else if (cur->type == XML_COMMENT_NODE) {
2698 if (!xmlStrEqual(cur->name, xmlStringComment))
2699 xmlFree((char *) cur->name);
2700 } else
2701 xmlFree((char *) cur->name);
2702 }
2703
Owen Taylor3473f882001-02-23 17:55:21 +00002704 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
Owen Taylor3473f882001-02-23 17:55:21 +00002705 xmlFree(cur);
2706}
2707
2708/**
2709 * xmlUnlinkNode:
2710 * @cur: the node
2711 *
2712 * Unlink a node from it's current context, the node is not freed
2713 */
2714void
2715xmlUnlinkNode(xmlNodePtr cur) {
2716 if (cur == NULL) {
2717#ifdef DEBUG_TREE
2718 xmlGenericError(xmlGenericErrorContext,
2719 "xmlUnlinkNode : node == NULL\n");
2720#endif
2721 return;
2722 }
Daniel Veillard29e43992001-12-13 22:21:58 +00002723 if (cur->type == XML_DTD_NODE) {
2724 xmlDocPtr doc;
2725 doc = cur->doc;
2726 if (doc->intSubset == (xmlDtdPtr) cur)
2727 doc->intSubset = NULL;
2728 if (doc->extSubset == (xmlDtdPtr) cur)
2729 doc->extSubset = NULL;
2730 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002731 if (cur->parent != NULL) {
2732 xmlNodePtr parent;
2733 parent = cur->parent;
2734 if (cur->type == XML_ATTRIBUTE_NODE) {
2735 if (parent->properties == (xmlAttrPtr) cur)
2736 parent->properties = ((xmlAttrPtr) cur)->next;
2737 } else {
2738 if (parent->children == cur)
2739 parent->children = cur->next;
2740 if (parent->last == cur)
2741 parent->last = cur->prev;
2742 }
2743 cur->parent = NULL;
2744 }
Owen Taylor3473f882001-02-23 17:55:21 +00002745 if (cur->next != NULL)
2746 cur->next->prev = cur->prev;
2747 if (cur->prev != NULL)
2748 cur->prev->next = cur->next;
2749 cur->next = cur->prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002750}
2751
2752/**
2753 * xmlReplaceNode:
2754 * @old: the old node
2755 * @cur: the node
2756 *
2757 * Unlink the old node from it's current context, prune the new one
Daniel Veillardd1640922001-12-17 15:30:10 +00002758 * at the same place. If @cur was already inserted in a document it is
Owen Taylor3473f882001-02-23 17:55:21 +00002759 * first unlinked from its existing context.
2760 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002761 * Returns the @old node
Owen Taylor3473f882001-02-23 17:55:21 +00002762 */
2763xmlNodePtr
2764xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2765 if (old == NULL) {
2766#ifdef DEBUG_TREE
2767 xmlGenericError(xmlGenericErrorContext,
2768 "xmlReplaceNode : old == NULL\n");
2769#endif
2770 return(NULL);
2771 }
2772 if (cur == NULL) {
2773 xmlUnlinkNode(old);
2774 return(old);
2775 }
2776 if (cur == old) {
2777 return(old);
2778 }
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002779 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2780#ifdef DEBUG_TREE
2781 xmlGenericError(xmlGenericErrorContext,
2782 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2783#endif
2784 return(old);
2785 }
2786 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2787#ifdef DEBUG_TREE
2788 xmlGenericError(xmlGenericErrorContext,
2789 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2790#endif
2791 return(old);
2792 }
Daniel Veillardbd227ae2002-01-24 16:05:41 +00002793 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
2794#ifdef DEBUG_TREE
2795 xmlGenericError(xmlGenericErrorContext,
2796 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
2797#endif
2798 return(old);
2799 }
2800 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
2801#ifdef DEBUG_TREE
2802 xmlGenericError(xmlGenericErrorContext,
2803 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
2804#endif
2805 return(old);
2806 }
Owen Taylor3473f882001-02-23 17:55:21 +00002807 xmlUnlinkNode(cur);
2808 cur->doc = old->doc;
2809 cur->parent = old->parent;
2810 cur->next = old->next;
2811 if (cur->next != NULL)
2812 cur->next->prev = cur;
2813 cur->prev = old->prev;
2814 if (cur->prev != NULL)
2815 cur->prev->next = cur;
2816 if (cur->parent != NULL) {
Daniel Veillardc169f8b2002-01-22 21:40:13 +00002817 if (cur->type == XML_ATTRIBUTE_NODE) {
2818 if (cur->parent->properties == (xmlAttrPtr)old)
2819 cur->parent->properties = ((xmlAttrPtr) cur);
2820 } else {
2821 if (cur->parent->children == old)
2822 cur->parent->children = cur;
2823 if (cur->parent->last == old)
2824 cur->parent->last = cur;
2825 }
Owen Taylor3473f882001-02-23 17:55:21 +00002826 }
2827 old->next = old->prev = NULL;
2828 old->parent = NULL;
2829 return(old);
2830}
2831
2832/************************************************************************
2833 * *
2834 * Copy operations *
2835 * *
2836 ************************************************************************/
2837
2838/**
2839 * xmlCopyNamespace:
2840 * @cur: the namespace
2841 *
2842 * Do a copy of the namespace.
2843 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002844 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002845 */
2846xmlNsPtr
2847xmlCopyNamespace(xmlNsPtr cur) {
2848 xmlNsPtr ret;
2849
2850 if (cur == NULL) return(NULL);
2851 switch (cur->type) {
2852 case XML_LOCAL_NAMESPACE:
2853 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2854 break;
2855 default:
2856#ifdef DEBUG_TREE
2857 xmlGenericError(xmlGenericErrorContext,
2858 "xmlCopyNamespace: invalid type %d\n", cur->type);
2859#endif
2860 return(NULL);
2861 }
2862 return(ret);
2863}
2864
2865/**
2866 * xmlCopyNamespaceList:
2867 * @cur: the first namespace
2868 *
2869 * Do a copy of an namespace list.
2870 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002871 * Returns: a new #xmlNsPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002872 */
2873xmlNsPtr
2874xmlCopyNamespaceList(xmlNsPtr cur) {
2875 xmlNsPtr ret = NULL;
2876 xmlNsPtr p = NULL,q;
2877
2878 while (cur != NULL) {
2879 q = xmlCopyNamespace(cur);
2880 if (p == NULL) {
2881 ret = p = q;
2882 } else {
2883 p->next = q;
2884 p = q;
2885 }
2886 cur = cur->next;
2887 }
2888 return(ret);
2889}
2890
2891static xmlNodePtr
2892xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2893/**
2894 * xmlCopyProp:
2895 * @target: the element where the attribute will be grafted
2896 * @cur: the attribute
2897 *
2898 * Do a copy of the attribute.
2899 *
Daniel Veillardd1640922001-12-17 15:30:10 +00002900 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002901 */
2902xmlAttrPtr
2903xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
2904 xmlAttrPtr ret;
2905
2906 if (cur == NULL) return(NULL);
2907 if (target != NULL)
2908 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2909 else if (cur->parent != NULL)
2910 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2911 else if (cur->children != NULL)
2912 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
2913 else
2914 ret = xmlNewDocProp(NULL, cur->name, NULL);
2915 if (ret == NULL) return(NULL);
2916 ret->parent = target;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002917
Owen Taylor3473f882001-02-23 17:55:21 +00002918 if ((cur->ns != NULL) && (target != NULL)) {
Daniel Veillard8107a222002-01-13 14:10:10 +00002919 xmlNsPtr ns;
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002920/*
2921 * if (target->doc)
2922 * ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2923 * else if (cur->doc) / * target may not yet have a doc : KPI * /
2924 * ns = xmlSearchNs(cur->doc, target, cur->ns->prefix);
2925 * else
2926 * ns = NULL;
2927 * ret->ns = ns;
2928 */
2929 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2930 if (ns == NULL) {
2931 /*
2932 * Humm, we are copying an element whose namespace is defined
2933 * out of the new tree scope. Search it in the original tree
2934 * and add it at the top of the new tree
2935 */
2936 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
2937 if (ns != NULL) {
2938 xmlNodePtr root = target;
2939 xmlNodePtr pred = NULL;
2940
2941 while (root->parent != NULL) {
2942 pred = root;
2943 root = root->parent;
2944 }
2945 if (root == (xmlNodePtr) target->doc) {
2946 /* correct possibly cycling above the document elt */
2947 root = pred;
2948 }
2949 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
2950 }
2951 } else {
2952 /*
2953 * we have to find something appropriate here since
2954 * we cant be sure, that the namespce we found is identified
2955 * by the prefix
2956 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002957 if (xmlStrEqual(ns->href, cur->ns->href)) {
Daniel Veillardd4f41aa2002-03-03 14:13:46 +00002958 /* this is the nice case */
2959 ret->ns = ns;
2960 } else {
2961 /*
2962 * we are in trouble: we need a new reconcilied namespace.
2963 * This is expensive
2964 */
2965 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns);
2966 }
2967 }
2968
Owen Taylor3473f882001-02-23 17:55:21 +00002969 } else
2970 ret->ns = NULL;
2971
2972 if (cur->children != NULL) {
2973 xmlNodePtr tmp;
2974
2975 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
2976 ret->last = NULL;
2977 tmp = ret->children;
2978 while (tmp != NULL) {
2979 /* tmp->parent = (xmlNodePtr)ret; */
2980 if (tmp->next == NULL)
2981 ret->last = tmp;
2982 tmp = tmp->next;
2983 }
2984 }
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002985 /*
2986 * Try to handle IDs
2987 */
Daniel Veillarda3db2e32002-03-08 15:46:57 +00002988 if ((target!= NULL) && (cur!= NULL) &&
2989 (target->doc != NULL) && (cur->doc != NULL) &&
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002990 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
2991 if (xmlIsID(cur->doc, cur->parent, cur)) {
2992 xmlChar *id;
2993
2994 id = xmlNodeListGetString(cur->doc, cur->children, 1);
2995 if (id != NULL) {
2996 xmlAddID(NULL, target->doc, id, ret);
2997 xmlFree(id);
2998 }
2999 }
3000 }
Owen Taylor3473f882001-02-23 17:55:21 +00003001 return(ret);
3002}
3003
3004/**
3005 * xmlCopyPropList:
3006 * @target: the element where the attributes will be grafted
3007 * @cur: the first attribute
3008 *
3009 * Do a copy of an attribute list.
3010 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003011 * Returns: a new #xmlAttrPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003012 */
3013xmlAttrPtr
3014xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
3015 xmlAttrPtr ret = NULL;
3016 xmlAttrPtr p = NULL,q;
3017
3018 while (cur != NULL) {
3019 q = xmlCopyProp(target, cur);
3020 if (p == NULL) {
3021 ret = p = q;
3022 } else {
3023 p->next = q;
3024 q->prev = p;
3025 p = q;
3026 }
3027 cur = cur->next;
3028 }
3029 return(ret);
3030}
3031
3032/*
Daniel Veillardd1640922001-12-17 15:30:10 +00003033 * NOTE about the CopyNode operations !
Owen Taylor3473f882001-02-23 17:55:21 +00003034 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003035 * They are split into external and internal parts for one
Owen Taylor3473f882001-02-23 17:55:21 +00003036 * tricky reason: namespaces. Doing a direct copy of a node
3037 * say RPM:Copyright without changing the namespace pointer to
3038 * something else can produce stale links. One way to do it is
3039 * to keep a reference counter but this doesn't work as soon
3040 * as one move the element or the subtree out of the scope of
3041 * the existing namespace. The actual solution seems to add
3042 * a copy of the namespace at the top of the copied tree if
3043 * not available in the subtree.
3044 * Hence two functions, the public front-end call the inner ones
3045 */
3046
3047static xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003048xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
Owen Taylor3473f882001-02-23 17:55:21 +00003049 int recursive) {
3050 xmlNodePtr ret;
3051
3052 if (node == NULL) return(NULL);
Daniel Veillard39196eb2001-06-19 18:09:42 +00003053 switch (node->type) {
3054 case XML_TEXT_NODE:
3055 case XML_CDATA_SECTION_NODE:
3056 case XML_ELEMENT_NODE:
Daniel Veillardec6725e2002-09-05 11:12:45 +00003057 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003058 case XML_ENTITY_REF_NODE:
3059 case XML_ENTITY_NODE:
3060 case XML_PI_NODE:
3061 case XML_COMMENT_NODE:
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003062 case XML_XINCLUDE_START:
3063 case XML_XINCLUDE_END:
3064 break;
3065 case XML_ATTRIBUTE_NODE:
3066 return((xmlNodePtr) xmlCopyProp(parent, (xmlAttrPtr) node));
3067 case XML_NAMESPACE_DECL:
3068 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
3069
Daniel Veillard39196eb2001-06-19 18:09:42 +00003070 case XML_DOCUMENT_NODE:
3071 case XML_HTML_DOCUMENT_NODE:
3072#ifdef LIBXML_DOCB_ENABLED
3073 case XML_DOCB_DOCUMENT_NODE:
3074#endif
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003075 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, recursive));
Daniel Veillard39196eb2001-06-19 18:09:42 +00003076 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard39196eb2001-06-19 18:09:42 +00003077 case XML_NOTATION_NODE:
3078 case XML_DTD_NODE:
3079 case XML_ELEMENT_DECL:
3080 case XML_ATTRIBUTE_DECL:
3081 case XML_ENTITY_DECL:
3082 return(NULL);
3083 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003084
Owen Taylor3473f882001-02-23 17:55:21 +00003085 /*
3086 * Allocate a new node and fill the fields.
3087 */
3088 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
3089 if (ret == NULL) {
3090 xmlGenericError(xmlGenericErrorContext,
3091 "xmlStaticCopyNode : malloc failed\n");
3092 return(NULL);
3093 }
3094 memset(ret, 0, sizeof(xmlNode));
3095 ret->type = node->type;
3096
3097 ret->doc = doc;
3098 ret->parent = parent;
3099 if (node->name == xmlStringText)
3100 ret->name = xmlStringText;
3101 else if (node->name == xmlStringTextNoenc)
3102 ret->name = xmlStringTextNoenc;
3103 else if (node->name == xmlStringComment)
3104 ret->name = xmlStringComment;
3105 else if (node->name != NULL)
3106 ret->name = xmlStrdup(node->name);
Daniel Veillard7db37732001-07-12 01:20:08 +00003107 if ((node->type != XML_ELEMENT_NODE) &&
3108 (node->content != NULL) &&
3109 (node->type != XML_ENTITY_REF_NODE) &&
3110 (node->type != XML_XINCLUDE_END) &&
3111 (node->type != XML_XINCLUDE_START)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003112 ret->content = xmlStrdup(node->content);
Daniel Veillard8107a222002-01-13 14:10:10 +00003113 }else{
3114 if (node->type == XML_ELEMENT_NODE)
3115 ret->content = (void*)(long) node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00003116 }
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003117 if (parent != NULL) {
3118 xmlNodePtr tmp;
3119
3120 tmp = xmlAddChild(parent, ret);
3121 /* node could have coalesced */
3122 if (tmp != ret)
3123 return(tmp);
3124 }
Owen Taylor3473f882001-02-23 17:55:21 +00003125
3126 if (!recursive) return(ret);
3127 if (node->nsDef != NULL)
3128 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
3129
3130 if (node->ns != NULL) {
3131 xmlNsPtr ns;
3132
3133 ns = xmlSearchNs(doc, ret, node->ns->prefix);
3134 if (ns == NULL) {
3135 /*
3136 * Humm, we are copying an element whose namespace is defined
3137 * out of the new tree scope. Search it in the original tree
3138 * and add it at the top of the new tree
3139 */
3140 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
3141 if (ns != NULL) {
3142 xmlNodePtr root = ret;
3143
3144 while (root->parent != NULL) root = root->parent;
Daniel Veillarde82a9922001-04-22 12:12:58 +00003145 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00003146 }
3147 } else {
3148 /*
3149 * reference the existing namespace definition in our own tree.
3150 */
3151 ret->ns = ns;
3152 }
3153 }
3154 if (node->properties != NULL)
3155 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003156 if (node->type == XML_ENTITY_REF_NODE) {
3157 if ((doc == NULL) || (node->doc != doc)) {
3158 /*
3159 * The copied node will go into a separate document, so
Daniel Veillardd1640922001-12-17 15:30:10 +00003160 * to avoid dangling references to the ENTITY_DECL node
Daniel Veillardb33c2012001-04-25 12:59:04 +00003161 * we cannot keep the reference. Try to find it in the
3162 * target document.
3163 */
3164 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
3165 } else {
3166 ret->children = node->children;
3167 }
Daniel Veillard0ec98632001-11-14 15:04:32 +00003168 ret->last = ret->children;
3169 } else if (node->children != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003170 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard0ec98632001-11-14 15:04:32 +00003171 UPDATE_LAST_CHILD_AND_PARENT(ret)
3172 }
Owen Taylor3473f882001-02-23 17:55:21 +00003173 return(ret);
3174}
3175
3176static xmlNodePtr
3177xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
3178 xmlNodePtr ret = NULL;
3179 xmlNodePtr p = NULL,q;
3180
3181 while (node != NULL) {
Daniel Veillard1d0bfab2001-07-26 11:49:41 +00003182 if (node->type == XML_DTD_NODE ) {
Daniel Veillard4497e692001-06-09 14:19:02 +00003183 if (doc == NULL) {
3184 node = node->next;
3185 continue;
3186 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003187 if (doc->intSubset == NULL) {
3188 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
3189 q->doc = doc;
3190 q->parent = parent;
3191 doc->intSubset = (xmlDtdPtr) q;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003192 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003193 } else {
3194 q = (xmlNodePtr) doc->intSubset;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003195 xmlAddChild(parent, q);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003196 }
3197 } else
3198 q = xmlStaticCopyNode(node, doc, parent, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003199 if (ret == NULL) {
3200 q->prev = NULL;
3201 ret = p = q;
Daniel Veillardacb2bda2002-01-13 16:15:43 +00003202 } else if (p != q) {
3203 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
Owen Taylor3473f882001-02-23 17:55:21 +00003204 p->next = q;
3205 q->prev = p;
3206 p = q;
3207 }
3208 node = node->next;
3209 }
3210 return(ret);
3211}
3212
3213/**
3214 * xmlCopyNode:
3215 * @node: the node
3216 * @recursive: if 1 do a recursive copy.
3217 *
3218 * Do a copy of the node.
3219 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003220 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003221 */
3222xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003223xmlCopyNode(const xmlNodePtr node, int recursive) {
Owen Taylor3473f882001-02-23 17:55:21 +00003224 xmlNodePtr ret;
3225
3226 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
3227 return(ret);
3228}
3229
3230/**
Daniel Veillard82daa812001-04-12 08:55:36 +00003231 * xmlDocCopyNode:
3232 * @node: the node
Daniel Veillardd1640922001-12-17 15:30:10 +00003233 * @doc: the document
Daniel Veillard82daa812001-04-12 08:55:36 +00003234 * @recursive: if 1 do a recursive copy.
3235 *
3236 * Do a copy of the node to a given document.
3237 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003238 * Returns: a new #xmlNodePtr, or NULL in case of error.
Daniel Veillard82daa812001-04-12 08:55:36 +00003239 */
3240xmlNodePtr
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003241xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int recursive) {
Daniel Veillard82daa812001-04-12 08:55:36 +00003242 xmlNodePtr ret;
3243
3244 ret = xmlStaticCopyNode(node, doc, NULL, recursive);
3245 return(ret);
3246}
3247
3248/**
Owen Taylor3473f882001-02-23 17:55:21 +00003249 * xmlCopyNodeList:
3250 * @node: the first node in the list.
3251 *
3252 * Do a recursive copy of the node list.
3253 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003254 * Returns: a new #xmlNodePtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003255 */
Daniel Veillard3ec4c612001-08-28 20:39:49 +00003256xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) {
Owen Taylor3473f882001-02-23 17:55:21 +00003257 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
3258 return(ret);
3259}
3260
3261/**
Owen Taylor3473f882001-02-23 17:55:21 +00003262 * xmlCopyDtd:
3263 * @dtd: the dtd
3264 *
3265 * Do a copy of the dtd.
3266 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003267 * Returns: a new #xmlDtdPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003268 */
3269xmlDtdPtr
3270xmlCopyDtd(xmlDtdPtr dtd) {
3271 xmlDtdPtr ret;
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003272 xmlNodePtr cur, p = NULL, q;
Owen Taylor3473f882001-02-23 17:55:21 +00003273
3274 if (dtd == NULL) return(NULL);
3275 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
3276 if (ret == NULL) return(NULL);
3277 if (dtd->entities != NULL)
3278 ret->entities = (void *) xmlCopyEntitiesTable(
3279 (xmlEntitiesTablePtr) dtd->entities);
3280 if (dtd->notations != NULL)
3281 ret->notations = (void *) xmlCopyNotationTable(
3282 (xmlNotationTablePtr) dtd->notations);
3283 if (dtd->elements != NULL)
3284 ret->elements = (void *) xmlCopyElementTable(
3285 (xmlElementTablePtr) dtd->elements);
3286 if (dtd->attributes != NULL)
3287 ret->attributes = (void *) xmlCopyAttributeTable(
3288 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003289 if (dtd->pentities != NULL)
3290 ret->pentities = (void *) xmlCopyEntitiesTable(
3291 (xmlEntitiesTablePtr) dtd->pentities);
3292
3293 cur = dtd->children;
3294 while (cur != NULL) {
3295 q = NULL;
3296
3297 if (cur->type == XML_ENTITY_DECL) {
3298 xmlEntityPtr tmp = (xmlEntityPtr) cur;
3299 switch (tmp->etype) {
3300 case XML_INTERNAL_GENERAL_ENTITY:
3301 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
3302 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3303 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
3304 break;
3305 case XML_INTERNAL_PARAMETER_ENTITY:
3306 case XML_EXTERNAL_PARAMETER_ENTITY:
3307 q = (xmlNodePtr)
3308 xmlGetParameterEntityFromDtd(ret, tmp->name);
3309 break;
3310 case XML_INTERNAL_PREDEFINED_ENTITY:
3311 break;
3312 }
3313 } else if (cur->type == XML_ELEMENT_DECL) {
3314 xmlElementPtr tmp = (xmlElementPtr) cur;
3315 q = (xmlNodePtr)
3316 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
3317 } else if (cur->type == XML_ATTRIBUTE_DECL) {
3318 xmlAttributePtr tmp = (xmlAttributePtr) cur;
3319 q = (xmlNodePtr)
3320 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
3321 } else if (cur->type == XML_COMMENT_NODE) {
3322 q = xmlCopyNode(cur, 0);
3323 }
3324
3325 if (q == NULL) {
3326 cur = cur->next;
3327 continue;
3328 }
3329
3330 if (p == NULL)
3331 ret->children = q;
3332 else
3333 p->next = q;
3334
3335 q->prev = p;
3336 q->parent = (xmlNodePtr) ret;
3337 q->next = NULL;
3338 ret->last = q;
3339 p = q;
3340 cur = cur->next;
3341 }
3342
Owen Taylor3473f882001-02-23 17:55:21 +00003343 return(ret);
3344}
3345
3346/**
3347 * xmlCopyDoc:
3348 * @doc: the document
3349 * @recursive: if 1 do a recursive copy.
3350 *
3351 * Do a copy of the document info. If recursive, the content tree will
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003352 * be copied too as well as DTD, namespaces and entities.
Owen Taylor3473f882001-02-23 17:55:21 +00003353 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003354 * Returns: a new #xmlDocPtr, or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003355 */
3356xmlDocPtr
3357xmlCopyDoc(xmlDocPtr doc, int recursive) {
3358 xmlDocPtr ret;
3359
3360 if (doc == NULL) return(NULL);
3361 ret = xmlNewDoc(doc->version);
3362 if (ret == NULL) return(NULL);
3363 if (doc->name != NULL)
3364 ret->name = xmlMemStrdup(doc->name);
3365 if (doc->encoding != NULL)
3366 ret->encoding = xmlStrdup(doc->encoding);
3367 ret->charset = doc->charset;
3368 ret->compression = doc->compression;
3369 ret->standalone = doc->standalone;
3370 if (!recursive) return(ret);
3371
Daniel Veillardb33c2012001-04-25 12:59:04 +00003372 ret->last = NULL;
3373 ret->children = NULL;
3374 if (doc->intSubset != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003375 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillard8ee9c8f2002-01-26 21:42:58 +00003376 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
Daniel Veillardb33c2012001-04-25 12:59:04 +00003377 ret->intSubset->parent = ret;
3378 }
Owen Taylor3473f882001-02-23 17:55:21 +00003379 if (doc->oldNs != NULL)
3380 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
3381 if (doc->children != NULL) {
3382 xmlNodePtr tmp;
Daniel Veillardb33c2012001-04-25 12:59:04 +00003383
3384 ret->children = xmlStaticCopyNodeList(doc->children, ret,
3385 (xmlNodePtr)ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003386 ret->last = NULL;
3387 tmp = ret->children;
3388 while (tmp != NULL) {
3389 if (tmp->next == NULL)
3390 ret->last = tmp;
3391 tmp = tmp->next;
3392 }
3393 }
3394 return(ret);
3395}
3396
3397/************************************************************************
3398 * *
3399 * Content access functions *
3400 * *
3401 ************************************************************************/
3402
3403/**
Daniel Veillard8faa7832001-11-26 15:58:08 +00003404 * xmlGetLineNo:
3405 * @node : valid node
3406 *
3407 * Get line number of node. this requires activation of this option
Daniel Veillardd1640922001-12-17 15:30:10 +00003408 * before invoking the parser by calling xmlLineNumbersDefault(1)
Daniel Veillard8faa7832001-11-26 15:58:08 +00003409 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003410 * Returns the line number if successful, -1 otherwise
Daniel Veillard8faa7832001-11-26 15:58:08 +00003411 */
3412long
3413xmlGetLineNo(xmlNodePtr node)
3414{
3415 long result = -1;
3416
3417 if (!node)
3418 return result;
3419 if (node->type == XML_ELEMENT_NODE)
3420 result = (long) node->content;
3421 else if ((node->prev != NULL) &&
3422 ((node->prev->type == XML_ELEMENT_NODE) ||
3423 (node->prev->type == XML_TEXT_NODE)))
3424 result = xmlGetLineNo(node->prev);
3425 else if ((node->parent != NULL) &&
3426 ((node->parent->type == XML_ELEMENT_NODE) ||
3427 (node->parent->type == XML_TEXT_NODE)))
3428 result = xmlGetLineNo(node->parent);
3429
3430 return result;
3431}
3432
3433/**
3434 * xmlGetNodePath:
3435 * @node: a node
3436 *
3437 * Build a structure based Path for the given node
3438 *
3439 * Returns the new path or NULL in case of error. The caller must free
3440 * the returned string
3441 */
3442xmlChar *
3443xmlGetNodePath(xmlNodePtr node)
3444{
3445 xmlNodePtr cur, tmp, next;
3446 xmlChar *buffer = NULL, *temp;
3447 size_t buf_len;
3448 xmlChar *buf;
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00003449 const char *sep;
Daniel Veillard8faa7832001-11-26 15:58:08 +00003450 const char *name;
3451 char nametemp[100];
3452 int occur = 0;
3453
3454 if (node == NULL)
3455 return (NULL);
3456
3457 buf_len = 500;
3458 buffer = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3459 if (buffer == NULL)
3460 return (NULL);
3461 buf = (xmlChar *) xmlMalloc(buf_len * sizeof(xmlChar));
3462 if (buf == NULL) {
3463 xmlFree(buffer);
3464 return (NULL);
3465 }
3466
3467 buffer[0] = 0;
3468 cur = node;
3469 do {
3470 name = "";
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003471 sep = "?";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003472 occur = 0;
3473 if ((cur->type == XML_DOCUMENT_NODE) ||
3474 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3475 if (buffer[0] == '/')
3476 break;
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003477 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003478 next = NULL;
3479 } else if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003480 sep = "/";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003481 name = (const char *) cur->name;
3482 if (cur->ns) {
3483 snprintf(nametemp, sizeof(nametemp) - 1,
3484 "%s:%s", cur->ns->prefix, cur->name);
3485 nametemp[sizeof(nametemp) - 1] = 0;
3486 name = nametemp;
3487 }
3488 next = cur->parent;
3489
3490 /*
3491 * Thumbler index computation
3492 */
3493 tmp = cur->prev;
3494 while (tmp != NULL) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00003495 if ((tmp->type == XML_ELEMENT_NODE) &&
3496 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003497 occur++;
3498 tmp = tmp->prev;
3499 }
3500 if (occur == 0) {
3501 tmp = cur->next;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003502 while (tmp != NULL && occur == 0) {
3503 if ((tmp->type == XML_ELEMENT_NODE) &&
3504 (xmlStrEqual(cur->name, tmp->name)))
Daniel Veillard8faa7832001-11-26 15:58:08 +00003505 occur++;
3506 tmp = tmp->next;
3507 }
3508 if (occur != 0)
3509 occur = 1;
3510 } else
3511 occur++;
Daniel Veillard8606bbb2002-11-12 12:36:52 +00003512 } else if (cur->type == XML_COMMENT_NODE) {
3513 sep = "/";
3514 name = "comment()";
3515 next = cur->parent;
3516
3517 /*
3518 * Thumbler index computation
3519 */
3520 tmp = cur->prev;
3521 while (tmp != NULL) {
3522 if (tmp->type == XML_COMMENT_NODE)
3523 occur++;
3524 tmp = tmp->prev;
3525 }
3526 if (occur == 0) {
3527 tmp = cur->next;
3528 while (tmp != NULL && occur == 0) {
3529 if (tmp->type == XML_COMMENT_NODE)
3530 occur++;
3531 tmp = tmp->next;
3532 }
3533 if (occur != 0)
3534 occur = 1;
3535 } else
3536 occur++;
3537 } else if ((cur->type == XML_TEXT_NODE) ||
3538 (cur->type == XML_CDATA_SECTION_NODE)) {
3539 sep = "/";
3540 name = "text()";
3541 next = cur->parent;
3542
3543 /*
3544 * Thumbler index computation
3545 */
3546 tmp = cur->prev;
3547 while (tmp != NULL) {
3548 if ((cur->type == XML_TEXT_NODE) ||
3549 (cur->type == XML_CDATA_SECTION_NODE))
3550 occur++;
3551 tmp = tmp->prev;
3552 }
3553 if (occur == 0) {
3554 tmp = cur->next;
3555 while (tmp != NULL && occur == 0) {
3556 if ((cur->type == XML_TEXT_NODE) ||
3557 (cur->type == XML_CDATA_SECTION_NODE))
3558 occur++;
3559 tmp = tmp->next;
3560 }
3561 if (occur != 0)
3562 occur = 1;
3563 } else
3564 occur++;
3565 } else if (cur->type == XML_PI_NODE) {
3566 sep = "/";
3567 snprintf(nametemp, sizeof(nametemp) - 1,
3568 "processing-instruction('%s')", cur->name);
3569 nametemp[sizeof(nametemp) - 1] = 0;
3570 name = nametemp;
3571
3572 next = cur->parent;
3573
3574 /*
3575 * Thumbler index computation
3576 */
3577 tmp = cur->prev;
3578 while (tmp != NULL) {
3579 if ((tmp->type == XML_PI_NODE) &&
3580 (xmlStrEqual(cur->name, tmp->name)))
3581 occur++;
3582 tmp = tmp->prev;
3583 }
3584 if (occur == 0) {
3585 tmp = cur->next;
3586 while (tmp != NULL && occur == 0) {
3587 if ((tmp->type == XML_PI_NODE) &&
3588 (xmlStrEqual(cur->name, tmp->name)))
3589 occur++;
3590 tmp = tmp->next;
3591 }
3592 if (occur != 0)
3593 occur = 1;
3594 } else
3595 occur++;
3596
Daniel Veillard8faa7832001-11-26 15:58:08 +00003597 } else if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003598 sep = "/@";
Daniel Veillard8faa7832001-11-26 15:58:08 +00003599 name = (const char *) (((xmlAttrPtr) cur)->name);
3600 next = ((xmlAttrPtr) cur)->parent;
3601 } else {
3602 next = cur->parent;
3603 }
3604
3605 /*
3606 * Make sure there is enough room
3607 */
3608 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
3609 buf_len =
3610 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
3611 temp = (xmlChar *) xmlRealloc(buffer, buf_len);
3612 if (temp == NULL) {
3613 xmlFree(buf);
3614 xmlFree(buffer);
3615 return (NULL);
3616 }
3617 buffer = temp;
3618 temp = (xmlChar *) xmlRealloc(buf, buf_len);
3619 if (temp == NULL) {
3620 xmlFree(buf);
3621 xmlFree(buffer);
3622 return (NULL);
3623 }
3624 buf = temp;
3625 }
3626 if (occur == 0)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003627 snprintf((char *) buf, buf_len, "%s%s%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003628 sep, name, (char *) buffer);
3629 else
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00003630 snprintf((char *) buf, buf_len, "%s%s[%d]%s",
Daniel Veillard8faa7832001-11-26 15:58:08 +00003631 sep, name, occur, (char *) buffer);
3632 snprintf((char *) buffer, buf_len, "%s", buf);
3633 cur = next;
3634 } while (cur != NULL);
3635 xmlFree(buf);
3636 return (buffer);
3637}
3638
3639/**
Owen Taylor3473f882001-02-23 17:55:21 +00003640 * xmlDocGetRootElement:
3641 * @doc: the document
3642 *
3643 * Get the root element of the document (doc->children is a list
3644 * containing possibly comments, PIs, etc ...).
3645 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003646 * Returns the #xmlNodePtr for the root or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00003647 */
3648xmlNodePtr
3649xmlDocGetRootElement(xmlDocPtr doc) {
3650 xmlNodePtr ret;
3651
3652 if (doc == NULL) return(NULL);
3653 ret = doc->children;
3654 while (ret != NULL) {
3655 if (ret->type == XML_ELEMENT_NODE)
3656 return(ret);
3657 ret = ret->next;
3658 }
3659 return(ret);
3660}
3661
3662/**
3663 * xmlDocSetRootElement:
3664 * @doc: the document
3665 * @root: the new document root element
3666 *
3667 * Set the root element of the document (doc->children is a list
3668 * containing possibly comments, PIs, etc ...).
3669 *
3670 * Returns the old root element if any was found
3671 */
3672xmlNodePtr
3673xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
3674 xmlNodePtr old = NULL;
3675
3676 if (doc == NULL) return(NULL);
Daniel Veillardc575b992002-02-08 13:28:40 +00003677 if (root == NULL)
3678 return(NULL);
3679 xmlUnlinkNode(root);
3680 root->doc = doc;
3681 root->parent = (xmlNodePtr) doc;
Owen Taylor3473f882001-02-23 17:55:21 +00003682 old = doc->children;
3683 while (old != NULL) {
3684 if (old->type == XML_ELEMENT_NODE)
3685 break;
3686 old = old->next;
3687 }
3688 if (old == NULL) {
3689 if (doc->children == NULL) {
3690 doc->children = root;
3691 doc->last = root;
3692 } else {
3693 xmlAddSibling(doc->children, root);
3694 }
3695 } else {
3696 xmlReplaceNode(old, root);
3697 }
3698 return(old);
3699}
3700
3701/**
3702 * xmlNodeSetLang:
3703 * @cur: the node being changed
Daniel Veillardd1640922001-12-17 15:30:10 +00003704 * @lang: the language description
Owen Taylor3473f882001-02-23 17:55:21 +00003705 *
3706 * Set the language of a node, i.e. the values of the xml:lang
3707 * attribute.
3708 */
3709void
3710xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003711 xmlNsPtr ns;
3712
Owen Taylor3473f882001-02-23 17:55:21 +00003713 if (cur == NULL) return;
3714 switch(cur->type) {
3715 case XML_TEXT_NODE:
3716 case XML_CDATA_SECTION_NODE:
3717 case XML_COMMENT_NODE:
3718 case XML_DOCUMENT_NODE:
3719 case XML_DOCUMENT_TYPE_NODE:
3720 case XML_DOCUMENT_FRAG_NODE:
3721 case XML_NOTATION_NODE:
3722 case XML_HTML_DOCUMENT_NODE:
3723 case XML_DTD_NODE:
3724 case XML_ELEMENT_DECL:
3725 case XML_ATTRIBUTE_DECL:
3726 case XML_ENTITY_DECL:
3727 case XML_PI_NODE:
3728 case XML_ENTITY_REF_NODE:
3729 case XML_ENTITY_NODE:
3730 case XML_NAMESPACE_DECL:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003731#ifdef LIBXML_DOCB_ENABLED
3732 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003733#endif
3734 case XML_XINCLUDE_START:
3735 case XML_XINCLUDE_END:
3736 return;
3737 case XML_ELEMENT_NODE:
3738 case XML_ATTRIBUTE_NODE:
3739 break;
3740 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003741 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3742 if (ns == NULL)
3743 return;
3744 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
Owen Taylor3473f882001-02-23 17:55:21 +00003745}
3746
3747/**
3748 * xmlNodeGetLang:
3749 * @cur: the node being checked
3750 *
3751 * Searches the language of a node, i.e. the values of the xml:lang
3752 * attribute or the one carried by the nearest ancestor.
3753 *
3754 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003755 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003756 */
3757xmlChar *
3758xmlNodeGetLang(xmlNodePtr cur) {
3759 xmlChar *lang;
3760
3761 while (cur != NULL) {
Daniel Veillardc17337c2001-05-09 10:51:31 +00003762 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003763 if (lang != NULL)
3764 return(lang);
3765 cur = cur->parent;
3766 }
3767 return(NULL);
3768}
3769
3770
3771/**
3772 * xmlNodeSetSpacePreserve:
3773 * @cur: the node being changed
3774 * @val: the xml:space value ("0": default, 1: "preserve")
3775 *
3776 * Set (or reset) the space preserving behaviour of a node, i.e. the
3777 * value of the xml:space attribute.
3778 */
3779void
3780xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003781 xmlNsPtr ns;
3782
Owen Taylor3473f882001-02-23 17:55:21 +00003783 if (cur == NULL) return;
3784 switch(cur->type) {
3785 case XML_TEXT_NODE:
3786 case XML_CDATA_SECTION_NODE:
3787 case XML_COMMENT_NODE:
3788 case XML_DOCUMENT_NODE:
3789 case XML_DOCUMENT_TYPE_NODE:
3790 case XML_DOCUMENT_FRAG_NODE:
3791 case XML_NOTATION_NODE:
3792 case XML_HTML_DOCUMENT_NODE:
3793 case XML_DTD_NODE:
3794 case XML_ELEMENT_DECL:
3795 case XML_ATTRIBUTE_DECL:
3796 case XML_ENTITY_DECL:
3797 case XML_PI_NODE:
3798 case XML_ENTITY_REF_NODE:
3799 case XML_ENTITY_NODE:
3800 case XML_NAMESPACE_DECL:
3801 case XML_XINCLUDE_START:
3802 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003803#ifdef LIBXML_DOCB_ENABLED
3804 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003805#endif
3806 return;
3807 case XML_ELEMENT_NODE:
3808 case XML_ATTRIBUTE_NODE:
3809 break;
3810 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003811 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3812 if (ns == NULL)
3813 return;
Owen Taylor3473f882001-02-23 17:55:21 +00003814 switch (val) {
3815 case 0:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003816 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
Owen Taylor3473f882001-02-23 17:55:21 +00003817 break;
3818 case 1:
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003819 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
Owen Taylor3473f882001-02-23 17:55:21 +00003820 break;
3821 }
3822}
3823
3824/**
3825 * xmlNodeGetSpacePreserve:
3826 * @cur: the node being checked
3827 *
3828 * Searches the space preserving behaviour of a node, i.e. the values
3829 * of the xml:space attribute or the one carried by the nearest
3830 * ancestor.
3831 *
Daniel Veillardd1640922001-12-17 15:30:10 +00003832 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
Owen Taylor3473f882001-02-23 17:55:21 +00003833 */
3834int
3835xmlNodeGetSpacePreserve(xmlNodePtr cur) {
3836 xmlChar *space;
3837
3838 while (cur != NULL) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003839 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
Owen Taylor3473f882001-02-23 17:55:21 +00003840 if (space != NULL) {
3841 if (xmlStrEqual(space, BAD_CAST "preserve")) {
3842 xmlFree(space);
3843 return(1);
3844 }
3845 if (xmlStrEqual(space, BAD_CAST "default")) {
3846 xmlFree(space);
3847 return(0);
3848 }
3849 xmlFree(space);
3850 }
3851 cur = cur->parent;
3852 }
3853 return(-1);
3854}
3855
3856/**
3857 * xmlNodeSetName:
3858 * @cur: the node being changed
3859 * @name: the new tag name
3860 *
3861 * Set (or reset) the name of a node.
3862 */
3863void
3864xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
3865 if (cur == NULL) return;
3866 if (name == NULL) return;
3867 switch(cur->type) {
3868 case XML_TEXT_NODE:
3869 case XML_CDATA_SECTION_NODE:
3870 case XML_COMMENT_NODE:
3871 case XML_DOCUMENT_TYPE_NODE:
3872 case XML_DOCUMENT_FRAG_NODE:
3873 case XML_NOTATION_NODE:
3874 case XML_HTML_DOCUMENT_NODE:
3875 case XML_NAMESPACE_DECL:
3876 case XML_XINCLUDE_START:
3877 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003878#ifdef LIBXML_DOCB_ENABLED
3879 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003880#endif
3881 return;
3882 case XML_ELEMENT_NODE:
3883 case XML_ATTRIBUTE_NODE:
3884 case XML_PI_NODE:
3885 case XML_ENTITY_REF_NODE:
3886 case XML_ENTITY_NODE:
3887 case XML_DTD_NODE:
3888 case XML_DOCUMENT_NODE:
3889 case XML_ELEMENT_DECL:
3890 case XML_ATTRIBUTE_DECL:
3891 case XML_ENTITY_DECL:
3892 break;
3893 }
3894 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3895 cur->name = xmlStrdup(name);
3896}
3897
3898/**
3899 * xmlNodeSetBase:
3900 * @cur: the node being changed
3901 * @uri: the new base URI
3902 *
3903 * Set (or reset) the base URI of a node, i.e. the value of the
3904 * xml:base attribute.
3905 */
3906void
3907xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003908 xmlNsPtr ns;
3909
Owen Taylor3473f882001-02-23 17:55:21 +00003910 if (cur == NULL) return;
3911 switch(cur->type) {
3912 case XML_TEXT_NODE:
3913 case XML_CDATA_SECTION_NODE:
3914 case XML_COMMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003915 case XML_DOCUMENT_TYPE_NODE:
3916 case XML_DOCUMENT_FRAG_NODE:
3917 case XML_NOTATION_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003918 case XML_DTD_NODE:
3919 case XML_ELEMENT_DECL:
3920 case XML_ATTRIBUTE_DECL:
3921 case XML_ENTITY_DECL:
3922 case XML_PI_NODE:
3923 case XML_ENTITY_REF_NODE:
3924 case XML_ENTITY_NODE:
3925 case XML_NAMESPACE_DECL:
3926 case XML_XINCLUDE_START:
3927 case XML_XINCLUDE_END:
Owen Taylor3473f882001-02-23 17:55:21 +00003928 return;
3929 case XML_ELEMENT_NODE:
3930 case XML_ATTRIBUTE_NODE:
3931 break;
Daniel Veillard4cbe4702002-05-05 06:57:27 +00003932 case XML_DOCUMENT_NODE:
3933#ifdef LIBXML_DOCB_ENABLED
3934 case XML_DOCB_DOCUMENT_NODE:
3935#endif
3936 case XML_HTML_DOCUMENT_NODE: {
3937 xmlDocPtr doc = (xmlDocPtr) cur;
3938
3939 if (doc->URL != NULL)
3940 xmlFree((xmlChar *) doc->URL);
3941 if (uri == NULL)
3942 doc->URL = NULL;
3943 else
3944 doc->URL = xmlStrdup(uri);
3945 return;
3946 }
Owen Taylor3473f882001-02-23 17:55:21 +00003947 }
Daniel Veillardcfa0d812002-01-17 08:46:58 +00003948
3949 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
3950 if (ns == NULL)
3951 return;
3952 xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
Owen Taylor3473f882001-02-23 17:55:21 +00003953}
3954
3955/**
Owen Taylor3473f882001-02-23 17:55:21 +00003956 * xmlNodeGetBase:
3957 * @doc: the document the node pertains to
3958 * @cur: the node being checked
3959 *
3960 * Searches for the BASE URL. The code should work on both XML
3961 * and HTML document even if base mechanisms are completely different.
3962 * It returns the base as defined in RFC 2396 sections
3963 * 5.1.1. Base URI within Document Content
3964 * and
3965 * 5.1.2. Base URI from the Encapsulating Entity
3966 * However it does not return the document base (5.1.3), use
3967 * xmlDocumentGetBase() for this
3968 *
3969 * Returns a pointer to the base URL, or NULL if not found
Daniel Veillardbd9afb52002-09-25 22:25:35 +00003970 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00003971 */
3972xmlChar *
3973xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00003974 xmlChar *oldbase = NULL;
3975 xmlChar *base, *newbase;
Owen Taylor3473f882001-02-23 17:55:21 +00003976
3977 if ((cur == NULL) && (doc == NULL))
3978 return(NULL);
3979 if (doc == NULL) doc = cur->doc;
3980 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
3981 cur = doc->children;
3982 while ((cur != NULL) && (cur->name != NULL)) {
3983 if (cur->type != XML_ELEMENT_NODE) {
3984 cur = cur->next;
3985 continue;
3986 }
3987 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
3988 cur = cur->children;
3989 continue;
3990 }
3991 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
3992 cur = cur->children;
3993 continue;
3994 }
3995 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3996 return(xmlGetProp(cur, BAD_CAST "href"));
3997 }
3998 cur = cur->next;
3999 }
4000 return(NULL);
4001 }
4002 while (cur != NULL) {
4003 if (cur->type == XML_ENTITY_DECL) {
4004 xmlEntityPtr ent = (xmlEntityPtr) cur;
4005 return(xmlStrdup(ent->URI));
4006 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00004007 if (cur->type == XML_ELEMENT_NODE) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004008 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004009 if (base != NULL) {
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004010 if (oldbase != NULL) {
4011 newbase = xmlBuildURI(oldbase, base);
4012 if (newbase != NULL) {
4013 xmlFree(oldbase);
4014 xmlFree(base);
4015 oldbase = newbase;
4016 } else {
4017 xmlFree(oldbase);
4018 xmlFree(base);
4019 return(NULL);
4020 }
4021 } else {
4022 oldbase = base;
4023 }
4024 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
4025 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
4026 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
4027 return(oldbase);
Daniel Veillard42596ad2001-05-22 16:57:14 +00004028 }
4029 }
Owen Taylor3473f882001-02-23 17:55:21 +00004030 cur = cur->parent;
4031 }
Daniel Veillardb8c9be92001-07-09 16:01:19 +00004032 if ((doc != NULL) && (doc->URL != NULL)) {
4033 if (oldbase == NULL)
4034 return(xmlStrdup(doc->URL));
4035 newbase = xmlBuildURI(oldbase, doc->URL);
4036 xmlFree(oldbase);
4037 return(newbase);
4038 }
4039 return(oldbase);
Owen Taylor3473f882001-02-23 17:55:21 +00004040}
4041
4042/**
4043 * xmlNodeGetContent:
4044 * @cur: the node being read
4045 *
4046 * Read the value of a node, this can be either the text carried
4047 * directly by this node if it's a TEXT node or the aggregate string
4048 * of the values carried by this node child's (TEXT and ENTITY_REF).
Daniel Veillardd1640922001-12-17 15:30:10 +00004049 * Entity references are substituted.
4050 * Returns a new #xmlChar * or NULL if no content is available.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00004051 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00004052 */
4053xmlChar *
Daniel Veillard7646b182002-04-20 06:41:40 +00004054xmlNodeGetContent(xmlNodePtr cur)
4055{
4056 if (cur == NULL)
4057 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004058 switch (cur->type) {
4059 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004060 case XML_ELEMENT_NODE:{
4061 xmlNodePtr tmp = cur;
4062 xmlBufferPtr buffer;
4063 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00004064
Daniel Veillard7646b182002-04-20 06:41:40 +00004065 buffer = xmlBufferCreate();
4066 if (buffer == NULL)
4067 return (NULL);
4068 while (tmp != NULL) {
4069 switch (tmp->type) {
4070 case XML_CDATA_SECTION_NODE:
4071 case XML_TEXT_NODE:
4072 if (tmp->content != NULL)
4073 xmlBufferCat(buffer, tmp->content);
4074 break;
4075 case XML_ENTITY_REF_NODE:{
4076 /* recursive substitution of entity references */
4077 xmlChar *cont = xmlNodeGetContent(tmp);
Owen Taylor3473f882001-02-23 17:55:21 +00004078
Daniel Veillard7646b182002-04-20 06:41:40 +00004079 if (cont) {
4080 xmlBufferCat(buffer,
4081 (const xmlChar *) cont);
4082 xmlFree(cont);
4083 }
4084 break;
4085 }
4086 default:
4087 break;
4088 }
4089 /*
4090 * Skip to next node
4091 */
4092 if (tmp->children != NULL) {
4093 if (tmp->children->type != XML_ENTITY_DECL) {
4094 tmp = tmp->children;
4095 continue;
4096 }
4097 }
4098 if (tmp == cur)
4099 break;
Daniel Veillard6c831202001-03-07 15:57:53 +00004100
Daniel Veillard7646b182002-04-20 06:41:40 +00004101 if (tmp->next != NULL) {
4102 tmp = tmp->next;
4103 continue;
4104 }
4105
4106 do {
4107 tmp = tmp->parent;
4108 if (tmp == NULL)
4109 break;
4110 if (tmp == cur) {
4111 tmp = NULL;
4112 break;
4113 }
4114 if (tmp->next != NULL) {
4115 tmp = tmp->next;
4116 break;
4117 }
4118 } while (tmp != NULL);
4119 }
4120 ret = buffer->content;
4121 buffer->content = NULL;
4122 xmlBufferFree(buffer);
4123 return (ret);
4124 }
4125 case XML_ATTRIBUTE_NODE:{
4126 xmlAttrPtr attr = (xmlAttrPtr) cur;
4127
4128 if (attr->parent != NULL)
4129 return (xmlNodeListGetString
4130 (attr->parent->doc, attr->children, 1));
4131 else
4132 return (xmlNodeListGetString(NULL, attr->children, 1));
4133 break;
4134 }
Owen Taylor3473f882001-02-23 17:55:21 +00004135 case XML_COMMENT_NODE:
4136 case XML_PI_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004137 if (cur->content != NULL)
4138 return (xmlStrdup(cur->content));
4139 return (NULL);
4140 case XML_ENTITY_REF_NODE:{
4141 xmlEntityPtr ent;
4142 xmlNodePtr tmp;
4143 xmlBufferPtr buffer;
4144 xmlChar *ret;
4145
4146 /* lookup entity declaration */
4147 ent = xmlGetDocEntity(cur->doc, cur->name);
4148 if (ent == NULL)
4149 return (NULL);
4150
4151 buffer = xmlBufferCreate();
4152 if (buffer == NULL)
4153 return (NULL);
4154
4155 /* an entity content can be any "well balanced chunk",
4156 * i.e. the result of the content [43] production:
4157 * http://www.w3.org/TR/REC-xml#NT-content
4158 * -> we iterate through child nodes and recursive call
4159 * xmlNodeGetContent() which handles all possible node types */
4160 tmp = ent->children;
4161 while (tmp) {
4162 xmlChar *cont = xmlNodeGetContent(tmp);
4163
4164 if (cont) {
4165 xmlBufferCat(buffer, (const xmlChar *) cont);
4166 xmlFree(cont);
4167 }
4168 tmp = tmp->next;
4169 }
4170
4171 ret = buffer->content;
4172 buffer->content = NULL;
4173 xmlBufferFree(buffer);
4174 return (ret);
4175 }
Owen Taylor3473f882001-02-23 17:55:21 +00004176 case XML_ENTITY_NODE:
4177 case XML_DOCUMENT_NODE:
4178 case XML_HTML_DOCUMENT_NODE:
4179 case XML_DOCUMENT_TYPE_NODE:
4180 case XML_NOTATION_NODE:
4181 case XML_DTD_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004182 case XML_XINCLUDE_START:
4183 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004184#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard7646b182002-04-20 06:41:40 +00004185 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004186#endif
Daniel Veillard7646b182002-04-20 06:41:40 +00004187 return (NULL);
Daniel Veillard96c3a3b2002-10-14 15:39:04 +00004188 case XML_NAMESPACE_DECL: {
4189 xmlChar *tmp;
4190
4191 tmp = xmlStrdup(((xmlNsPtr) cur)->href);
4192 return (tmp);
4193 }
Owen Taylor3473f882001-02-23 17:55:21 +00004194 case XML_ELEMENT_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004195 /* TODO !!! */
4196 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004197 case XML_ATTRIBUTE_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004198 /* TODO !!! */
4199 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004200 case XML_ENTITY_DECL:
Daniel Veillard7646b182002-04-20 06:41:40 +00004201 /* TODO !!! */
4202 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004203 case XML_CDATA_SECTION_NODE:
4204 case XML_TEXT_NODE:
Daniel Veillard7646b182002-04-20 06:41:40 +00004205 if (cur->content != NULL)
4206 return (xmlStrdup(cur->content));
4207 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004208 }
Daniel Veillard7646b182002-04-20 06:41:40 +00004209 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004210}
Owen Taylor3473f882001-02-23 17:55:21 +00004211/**
4212 * xmlNodeSetContent:
4213 * @cur: the node being modified
4214 * @content: the new value of the content
4215 *
4216 * Replace the content of a node.
4217 */
4218void
4219xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
4220 if (cur == NULL) {
4221#ifdef DEBUG_TREE
4222 xmlGenericError(xmlGenericErrorContext,
4223 "xmlNodeSetContent : node == NULL\n");
4224#endif
4225 return;
4226 }
4227 switch (cur->type) {
4228 case XML_DOCUMENT_FRAG_NODE:
4229 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004230 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004231 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4232 cur->children = xmlStringGetNodeList(cur->doc, content);
4233 UPDATE_LAST_CHILD_AND_PARENT(cur)
4234 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004235 case XML_TEXT_NODE:
4236 case XML_CDATA_SECTION_NODE:
4237 case XML_ENTITY_REF_NODE:
4238 case XML_ENTITY_NODE:
4239 case XML_PI_NODE:
4240 case XML_COMMENT_NODE:
4241 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004242 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004243 }
4244 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4245 cur->last = cur->children = NULL;
4246 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004247 cur->content = xmlStrdup(content);
Owen Taylor3473f882001-02-23 17:55:21 +00004248 } else
4249 cur->content = NULL;
4250 break;
4251 case XML_DOCUMENT_NODE:
4252 case XML_HTML_DOCUMENT_NODE:
4253 case XML_DOCUMENT_TYPE_NODE:
4254 case XML_XINCLUDE_START:
4255 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004256#ifdef LIBXML_DOCB_ENABLED
4257 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004258#endif
4259 break;
4260 case XML_NOTATION_NODE:
4261 break;
4262 case XML_DTD_NODE:
4263 break;
4264 case XML_NAMESPACE_DECL:
4265 break;
4266 case XML_ELEMENT_DECL:
4267 /* TODO !!! */
4268 break;
4269 case XML_ATTRIBUTE_DECL:
4270 /* TODO !!! */
4271 break;
4272 case XML_ENTITY_DECL:
4273 /* TODO !!! */
4274 break;
4275 }
4276}
4277
4278/**
4279 * xmlNodeSetContentLen:
4280 * @cur: the node being modified
4281 * @content: the new value of the content
4282 * @len: the size of @content
4283 *
4284 * Replace the content of a node.
4285 */
4286void
4287xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4288 if (cur == NULL) {
4289#ifdef DEBUG_TREE
4290 xmlGenericError(xmlGenericErrorContext,
4291 "xmlNodeSetContentLen : node == NULL\n");
4292#endif
4293 return;
4294 }
4295 switch (cur->type) {
4296 case XML_DOCUMENT_FRAG_NODE:
4297 case XML_ELEMENT_NODE:
Daniel Veillard2c748c62002-01-16 15:37:50 +00004298 case XML_ATTRIBUTE_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004299 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4300 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
4301 UPDATE_LAST_CHILD_AND_PARENT(cur)
4302 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004303 case XML_TEXT_NODE:
4304 case XML_CDATA_SECTION_NODE:
4305 case XML_ENTITY_REF_NODE:
4306 case XML_ENTITY_NODE:
4307 case XML_PI_NODE:
4308 case XML_COMMENT_NODE:
4309 case XML_NOTATION_NODE:
4310 if (cur->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004311 xmlFree(cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004312 }
4313 if (cur->children != NULL) xmlFreeNodeList(cur->children);
4314 cur->children = cur->last = NULL;
4315 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004316 cur->content = xmlStrndup(content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004317 } else
4318 cur->content = NULL;
4319 break;
4320 case XML_DOCUMENT_NODE:
4321 case XML_DTD_NODE:
4322 case XML_HTML_DOCUMENT_NODE:
4323 case XML_DOCUMENT_TYPE_NODE:
4324 case XML_NAMESPACE_DECL:
4325 case XML_XINCLUDE_START:
4326 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004327#ifdef LIBXML_DOCB_ENABLED
4328 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004329#endif
4330 break;
4331 case XML_ELEMENT_DECL:
4332 /* TODO !!! */
4333 break;
4334 case XML_ATTRIBUTE_DECL:
4335 /* TODO !!! */
4336 break;
4337 case XML_ENTITY_DECL:
4338 /* TODO !!! */
4339 break;
4340 }
4341}
4342
4343/**
4344 * xmlNodeAddContentLen:
4345 * @cur: the node being modified
4346 * @content: extra content
4347 * @len: the size of @content
4348 *
4349 * Append the extra substring to the node content.
4350 */
4351void
4352xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
4353 if (cur == NULL) {
4354#ifdef DEBUG_TREE
4355 xmlGenericError(xmlGenericErrorContext,
4356 "xmlNodeAddContentLen : node == NULL\n");
4357#endif
4358 return;
4359 }
4360 if (len <= 0) return;
4361 switch (cur->type) {
4362 case XML_DOCUMENT_FRAG_NODE:
4363 case XML_ELEMENT_NODE: {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004364 xmlNodePtr last, newNode, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00004365
Daniel Veillard7db37732001-07-12 01:20:08 +00004366 last = cur->last;
Owen Taylor3473f882001-02-23 17:55:21 +00004367 newNode = xmlNewTextLen(content, len);
4368 if (newNode != NULL) {
Daniel Veillardacb2bda2002-01-13 16:15:43 +00004369 tmp = xmlAddChild(cur, newNode);
4370 if (tmp != newNode)
4371 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004372 if ((last != NULL) && (last->next == newNode)) {
4373 xmlTextMerge(last, newNode);
4374 }
4375 }
4376 break;
4377 }
4378 case XML_ATTRIBUTE_NODE:
4379 break;
4380 case XML_TEXT_NODE:
4381 case XML_CDATA_SECTION_NODE:
4382 case XML_ENTITY_REF_NODE:
4383 case XML_ENTITY_NODE:
4384 case XML_PI_NODE:
4385 case XML_COMMENT_NODE:
4386 case XML_NOTATION_NODE:
4387 if (content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004388 cur->content = xmlStrncat(cur->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00004389 }
4390 case XML_DOCUMENT_NODE:
4391 case XML_DTD_NODE:
4392 case XML_HTML_DOCUMENT_NODE:
4393 case XML_DOCUMENT_TYPE_NODE:
4394 case XML_NAMESPACE_DECL:
4395 case XML_XINCLUDE_START:
4396 case XML_XINCLUDE_END:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004397#ifdef LIBXML_DOCB_ENABLED
4398 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004399#endif
4400 break;
4401 case XML_ELEMENT_DECL:
4402 case XML_ATTRIBUTE_DECL:
4403 case XML_ENTITY_DECL:
4404 break;
4405 }
4406}
4407
4408/**
4409 * xmlNodeAddContent:
4410 * @cur: the node being modified
4411 * @content: extra content
4412 *
4413 * Append the extra substring to the node content.
4414 */
4415void
4416xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
4417 int len;
4418
4419 if (cur == NULL) {
4420#ifdef DEBUG_TREE
4421 xmlGenericError(xmlGenericErrorContext,
4422 "xmlNodeAddContent : node == NULL\n");
4423#endif
4424 return;
4425 }
4426 if (content == NULL) return;
4427 len = xmlStrlen(content);
4428 xmlNodeAddContentLen(cur, content, len);
4429}
4430
4431/**
4432 * xmlTextMerge:
4433 * @first: the first text node
4434 * @second: the second text node being merged
4435 *
4436 * Merge two text nodes into one
4437 * Returns the first text node augmented
4438 */
4439xmlNodePtr
4440xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
4441 if (first == NULL) return(second);
4442 if (second == NULL) return(first);
4443 if (first->type != XML_TEXT_NODE) return(first);
4444 if (second->type != XML_TEXT_NODE) return(first);
4445 if (second->name != first->name)
4446 return(first);
Owen Taylor3473f882001-02-23 17:55:21 +00004447 xmlNodeAddContent(first, second->content);
Owen Taylor3473f882001-02-23 17:55:21 +00004448 xmlUnlinkNode(second);
4449 xmlFreeNode(second);
4450 return(first);
4451}
4452
4453/**
4454 * xmlGetNsList:
4455 * @doc: the document
4456 * @node: the current node
4457 *
4458 * Search all the namespace applying to a given element.
Daniel Veillardd1640922001-12-17 15:30:10 +00004459 * Returns an NULL terminated array of all the #xmlNsPtr found
Owen Taylor3473f882001-02-23 17:55:21 +00004460 * that need to be freed by the caller or NULL if no
4461 * namespace if defined
4462 */
4463xmlNsPtr *
Daniel Veillard77044732001-06-29 21:31:07 +00004464xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node)
4465{
Owen Taylor3473f882001-02-23 17:55:21 +00004466 xmlNsPtr cur;
4467 xmlNsPtr *ret = NULL;
4468 int nbns = 0;
4469 int maxns = 10;
4470 int i;
4471
4472 while (node != NULL) {
Daniel Veillard77044732001-06-29 21:31:07 +00004473 if (node->type == XML_ELEMENT_NODE) {
4474 cur = node->nsDef;
4475 while (cur != NULL) {
4476 if (ret == NULL) {
4477 ret =
4478 (xmlNsPtr *) xmlMalloc((maxns + 1) *
4479 sizeof(xmlNsPtr));
4480 if (ret == NULL) {
4481 xmlGenericError(xmlGenericErrorContext,
4482 "xmlGetNsList : out of memory!\n");
4483 return (NULL);
4484 }
4485 ret[nbns] = NULL;
4486 }
4487 for (i = 0; i < nbns; i++) {
4488 if ((cur->prefix == ret[i]->prefix) ||
4489 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
4490 break;
4491 }
4492 if (i >= nbns) {
4493 if (nbns >= maxns) {
4494 maxns *= 2;
4495 ret = (xmlNsPtr *) xmlRealloc(ret,
4496 (maxns +
4497 1) *
4498 sizeof(xmlNsPtr));
4499 if (ret == NULL) {
4500 xmlGenericError(xmlGenericErrorContext,
4501 "xmlGetNsList : realloc failed!\n");
4502 return (NULL);
4503 }
4504 }
4505 ret[nbns++] = cur;
4506 ret[nbns] = NULL;
4507 }
Owen Taylor3473f882001-02-23 17:55:21 +00004508
Daniel Veillard77044732001-06-29 21:31:07 +00004509 cur = cur->next;
4510 }
4511 }
4512 node = node->parent;
Owen Taylor3473f882001-02-23 17:55:21 +00004513 }
Daniel Veillard77044732001-06-29 21:31:07 +00004514 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004515}
4516
4517/**
4518 * xmlSearchNs:
4519 * @doc: the document
4520 * @node: the current node
Daniel Veillard77851712001-02-27 21:54:07 +00004521 * @nameSpace: the namespace prefix
Owen Taylor3473f882001-02-23 17:55:21 +00004522 *
4523 * Search a Ns registered under a given name space for a document.
4524 * recurse on the parents until it finds the defined namespace
4525 * or return NULL otherwise.
4526 * @nameSpace can be NULL, this is a search for the default namespace.
4527 * We don't allow to cross entities boundaries. If you don't declare
4528 * the namespace within those you will be in troubles !!! A warning
4529 * is generated to cover this case.
4530 *
4531 * Returns the namespace pointer or NULL.
4532 */
4533xmlNsPtr
4534xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
4535 xmlNsPtr cur;
4536
4537 if (node == NULL) return(NULL);
4538 if ((nameSpace != NULL) &&
4539 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00004540 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4541 /*
4542 * The XML-1.0 namespace is normally held on the root
4543 * element. In this case exceptionally create it on the
4544 * node element.
4545 */
4546 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4547 if (cur == NULL) {
4548 xmlGenericError(xmlGenericErrorContext,
4549 "xmlSearchNs : malloc failed\n");
4550 return(NULL);
4551 }
4552 memset(cur, 0, sizeof(xmlNs));
4553 cur->type = XML_LOCAL_NAMESPACE;
4554 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4555 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4556 cur->next = node->nsDef;
4557 node->nsDef = cur;
4558 return(cur);
4559 }
Owen Taylor3473f882001-02-23 17:55:21 +00004560 if (doc->oldNs == NULL) {
4561 /*
4562 * Allocate a new Namespace and fill the fields.
4563 */
4564 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4565 if (doc->oldNs == NULL) {
4566 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00004567 "xmlSearchNs : malloc failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004568 return(NULL);
4569 }
4570 memset(doc->oldNs, 0, sizeof(xmlNs));
4571 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4572
4573 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4574 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4575 }
4576 return(doc->oldNs);
4577 }
4578 while (node != NULL) {
4579 if ((node->type == XML_ENTITY_REF_NODE) ||
4580 (node->type == XML_ENTITY_NODE) ||
4581 (node->type == XML_ENTITY_DECL))
4582 return(NULL);
4583 if (node->type == XML_ELEMENT_NODE) {
4584 cur = node->nsDef;
4585 while (cur != NULL) {
4586 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
4587 (cur->href != NULL))
4588 return(cur);
4589 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
4590 (cur->href != NULL) &&
4591 (xmlStrEqual(cur->prefix, nameSpace)))
4592 return(cur);
4593 cur = cur->next;
4594 }
4595 }
4596 node = node->parent;
4597 }
4598 return(NULL);
4599}
4600
4601/**
4602 * xmlSearchNsByHref:
4603 * @doc: the document
4604 * @node: the current node
4605 * @href: the namespace value
4606 *
4607 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
4608 * the defined namespace or return NULL otherwise.
4609 * Returns the namespace pointer or NULL.
4610 */
4611xmlNsPtr
4612xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
4613 xmlNsPtr cur;
4614 xmlNodePtr orig = node;
4615
4616 if ((node == NULL) || (href == NULL)) return(NULL);
4617 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
Daniel Veillardcfa0d812002-01-17 08:46:58 +00004618 /*
4619 * Only the document can hold the XML spec namespace.
4620 */
Daniel Veillardc1a0da32002-08-14 08:32:18 +00004621 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
4622 /*
4623 * The XML-1.0 namespace is normally held on the root
4624 * element. In this case exceptionally create it on the
4625 * node element.
4626 */
4627 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4628 if (cur == NULL) {
4629 xmlGenericError(xmlGenericErrorContext,
4630 "xmlSearchNs : malloc failed\n");
4631 return(NULL);
4632 }
4633 memset(cur, 0, sizeof(xmlNs));
4634 cur->type = XML_LOCAL_NAMESPACE;
4635 cur->href = xmlStrdup(XML_XML_NAMESPACE);
4636 cur->prefix = xmlStrdup((const xmlChar *)"xml");
4637 cur->next = node->nsDef;
4638 node->nsDef = cur;
4639 return(cur);
4640 }
Owen Taylor3473f882001-02-23 17:55:21 +00004641 if (doc->oldNs == NULL) {
4642 /*
4643 * Allocate a new Namespace and fill the fields.
4644 */
4645 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
4646 if (doc->oldNs == NULL) {
4647 xmlGenericError(xmlGenericErrorContext,
4648 "xmlSearchNsByHref : malloc failed\n");
4649 return(NULL);
4650 }
4651 memset(doc->oldNs, 0, sizeof(xmlNs));
4652 doc->oldNs->type = XML_LOCAL_NAMESPACE;
4653
4654 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
4655 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
4656 }
4657 return(doc->oldNs);
4658 }
4659 while (node != NULL) {
4660 cur = node->nsDef;
4661 while (cur != NULL) {
4662 if ((cur->href != NULL) && (href != NULL) &&
4663 (xmlStrEqual(cur->href, href))) {
4664 /*
4665 * Check that the prefix is not shadowed between orig and node
4666 */
4667 xmlNodePtr check = orig;
4668 xmlNsPtr tst;
4669
4670 while (check != node) {
4671 tst = check->nsDef;
4672 while (tst != NULL) {
4673 if ((tst->prefix == NULL) && (cur->prefix == NULL))
4674 goto shadowed;
4675 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
4676 (xmlStrEqual(tst->prefix, cur->prefix)))
4677 goto shadowed;
4678 tst = tst->next;
4679 }
4680 check = check->parent;
4681 }
4682 return(cur);
4683 }
4684shadowed:
4685 cur = cur->next;
4686 }
4687 node = node->parent;
4688 }
4689 return(NULL);
4690}
4691
4692/**
4693 * xmlNewReconciliedNs
4694 * @doc: the document
4695 * @tree: a node expected to hold the new namespace
4696 * @ns: the original namespace
4697 *
4698 * This function tries to locate a namespace definition in a tree
4699 * ancestors, or create a new namespace definition node similar to
4700 * @ns trying to reuse the same prefix. However if the given prefix is
4701 * null (default namespace) or reused within the subtree defined by
4702 * @tree or on one of its ancestors then a new prefix is generated.
4703 * Returns the (new) namespace definition or NULL in case of error
4704 */
4705xmlNsPtr
4706xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
4707 xmlNsPtr def;
4708 xmlChar prefix[50];
4709 int counter = 1;
4710
4711 if (tree == NULL) {
4712#ifdef DEBUG_TREE
4713 xmlGenericError(xmlGenericErrorContext,
4714 "xmlNewReconciliedNs : tree == NULL\n");
4715#endif
4716 return(NULL);
4717 }
4718 if (ns == NULL) {
4719#ifdef DEBUG_TREE
4720 xmlGenericError(xmlGenericErrorContext,
4721 "xmlNewReconciliedNs : ns == NULL\n");
4722#endif
4723 return(NULL);
4724 }
4725 /*
4726 * Search an existing namespace definition inherited.
4727 */
4728 def = xmlSearchNsByHref(doc, tree, ns->href);
4729 if (def != NULL)
4730 return(def);
4731
4732 /*
4733 * Find a close prefix which is not already in use.
4734 * Let's strip namespace prefixes longer than 20 chars !
4735 */
Daniel Veillardf742d342002-03-07 00:05:35 +00004736 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004737 snprintf((char *) prefix, sizeof(prefix), "default");
Daniel Veillardf742d342002-03-07 00:05:35 +00004738 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004739 snprintf((char *) prefix, sizeof(prefix), "%.20s", ns->prefix);
Daniel Veillardf742d342002-03-07 00:05:35 +00004740
Owen Taylor3473f882001-02-23 17:55:21 +00004741 def = xmlSearchNs(doc, tree, prefix);
4742 while (def != NULL) {
4743 if (counter > 1000) return(NULL);
Daniel Veillardf742d342002-03-07 00:05:35 +00004744 if (ns->prefix == NULL)
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004745 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
Daniel Veillardf742d342002-03-07 00:05:35 +00004746 else
Aleksey Sanin49cc9752002-06-14 17:07:10 +00004747 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", ns->prefix, counter++);
Owen Taylor3473f882001-02-23 17:55:21 +00004748 def = xmlSearchNs(doc, tree, prefix);
4749 }
4750
4751 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004752 * OK, now we are ready to create a new one.
Owen Taylor3473f882001-02-23 17:55:21 +00004753 */
4754 def = xmlNewNs(tree, ns->href, prefix);
4755 return(def);
4756}
4757
4758/**
4759 * xmlReconciliateNs
4760 * @doc: the document
4761 * @tree: a node defining the subtree to reconciliate
4762 *
4763 * This function checks that all the namespaces declared within the given
4764 * tree are properly declared. This is needed for example after Copy or Cut
4765 * and then paste operations. The subtree may still hold pointers to
4766 * namespace declarations outside the subtree or invalid/masked. As much
Daniel Veillardd1640922001-12-17 15:30:10 +00004767 * as possible the function try to reuse the existing namespaces found in
Owen Taylor3473f882001-02-23 17:55:21 +00004768 * the new environment. If not possible the new namespaces are redeclared
4769 * on @tree at the top of the given subtree.
4770 * Returns the number of namespace declarations created or -1 in case of error.
4771 */
4772int
4773xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
4774 xmlNsPtr *oldNs = NULL;
4775 xmlNsPtr *newNs = NULL;
4776 int sizeCache = 0;
4777 int nbCache = 0;
4778
4779 xmlNsPtr n;
4780 xmlNodePtr node = tree;
4781 xmlAttrPtr attr;
4782 int ret = 0, i;
4783
4784 while (node != NULL) {
4785 /*
4786 * Reconciliate the node namespace
4787 */
4788 if (node->ns != NULL) {
4789 /*
4790 * initialize the cache if needed
4791 */
4792 if (sizeCache == 0) {
4793 sizeCache = 10;
4794 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4795 sizeof(xmlNsPtr));
4796 if (oldNs == NULL) {
4797 xmlGenericError(xmlGenericErrorContext,
4798 "xmlReconciliateNs : memory pbm\n");
4799 return(-1);
4800 }
4801 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4802 sizeof(xmlNsPtr));
4803 if (newNs == NULL) {
4804 xmlGenericError(xmlGenericErrorContext,
4805 "xmlReconciliateNs : memory pbm\n");
4806 xmlFree(oldNs);
4807 return(-1);
4808 }
4809 }
4810 for (i = 0;i < nbCache;i++) {
4811 if (oldNs[i] == node->ns) {
4812 node->ns = newNs[i];
4813 break;
4814 }
4815 }
4816 if (i == nbCache) {
4817 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004818 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004819 */
4820 n = xmlNewReconciliedNs(doc, tree, node->ns);
4821 if (n != NULL) { /* :-( what if else ??? */
4822 /*
4823 * check if we need to grow the cache buffers.
4824 */
4825 if (sizeCache <= nbCache) {
4826 sizeCache *= 2;
4827 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4828 sizeof(xmlNsPtr));
4829 if (oldNs == NULL) {
4830 xmlGenericError(xmlGenericErrorContext,
4831 "xmlReconciliateNs : memory pbm\n");
4832 xmlFree(newNs);
4833 return(-1);
4834 }
4835 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4836 sizeof(xmlNsPtr));
4837 if (newNs == NULL) {
4838 xmlGenericError(xmlGenericErrorContext,
4839 "xmlReconciliateNs : memory pbm\n");
4840 xmlFree(oldNs);
4841 return(-1);
4842 }
4843 }
4844 newNs[nbCache] = n;
4845 oldNs[nbCache++] = node->ns;
4846 node->ns = n;
4847 }
4848 }
4849 }
4850 /*
4851 * now check for namespace hold by attributes on the node.
4852 */
4853 attr = node->properties;
4854 while (attr != NULL) {
4855 if (attr->ns != NULL) {
4856 /*
4857 * initialize the cache if needed
4858 */
4859 if (sizeCache == 0) {
4860 sizeCache = 10;
4861 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4862 sizeof(xmlNsPtr));
4863 if (oldNs == NULL) {
4864 xmlGenericError(xmlGenericErrorContext,
4865 "xmlReconciliateNs : memory pbm\n");
4866 return(-1);
4867 }
4868 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
4869 sizeof(xmlNsPtr));
4870 if (newNs == NULL) {
4871 xmlGenericError(xmlGenericErrorContext,
4872 "xmlReconciliateNs : memory pbm\n");
4873 xmlFree(oldNs);
4874 return(-1);
4875 }
4876 }
4877 for (i = 0;i < nbCache;i++) {
4878 if (oldNs[i] == attr->ns) {
Daniel Veillardce66ce12002-10-28 19:01:59 +00004879 attr->ns = newNs[i];
Owen Taylor3473f882001-02-23 17:55:21 +00004880 break;
4881 }
4882 }
4883 if (i == nbCache) {
4884 /*
Daniel Veillardd1640922001-12-17 15:30:10 +00004885 * OK we need to recreate a new namespace definition
Owen Taylor3473f882001-02-23 17:55:21 +00004886 */
4887 n = xmlNewReconciliedNs(doc, tree, attr->ns);
4888 if (n != NULL) { /* :-( what if else ??? */
4889 /*
4890 * check if we need to grow the cache buffers.
4891 */
4892 if (sizeCache <= nbCache) {
4893 sizeCache *= 2;
4894 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
4895 sizeof(xmlNsPtr));
4896 if (oldNs == NULL) {
4897 xmlGenericError(xmlGenericErrorContext,
4898 "xmlReconciliateNs : memory pbm\n");
4899 xmlFree(newNs);
4900 return(-1);
4901 }
4902 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
4903 sizeof(xmlNsPtr));
4904 if (newNs == NULL) {
4905 xmlGenericError(xmlGenericErrorContext,
4906 "xmlReconciliateNs : memory pbm\n");
4907 xmlFree(oldNs);
4908 return(-1);
4909 }
4910 }
4911 newNs[nbCache] = n;
4912 oldNs[nbCache++] = attr->ns;
4913 attr->ns = n;
4914 }
4915 }
4916 }
4917 attr = attr->next;
4918 }
4919
4920 /*
4921 * Browse the full subtree, deep first
4922 */
4923 if (node->children != NULL) {
4924 /* deep first */
4925 node = node->children;
4926 } else if ((node != tree) && (node->next != NULL)) {
4927 /* then siblings */
4928 node = node->next;
4929 } else if (node != tree) {
4930 /* go up to parents->next if needed */
4931 while (node != tree) {
4932 if (node->parent != NULL)
4933 node = node->parent;
4934 if ((node != tree) && (node->next != NULL)) {
4935 node = node->next;
4936 break;
4937 }
4938 if (node->parent == NULL) {
4939 node = NULL;
4940 break;
4941 }
4942 }
4943 /* exit condition */
4944 if (node == tree)
4945 node = NULL;
Daniel Veillard1e774382002-03-06 17:35:40 +00004946 } else
4947 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004948 }
Daniel Veillardf742d342002-03-07 00:05:35 +00004949 if (oldNs != NULL)
4950 xmlFree(oldNs);
4951 if (newNs != NULL)
4952 xmlFree(newNs);
Owen Taylor3473f882001-02-23 17:55:21 +00004953 return(ret);
4954}
4955
4956/**
4957 * xmlHasProp:
4958 * @node: the node
4959 * @name: the attribute name
4960 *
4961 * Search an attribute associated to a node
4962 * This function also looks in DTD attribute declaration for #FIXED or
4963 * default declaration values unless DTD use has been turned off.
4964 *
4965 * Returns the attribute or the attribute declaration or NULL if
4966 * neither was found.
4967 */
4968xmlAttrPtr
4969xmlHasProp(xmlNodePtr node, const xmlChar *name) {
4970 xmlAttrPtr prop;
4971 xmlDocPtr doc;
4972
4973 if ((node == NULL) || (name == NULL)) return(NULL);
4974 /*
4975 * Check on the properties attached to the node
4976 */
4977 prop = node->properties;
4978 while (prop != NULL) {
4979 if (xmlStrEqual(prop->name, name)) {
4980 return(prop);
4981 }
4982 prop = prop->next;
4983 }
4984 if (!xmlCheckDTD) return(NULL);
4985
4986 /*
4987 * Check if there is a default declaration in the internal
4988 * or external subsets
4989 */
4990 doc = node->doc;
4991 if (doc != NULL) {
4992 xmlAttributePtr attrDecl;
4993 if (doc->intSubset != NULL) {
4994 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4995 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4996 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4997 if (attrDecl != NULL)
4998 return((xmlAttrPtr) attrDecl);
4999 }
5000 }
5001 return(NULL);
5002}
5003
5004/**
Daniel Veillarde95e2392001-06-06 10:46:28 +00005005 * xmlHasNsProp:
5006 * @node: the node
5007 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005008 * @nameSpace: the URI of the namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005009 *
5010 * Search for an attribute associated to a node
5011 * This attribute has to be anchored in the namespace specified.
5012 * This does the entity substitution.
5013 * This function looks in DTD attribute declaration for #FIXED or
5014 * default declaration values unless DTD use has been turned off.
5015 *
5016 * Returns the attribute or the attribute declaration or NULL
5017 * if neither was found.
5018 */
5019xmlAttrPtr
Daniel Veillardca2366a2001-06-11 12:09:01 +00005020xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Daniel Veillarde95e2392001-06-06 10:46:28 +00005021 xmlAttrPtr prop;
5022 xmlDocPtr doc;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005023
5024 if (node == NULL)
5025 return(NULL);
5026
5027 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005028 if (nameSpace == NULL)
Daniel Veillarde95e2392001-06-06 10:46:28 +00005029 return(xmlHasProp(node, name));
5030 while (prop != NULL) {
5031 /*
5032 * One need to have
5033 * - same attribute names
5034 * - and the attribute carrying that namespace
Daniel Veillarde95e2392001-06-06 10:46:28 +00005035 */
5036 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde3c81b52001-06-17 14:50:34 +00005037 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, nameSpace)))) {
5038 return(prop);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005039 }
5040 prop = prop->next;
5041 }
5042 if (!xmlCheckDTD) return(NULL);
5043
5044 /*
5045 * Check if there is a default declaration in the internal
5046 * or external subsets
5047 */
5048 doc = node->doc;
5049 if (doc != NULL) {
5050 if (doc->intSubset != NULL) {
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005051 xmlAttributePtr attrDecl = NULL;
5052 xmlNsPtr *nsList, *cur;
5053 xmlChar *ename;
Daniel Veillarde95e2392001-06-06 10:46:28 +00005054
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005055 nsList = xmlGetNsList(node->doc, node);
5056 if (nsList == NULL)
5057 return(NULL);
5058 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
5059 ename = xmlStrdup(node->ns->prefix);
5060 ename = xmlStrcat(ename, BAD_CAST ":");
5061 ename = xmlStrcat(ename, node->name);
5062 } else {
5063 ename = xmlStrdup(node->name);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005064 }
Daniel Veillardef6c46f2002-03-07 22:21:56 +00005065 if (ename == NULL) {
5066 xmlFree(nsList);
5067 return(NULL);
5068 }
5069
5070 cur = nsList;
5071 while (*cur != NULL) {
5072 if (xmlStrEqual((*cur)->href, nameSpace)) {
5073 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, ename,
5074 name, (*cur)->prefix);
5075 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5076 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, ename,
5077 name, (*cur)->prefix);
5078 }
5079 cur++;
5080 }
5081 xmlFree(nsList);
5082 xmlFree(ename);
5083 return((xmlAttrPtr) attrDecl);
Daniel Veillarde95e2392001-06-06 10:46:28 +00005084 }
5085 }
5086 return(NULL);
5087}
5088
5089/**
Owen Taylor3473f882001-02-23 17:55:21 +00005090 * xmlGetProp:
5091 * @node: the node
5092 * @name: the attribute name
5093 *
5094 * Search and get the value of an attribute associated to a node
5095 * This does the entity substitution.
5096 * This function looks in DTD attribute declaration for #FIXED or
5097 * default declaration values unless DTD use has been turned off.
5098 *
5099 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005100 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005101 */
5102xmlChar *
5103xmlGetProp(xmlNodePtr node, const xmlChar *name) {
5104 xmlAttrPtr prop;
5105 xmlDocPtr doc;
5106
5107 if ((node == NULL) || (name == NULL)) return(NULL);
5108 /*
5109 * Check on the properties attached to the node
5110 */
5111 prop = node->properties;
5112 while (prop != NULL) {
5113 if (xmlStrEqual(prop->name, name)) {
5114 xmlChar *ret;
5115
5116 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5117 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5118 return(ret);
5119 }
5120 prop = prop->next;
5121 }
5122 if (!xmlCheckDTD) return(NULL);
5123
5124 /*
5125 * Check if there is a default declaration in the internal
5126 * or external subsets
5127 */
5128 doc = node->doc;
5129 if (doc != NULL) {
5130 xmlAttributePtr attrDecl;
5131 if (doc->intSubset != NULL) {
5132 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5133 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5134 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5135 if (attrDecl != NULL)
5136 return(xmlStrdup(attrDecl->defaultValue));
5137 }
5138 }
5139 return(NULL);
5140}
5141
5142/**
5143 * xmlGetNsProp:
5144 * @node: the node
5145 * @name: the attribute name
Daniel Veillardca2366a2001-06-11 12:09:01 +00005146 * @nameSpace: the URI of the namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005147 *
5148 * Search and get the value of an attribute associated to a node
5149 * This attribute has to be anchored in the namespace specified.
5150 * This does the entity substitution.
5151 * This function looks in DTD attribute declaration for #FIXED or
5152 * default declaration values unless DTD use has been turned off.
5153 *
5154 * Returns the attribute value or NULL if not found.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005155 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00005156 */
5157xmlChar *
Daniel Veillardca2366a2001-06-11 12:09:01 +00005158xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
Owen Taylor3473f882001-02-23 17:55:21 +00005159 xmlAttrPtr prop;
5160 xmlDocPtr doc;
5161 xmlNsPtr ns;
5162
5163 if (node == NULL)
5164 return(NULL);
5165
5166 prop = node->properties;
Daniel Veillardca2366a2001-06-11 12:09:01 +00005167 if (nameSpace == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005168 return(xmlGetProp(node, name));
5169 while (prop != NULL) {
5170 /*
5171 * One need to have
5172 * - same attribute names
5173 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005174 */
5175 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarde8fc08e2001-06-07 19:35:47 +00005176 ((prop->ns != NULL) &&
Daniel Veillardca2366a2001-06-11 12:09:01 +00005177 (xmlStrEqual(prop->ns->href, nameSpace)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005178 xmlChar *ret;
5179
5180 ret = xmlNodeListGetString(node->doc, prop->children, 1);
5181 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
5182 return(ret);
5183 }
5184 prop = prop->next;
5185 }
5186 if (!xmlCheckDTD) return(NULL);
5187
5188 /*
5189 * Check if there is a default declaration in the internal
5190 * or external subsets
5191 */
5192 doc = node->doc;
5193 if (doc != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005194 if (doc->intSubset != NULL) {
Daniel Veillard5792e162001-04-30 17:44:45 +00005195 xmlAttributePtr attrDecl;
5196
Owen Taylor3473f882001-02-23 17:55:21 +00005197 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
5198 if ((attrDecl == NULL) && (doc->extSubset != NULL))
5199 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
5200
5201 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
5202 /*
5203 * The DTD declaration only allows a prefix search
5204 */
5205 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillardca2366a2001-06-11 12:09:01 +00005206 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
Owen Taylor3473f882001-02-23 17:55:21 +00005207 return(xmlStrdup(attrDecl->defaultValue));
5208 }
5209 }
5210 }
5211 return(NULL);
5212}
5213
5214/**
5215 * xmlSetProp:
5216 * @node: the node
5217 * @name: the attribute name
5218 * @value: the attribute value
5219 *
5220 * Set (or reset) an attribute carried by a node.
5221 * Returns the attribute pointer.
5222 */
5223xmlAttrPtr
5224xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005225 xmlAttrPtr prop;
5226 xmlDocPtr doc;
Owen Taylor3473f882001-02-23 17:55:21 +00005227
5228 if ((node == NULL) || (name == NULL))
5229 return(NULL);
5230 doc = node->doc;
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005231 prop = node->properties;
Owen Taylor3473f882001-02-23 17:55:21 +00005232 while (prop != NULL) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005233 if ((xmlStrEqual(prop->name, name)) &&
5234 (prop->ns == NULL)){
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005235 xmlNodePtr oldprop = prop->children;
5236
Owen Taylor3473f882001-02-23 17:55:21 +00005237 prop->children = NULL;
5238 prop->last = NULL;
5239 if (value != NULL) {
5240 xmlChar *buffer;
5241 xmlNodePtr tmp;
5242
5243 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5244 prop->children = xmlStringGetNodeList(node->doc, buffer);
5245 prop->last = NULL;
5246 prop->doc = doc;
5247 tmp = prop->children;
5248 while (tmp != NULL) {
5249 tmp->parent = (xmlNodePtr) prop;
5250 tmp->doc = doc;
5251 if (tmp->next == NULL)
5252 prop->last = tmp;
5253 tmp = tmp->next;
5254 }
5255 xmlFree(buffer);
Daniel Veillard75bea542001-05-11 17:41:21 +00005256 }
Daniel Veillard4855c8c2001-11-25 10:35:25 +00005257 if (oldprop != NULL)
5258 xmlFreeNodeList(oldprop);
Owen Taylor3473f882001-02-23 17:55:21 +00005259 return(prop);
5260 }
5261 prop = prop->next;
5262 }
5263 prop = xmlNewProp(node, name, value);
5264 return(prop);
5265}
5266
5267/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005268 * xmlUnsetProp:
5269 * @node: the node
5270 * @name: the attribute name
5271 *
5272 * Remove an attribute carried by a node.
5273 * Returns 0 if successful, -1 if not found
5274 */
5275int
5276xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
5277 xmlAttrPtr prop = node->properties, prev = NULL;;
5278
5279 if ((node == NULL) || (name == NULL))
5280 return(-1);
5281 while (prop != NULL) {
5282 if ((xmlStrEqual(prop->name, name)) &&
5283 (prop->ns == NULL)) {
5284 if (prev == NULL)
5285 node->properties = prop->next;
5286 else
5287 prev->next = prop->next;
5288 xmlFreeProp(prop);
5289 return(0);
5290 }
5291 prev = prop;
5292 prop = prop->next;
5293 }
5294 return(-1);
5295}
5296
5297/**
Owen Taylor3473f882001-02-23 17:55:21 +00005298 * xmlSetNsProp:
5299 * @node: the node
5300 * @ns: the namespace definition
5301 * @name: the attribute name
5302 * @value: the attribute value
5303 *
5304 * Set (or reset) an attribute carried by a node.
5305 * The ns structure must be in scope, this is not checked.
5306 *
5307 * Returns the attribute pointer.
5308 */
5309xmlAttrPtr
5310xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
5311 const xmlChar *value) {
5312 xmlAttrPtr prop;
5313
5314 if ((node == NULL) || (name == NULL))
5315 return(NULL);
5316
5317 if (ns == NULL)
5318 return(xmlSetProp(node, name, value));
5319 if (ns->href == NULL)
5320 return(NULL);
5321 prop = node->properties;
5322
5323 while (prop != NULL) {
5324 /*
5325 * One need to have
5326 * - same attribute names
5327 * - and the attribute carrying that namespace
Owen Taylor3473f882001-02-23 17:55:21 +00005328 */
5329 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillarda57c26e2002-08-01 12:52:24 +00005330 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Owen Taylor3473f882001-02-23 17:55:21 +00005331 if (prop->children != NULL)
5332 xmlFreeNodeList(prop->children);
5333 prop->children = NULL;
5334 prop->last = NULL;
5335 prop->ns = ns;
5336 if (value != NULL) {
5337 xmlChar *buffer;
5338 xmlNodePtr tmp;
5339
5340 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
5341 prop->children = xmlStringGetNodeList(node->doc, buffer);
5342 prop->last = NULL;
5343 tmp = prop->children;
5344 while (tmp != NULL) {
5345 tmp->parent = (xmlNodePtr) prop;
5346 if (tmp->next == NULL)
5347 prop->last = tmp;
5348 tmp = tmp->next;
5349 }
5350 xmlFree(buffer);
5351 }
5352 return(prop);
5353 }
5354 prop = prop->next;
5355 }
5356 prop = xmlNewNsProp(node, ns, name, value);
5357 return(prop);
5358}
5359
5360/**
Daniel Veillard75bea542001-05-11 17:41:21 +00005361 * xmlUnsetNsProp:
5362 * @node: the node
5363 * @ns: the namespace definition
5364 * @name: the attribute name
5365 *
5366 * Remove an attribute carried by a node.
5367 * Returns 0 if successful, -1 if not found
5368 */
5369int
5370xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
5371 xmlAttrPtr prop = node->properties, prev = NULL;;
5372
5373 if ((node == NULL) || (name == NULL))
5374 return(-1);
5375 if (ns == NULL)
5376 return(xmlUnsetProp(node, name));
5377 if (ns->href == NULL)
5378 return(-1);
5379 while (prop != NULL) {
5380 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard0bf29002002-08-01 12:54:11 +00005381 (prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))) {
Daniel Veillard75bea542001-05-11 17:41:21 +00005382 if (prev == NULL)
5383 node->properties = prop->next;
5384 else
5385 prev->next = prop->next;
5386 xmlFreeProp(prop);
5387 return(0);
5388 }
5389 prev = prop;
5390 prop = prop->next;
5391 }
5392 return(-1);
5393}
5394
5395/**
Owen Taylor3473f882001-02-23 17:55:21 +00005396 * xmlNodeIsText:
5397 * @node: the node
5398 *
5399 * Is this node a Text node ?
5400 * Returns 1 yes, 0 no
5401 */
5402int
5403xmlNodeIsText(xmlNodePtr node) {
5404 if (node == NULL) return(0);
5405
5406 if (node->type == XML_TEXT_NODE) return(1);
5407 return(0);
5408}
5409
5410/**
5411 * xmlIsBlankNode:
5412 * @node: the node
5413 *
5414 * Checks whether this node is an empty or whitespace only
5415 * (and possibly ignorable) text-node.
5416 *
5417 * Returns 1 yes, 0 no
5418 */
5419int
5420xmlIsBlankNode(xmlNodePtr node) {
5421 const xmlChar *cur;
5422 if (node == NULL) return(0);
5423
Daniel Veillard7db37732001-07-12 01:20:08 +00005424 if ((node->type != XML_TEXT_NODE) &&
5425 (node->type != XML_CDATA_SECTION_NODE))
5426 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005427 if (node->content == NULL) return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005428 cur = node->content;
Owen Taylor3473f882001-02-23 17:55:21 +00005429 while (*cur != 0) {
5430 if (!IS_BLANK(*cur)) return(0);
5431 cur++;
5432 }
5433
5434 return(1);
5435}
5436
5437/**
5438 * xmlTextConcat:
5439 * @node: the node
5440 * @content: the content
Daniel Veillard60087f32001-10-10 09:45:09 +00005441 * @len: @content length
Owen Taylor3473f882001-02-23 17:55:21 +00005442 *
5443 * Concat the given string at the end of the existing node content
5444 */
5445
5446void
5447xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
5448 if (node == NULL) return;
5449
5450 if ((node->type != XML_TEXT_NODE) &&
5451 (node->type != XML_CDATA_SECTION_NODE)) {
5452#ifdef DEBUG_TREE
5453 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005454 "xmlTextConcat: node is not text nor CDATA\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005455#endif
5456 return;
5457 }
Owen Taylor3473f882001-02-23 17:55:21 +00005458 node->content = xmlStrncat(node->content, content, len);
Owen Taylor3473f882001-02-23 17:55:21 +00005459}
5460
5461/************************************************************************
5462 * *
5463 * Output : to a FILE or in memory *
5464 * *
5465 ************************************************************************/
5466
Owen Taylor3473f882001-02-23 17:55:21 +00005467/**
5468 * xmlBufferCreate:
5469 *
5470 * routine to create an XML buffer.
5471 * returns the new structure.
5472 */
5473xmlBufferPtr
5474xmlBufferCreate(void) {
5475 xmlBufferPtr ret;
5476
5477 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5478 if (ret == NULL) {
5479 xmlGenericError(xmlGenericErrorContext,
5480 "xmlBufferCreate : out of memory!\n");
5481 return(NULL);
5482 }
5483 ret->use = 0;
Daniel Veillarde356c282001-03-10 12:32:04 +00005484 ret->size = xmlDefaultBufferSize;
Owen Taylor3473f882001-02-23 17:55:21 +00005485 ret->alloc = xmlBufferAllocScheme;
5486 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5487 if (ret->content == NULL) {
5488 xmlGenericError(xmlGenericErrorContext,
5489 "xmlBufferCreate : out of memory!\n");
5490 xmlFree(ret);
5491 return(NULL);
5492 }
5493 ret->content[0] = 0;
5494 return(ret);
5495}
5496
5497/**
5498 * xmlBufferCreateSize:
5499 * @size: initial size of buffer
5500 *
5501 * routine to create an XML buffer.
5502 * returns the new structure.
5503 */
5504xmlBufferPtr
5505xmlBufferCreateSize(size_t size) {
5506 xmlBufferPtr ret;
5507
5508 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
5509 if (ret == NULL) {
5510 xmlGenericError(xmlGenericErrorContext,
5511 "xmlBufferCreate : out of memory!\n");
5512 return(NULL);
5513 }
5514 ret->use = 0;
5515 ret->alloc = xmlBufferAllocScheme;
5516 ret->size = (size ? size+2 : 0); /* +1 for ending null */
5517 if (ret->size){
5518 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
5519 if (ret->content == NULL) {
5520 xmlGenericError(xmlGenericErrorContext,
5521 "xmlBufferCreate : out of memory!\n");
5522 xmlFree(ret);
5523 return(NULL);
5524 }
5525 ret->content[0] = 0;
5526 } else
5527 ret->content = NULL;
5528 return(ret);
5529}
5530
5531/**
5532 * xmlBufferSetAllocationScheme:
Daniel Veillardbd9afb52002-09-25 22:25:35 +00005533 * @buf: the buffer to tune
Owen Taylor3473f882001-02-23 17:55:21 +00005534 * @scheme: allocation scheme to use
5535 *
5536 * Sets the allocation scheme for this buffer
5537 */
5538void
5539xmlBufferSetAllocationScheme(xmlBufferPtr buf,
5540 xmlBufferAllocationScheme scheme) {
5541 if (buf == NULL) {
5542#ifdef DEBUG_BUFFER
5543 xmlGenericError(xmlGenericErrorContext,
5544 "xmlBufferSetAllocationScheme: buf == NULL\n");
5545#endif
5546 return;
5547 }
5548
5549 buf->alloc = scheme;
5550}
5551
5552/**
5553 * xmlBufferFree:
5554 * @buf: the buffer to free
5555 *
Daniel Veillard9d06d302002-01-22 18:15:52 +00005556 * Frees an XML buffer. It frees both the content and the structure which
5557 * encapsulate it.
Owen Taylor3473f882001-02-23 17:55:21 +00005558 */
5559void
5560xmlBufferFree(xmlBufferPtr buf) {
5561 if (buf == NULL) {
5562#ifdef DEBUG_BUFFER
5563 xmlGenericError(xmlGenericErrorContext,
5564 "xmlBufferFree: buf == NULL\n");
5565#endif
5566 return;
5567 }
Daniel Veillard561b7f82002-03-20 21:55:57 +00005568 if (buf->content != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005569 xmlFree(buf->content);
5570 }
Owen Taylor3473f882001-02-23 17:55:21 +00005571 xmlFree(buf);
5572}
5573
5574/**
5575 * xmlBufferEmpty:
5576 * @buf: the buffer
5577 *
5578 * empty a buffer.
5579 */
5580void
5581xmlBufferEmpty(xmlBufferPtr buf) {
5582 if (buf->content == NULL) return;
5583 buf->use = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005584 memset(buf->content, 0, buf->size);
Owen Taylor3473f882001-02-23 17:55:21 +00005585}
5586
5587/**
5588 * xmlBufferShrink:
5589 * @buf: the buffer to dump
5590 * @len: the number of xmlChar to remove
5591 *
5592 * Remove the beginning of an XML buffer.
5593 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005594 * Returns the number of #xmlChar removed, or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00005595 */
5596int
5597xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
5598 if (len == 0) return(0);
5599 if (len > buf->use) return(-1);
5600
5601 buf->use -= len;
5602 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
5603
5604 buf->content[buf->use] = 0;
5605 return(len);
5606}
5607
5608/**
5609 * xmlBufferGrow:
5610 * @buf: the buffer
5611 * @len: the minimum free size to allocate
5612 *
5613 * Grow the available space of an XML buffer.
5614 *
5615 * Returns the new available space or -1 in case of error
5616 */
5617int
5618xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
5619 int size;
5620 xmlChar *newbuf;
5621
5622 if (len + buf->use < buf->size) return(0);
5623
5624 size = buf->use + len + 100;
5625
5626 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
5627 if (newbuf == NULL) return(-1);
5628 buf->content = newbuf;
5629 buf->size = size;
5630 return(buf->size - buf->use);
5631}
5632
5633/**
5634 * xmlBufferDump:
5635 * @file: the file output
5636 * @buf: the buffer to dump
5637 *
5638 * Dumps an XML buffer to a FILE *.
Daniel Veillardd1640922001-12-17 15:30:10 +00005639 * Returns the number of #xmlChar written
Owen Taylor3473f882001-02-23 17:55:21 +00005640 */
5641int
5642xmlBufferDump(FILE *file, xmlBufferPtr buf) {
5643 int ret;
5644
5645 if (buf == NULL) {
5646#ifdef DEBUG_BUFFER
5647 xmlGenericError(xmlGenericErrorContext,
5648 "xmlBufferDump: buf == NULL\n");
5649#endif
5650 return(0);
5651 }
5652 if (buf->content == NULL) {
5653#ifdef DEBUG_BUFFER
5654 xmlGenericError(xmlGenericErrorContext,
5655 "xmlBufferDump: buf->content == NULL\n");
5656#endif
5657 return(0);
5658 }
Daniel Veillardcd337f02001-11-22 18:20:37 +00005659 if (file == NULL)
5660 file = stdout;
Owen Taylor3473f882001-02-23 17:55:21 +00005661 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
5662 return(ret);
5663}
5664
5665/**
5666 * xmlBufferContent:
5667 * @buf: the buffer
5668 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005669 * Function to extract the content of a buffer
5670 *
Owen Taylor3473f882001-02-23 17:55:21 +00005671 * Returns the internal content
5672 */
5673
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005674const xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005675xmlBufferContent(const xmlBufferPtr buf)
5676{
5677 if(!buf)
5678 return NULL;
5679
5680 return buf->content;
5681}
5682
5683/**
5684 * xmlBufferLength:
5685 * @buf: the buffer
5686 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005687 * Function to get the length of a buffer
5688 *
Owen Taylor3473f882001-02-23 17:55:21 +00005689 * Returns the length of data in the internal content
5690 */
5691
5692int
5693xmlBufferLength(const xmlBufferPtr buf)
5694{
5695 if(!buf)
5696 return 0;
5697
5698 return buf->use;
5699}
5700
5701/**
5702 * xmlBufferResize:
5703 * @buf: the buffer to resize
5704 * @size: the desired size
5705 *
Daniel Veillardd1640922001-12-17 15:30:10 +00005706 * Resize a buffer to accommodate minimum size of @size.
Owen Taylor3473f882001-02-23 17:55:21 +00005707 *
5708 * Returns 0 in case of problems, 1 otherwise
5709 */
5710int
5711xmlBufferResize(xmlBufferPtr buf, unsigned int size)
5712{
5713 unsigned int newSize;
5714 xmlChar* rebuf = NULL;
5715
5716 /*take care of empty case*/
5717 newSize = (buf->size ? buf->size*2 : size);
5718
5719 /* Don't resize if we don't have to */
5720 if (size < buf->size)
5721 return 1;
5722
5723 /* figure out new size */
5724 switch (buf->alloc){
5725 case XML_BUFFER_ALLOC_DOUBLEIT:
5726 while (size > newSize) newSize *= 2;
5727 break;
5728 case XML_BUFFER_ALLOC_EXACT:
5729 newSize = size+10;
5730 break;
5731 default:
5732 newSize = size+10;
5733 break;
5734 }
5735
5736 if (buf->content == NULL)
5737 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
5738 else
5739 rebuf = (xmlChar *) xmlRealloc(buf->content,
5740 newSize * sizeof(xmlChar));
5741 if (rebuf == NULL) {
5742 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005743 "xmlBufferResize : out of memory!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005744 return 0;
5745 }
5746 buf->content = rebuf;
5747 buf->size = newSize;
5748
5749 return 1;
5750}
5751
5752/**
5753 * xmlBufferAdd:
5754 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005755 * @str: the #xmlChar string
5756 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005757 *
Daniel Veillard60087f32001-10-10 09:45:09 +00005758 * Add a string range to an XML buffer. if len == -1, the length of
Owen Taylor3473f882001-02-23 17:55:21 +00005759 * str is recomputed.
5760 */
5761void
5762xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
5763 unsigned int needSize;
5764
5765 if (str == NULL) {
5766#ifdef DEBUG_BUFFER
5767 xmlGenericError(xmlGenericErrorContext,
5768 "xmlBufferAdd: str == NULL\n");
5769#endif
5770 return;
5771 }
5772 if (len < -1) {
5773#ifdef DEBUG_BUFFER
5774 xmlGenericError(xmlGenericErrorContext,
5775 "xmlBufferAdd: len < 0\n");
5776#endif
5777 return;
5778 }
5779 if (len == 0) return;
5780
5781 if (len < 0)
5782 len = xmlStrlen(str);
5783
5784 if (len <= 0) return;
5785
5786 needSize = buf->use + len + 2;
5787 if (needSize > buf->size){
5788 if (!xmlBufferResize(buf, needSize)){
5789 xmlGenericError(xmlGenericErrorContext,
5790 "xmlBufferAdd : out of memory!\n");
5791 return;
5792 }
5793 }
5794
5795 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
5796 buf->use += len;
5797 buf->content[buf->use] = 0;
5798}
5799
5800/**
5801 * xmlBufferAddHead:
5802 * @buf: the buffer
Daniel Veillardd1640922001-12-17 15:30:10 +00005803 * @str: the #xmlChar string
5804 * @len: the number of #xmlChar to add
Owen Taylor3473f882001-02-23 17:55:21 +00005805 *
5806 * Add a string range to the beginning of an XML buffer.
Daniel Veillard60087f32001-10-10 09:45:09 +00005807 * if len == -1, the length of @str is recomputed.
Owen Taylor3473f882001-02-23 17:55:21 +00005808 */
5809void
5810xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
5811 unsigned int needSize;
5812
5813 if (str == NULL) {
5814#ifdef DEBUG_BUFFER
5815 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005816 "xmlBufferAddHead: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005817#endif
5818 return;
5819 }
5820 if (len < -1) {
5821#ifdef DEBUG_BUFFER
5822 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005823 "xmlBufferAddHead: len < 0\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005824#endif
5825 return;
5826 }
5827 if (len == 0) return;
5828
5829 if (len < 0)
5830 len = xmlStrlen(str);
5831
5832 if (len <= 0) return;
5833
5834 needSize = buf->use + len + 2;
5835 if (needSize > buf->size){
5836 if (!xmlBufferResize(buf, needSize)){
5837 xmlGenericError(xmlGenericErrorContext,
5838 "xmlBufferAddHead : out of memory!\n");
5839 return;
5840 }
5841 }
5842
5843 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
5844 memmove(&buf->content[0], str, len * sizeof(xmlChar));
5845 buf->use += len;
5846 buf->content[buf->use] = 0;
5847}
5848
5849/**
5850 * xmlBufferCat:
5851 * @buf: the buffer to dump
Daniel Veillardd1640922001-12-17 15:30:10 +00005852 * @str: the #xmlChar string
Owen Taylor3473f882001-02-23 17:55:21 +00005853 *
5854 * Append a zero terminated string to an XML buffer.
5855 */
5856void
5857xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
5858 if (str != NULL)
5859 xmlBufferAdd(buf, str, -1);
5860}
5861
5862/**
5863 * xmlBufferCCat:
5864 * @buf: the buffer to dump
5865 * @str: the C char string
5866 *
5867 * Append a zero terminated C string to an XML buffer.
5868 */
5869void
5870xmlBufferCCat(xmlBufferPtr buf, const char *str) {
5871 const char *cur;
5872
5873 if (str == NULL) {
5874#ifdef DEBUG_BUFFER
5875 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00005876 "xmlBufferCCat: str == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005877#endif
5878 return;
5879 }
5880 for (cur = str;*cur != 0;cur++) {
5881 if (buf->use + 10 >= buf->size) {
5882 if (!xmlBufferResize(buf, buf->use+10)){
5883 xmlGenericError(xmlGenericErrorContext,
5884 "xmlBufferCCat : out of memory!\n");
5885 return;
5886 }
5887 }
5888 buf->content[buf->use++] = *cur;
5889 }
5890 buf->content[buf->use] = 0;
5891}
5892
5893/**
5894 * xmlBufferWriteCHAR:
5895 * @buf: the XML buffer
5896 * @string: the string to add
5897 *
5898 * routine which manages and grows an output buffer. This one adds
5899 * xmlChars at the end of the buffer.
5900 */
5901void
Owen Taylor3473f882001-02-23 17:55:21 +00005902xmlBufferWriteCHAR
Owen Taylor3473f882001-02-23 17:55:21 +00005903(xmlBufferPtr buf, const xmlChar *string) {
5904 xmlBufferCat(buf, string);
5905}
5906
5907/**
5908 * xmlBufferWriteChar:
5909 * @buf: the XML buffer output
5910 * @string: the string to add
5911 *
5912 * routine which manage and grows an output buffer. This one add
5913 * C chars at the end of the array.
5914 */
5915void
5916xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
5917 xmlBufferCCat(buf, string);
5918}
5919
5920
5921/**
5922 * xmlBufferWriteQuotedString:
5923 * @buf: the XML buffer output
5924 * @string: the string to add
5925 *
5926 * routine which manage and grows an output buffer. This one writes
Daniel Veillardd1640922001-12-17 15:30:10 +00005927 * a quoted or double quoted #xmlChar string, checking first if it holds
Owen Taylor3473f882001-02-23 17:55:21 +00005928 * quote or double-quotes internally
5929 */
5930void
5931xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
5932 if (xmlStrchr(string, '"')) {
5933 if (xmlStrchr(string, '\'')) {
5934#ifdef DEBUG_BUFFER
5935 xmlGenericError(xmlGenericErrorContext,
5936 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
5937#endif
5938 }
5939 xmlBufferCCat(buf, "'");
5940 xmlBufferCat(buf, string);
5941 xmlBufferCCat(buf, "'");
5942 } else {
5943 xmlBufferCCat(buf, "\"");
5944 xmlBufferCat(buf, string);
5945 xmlBufferCCat(buf, "\"");
5946 }
5947}
5948
5949
5950/************************************************************************
5951 * *
5952 * Dumping XML tree content to a simple buffer *
5953 * *
5954 ************************************************************************/
5955
Owen Taylor3473f882001-02-23 17:55:21 +00005956static void
5957xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5958 int format);
Owen Taylor3473f882001-02-23 17:55:21 +00005959
5960/**
5961 * xmlNsDump:
5962 * @buf: the XML buffer output
5963 * @cur: a namespace
5964 *
5965 * Dump a local Namespace definition.
5966 * Should be called in the context of attributes dumps.
5967 */
5968static void
5969xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
5970 if (cur == NULL) {
5971#ifdef DEBUG_TREE
5972 xmlGenericError(xmlGenericErrorContext,
5973 "xmlNsDump : Ns == NULL\n");
5974#endif
5975 return;
5976 }
5977 if (cur->type == XML_LOCAL_NAMESPACE) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00005978 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
5979 return;
5980
Owen Taylor3473f882001-02-23 17:55:21 +00005981 /* Within the context of an element attributes */
5982 if (cur->prefix != NULL) {
5983 xmlBufferWriteChar(buf, " xmlns:");
5984 xmlBufferWriteCHAR(buf, cur->prefix);
5985 } else
5986 xmlBufferWriteChar(buf, " xmlns");
5987 xmlBufferWriteChar(buf, "=");
5988 xmlBufferWriteQuotedString(buf, cur->href);
5989 }
5990}
5991
5992/**
5993 * xmlNsListDump:
5994 * @buf: the XML buffer output
5995 * @cur: the first namespace
5996 *
5997 * Dump a list of local Namespace definitions.
5998 * Should be called in the context of attributes dumps.
5999 */
6000static void
6001xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
6002 while (cur != NULL) {
6003 xmlNsDump(buf, cur);
6004 cur = cur->next;
6005 }
6006}
6007
6008/**
6009 * xmlDtdDump:
6010 * @buf: the XML buffer output
Daniel Veillardd1640922001-12-17 15:30:10 +00006011 * @dtd: the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00006012 *
6013 * Dump the XML document DTD, if any.
6014 */
6015static void
6016xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
6017 if (dtd == NULL) {
6018#ifdef DEBUG_TREE
6019 xmlGenericError(xmlGenericErrorContext,
6020 "xmlDtdDump : no internal subset\n");
6021#endif
6022 return;
6023 }
6024 xmlBufferWriteChar(buf, "<!DOCTYPE ");
6025 xmlBufferWriteCHAR(buf, dtd->name);
6026 if (dtd->ExternalID != NULL) {
6027 xmlBufferWriteChar(buf, " PUBLIC ");
6028 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
6029 xmlBufferWriteChar(buf, " ");
6030 xmlBufferWriteQuotedString(buf, dtd->SystemID);
6031 } else if (dtd->SystemID != NULL) {
6032 xmlBufferWriteChar(buf, " SYSTEM ");
6033 xmlBufferWriteQuotedString(buf, dtd->SystemID);
6034 }
6035 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6036 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6037 xmlBufferWriteChar(buf, ">");
6038 return;
6039 }
6040 xmlBufferWriteChar(buf, " [\n");
6041 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
6042#if 0
6043 if (dtd->entities != NULL)
6044 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
6045 if (dtd->notations != NULL)
6046 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
6047 if (dtd->elements != NULL)
6048 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
6049 if (dtd->attributes != NULL)
6050 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
6051#endif
6052 xmlBufferWriteChar(buf, "]>");
6053}
6054
6055/**
Daniel Veillarda6d05382002-02-13 13:07:41 +00006056 * xmlAttrSerializeContent:
6057 * @buf: the XML buffer output
6058 * @doc: the document
6059 * @attr: the attribute pointer
6060 *
6061 * Serialize the attribute in the buffer
6062 */
6063static void
6064xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) {
6065 const xmlChar *cur, *base;
6066 xmlNodePtr children;
6067
6068 children = attr->children;
6069 while (children != NULL) {
6070 switch (children->type) {
6071 case XML_TEXT_NODE:
6072 base = cur = children->content;
6073 while (*cur != 0) {
6074 if (*cur == '\n') {
6075 if (base != cur)
6076 xmlBufferAdd(buf, base, cur - base);
6077 xmlBufferAdd(buf, BAD_CAST "&#10;", 5);
6078 cur++;
6079 base = cur;
6080#if 0
6081 } else if (*cur == '\'') {
6082 if (base != cur)
6083 xmlBufferAdd(buf, base, cur - base);
6084 xmlBufferAdd(buf, BAD_CAST "&apos;", 6);
6085 cur++;
6086 base = cur;
6087#endif
6088 } else if (*cur == '"') {
6089 if (base != cur)
6090 xmlBufferAdd(buf, base, cur - base);
6091 xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
6092 cur++;
6093 base = cur;
6094 } else if (*cur == '<') {
6095 if (base != cur)
6096 xmlBufferAdd(buf, base, cur - base);
6097 xmlBufferAdd(buf, BAD_CAST "&lt;", 4);
6098 cur++;
6099 base = cur;
6100 } else if (*cur == '>') {
6101 if (base != cur)
6102 xmlBufferAdd(buf, base, cur - base);
6103 xmlBufferAdd(buf, BAD_CAST "&gt;", 4);
6104 cur++;
6105 base = cur;
6106 } else if (*cur == '&') {
6107 if (base != cur)
6108 xmlBufferAdd(buf, base, cur - base);
6109 xmlBufferAdd(buf, BAD_CAST "&amp;", 5);
6110 cur++;
6111 base = cur;
6112 } else if ((*cur >= 0x80) && ((doc == NULL) ||
6113 (doc->encoding == NULL))) {
6114 /*
6115 * We assume we have UTF-8 content.
6116 */
6117 char tmp[10];
6118 int val = 0, l = 1;
6119
6120 if (base != cur)
6121 xmlBufferAdd(buf, base, cur - base);
6122 if (*cur < 0xC0) {
6123 xmlGenericError(xmlGenericErrorContext,
6124 "xmlAttrSerializeContent : input not UTF-8\n");
6125 if (doc != NULL)
6126 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6127 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6128 tmp[sizeof(tmp) - 1] = 0;
6129 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6130 cur++;
6131 base = cur;
6132 continue;
6133 } else if (*cur < 0xE0) {
6134 val = (cur[0]) & 0x1F;
6135 val <<= 6;
6136 val |= (cur[1]) & 0x3F;
6137 l = 2;
6138 } else if (*cur < 0xF0) {
6139 val = (cur[0]) & 0x0F;
6140 val <<= 6;
6141 val |= (cur[1]) & 0x3F;
6142 val <<= 6;
6143 val |= (cur[2]) & 0x3F;
6144 l = 3;
6145 } else if (*cur < 0xF8) {
6146 val = (cur[0]) & 0x07;
6147 val <<= 6;
6148 val |= (cur[1]) & 0x3F;
6149 val <<= 6;
6150 val |= (cur[2]) & 0x3F;
6151 val <<= 6;
6152 val |= (cur[3]) & 0x3F;
6153 l = 4;
6154 }
6155 if ((l == 1) || (!IS_CHAR(val))) {
6156 xmlGenericError(xmlGenericErrorContext,
6157 "xmlAttrSerializeContent : char out of range\n");
6158 if (doc != NULL)
6159 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6160 snprintf(tmp, sizeof(tmp), "&#%d;", *cur);
6161 tmp[sizeof(tmp) - 1] = 0;
6162 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6163 cur++;
6164 base = cur;
6165 continue;
6166 }
6167 /*
6168 * We could do multiple things here. Just save
6169 * as a char ref
6170 */
6171 snprintf(tmp, sizeof(tmp), "&#x%X;", val);
6172 tmp[sizeof(tmp) - 1] = 0;
6173 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
6174 cur += l;
6175 base = cur;
6176 } else {
6177 cur++;
6178 }
6179 }
6180 if (base != cur)
6181 xmlBufferAdd(buf, base, cur - base);
6182 break;
6183 case XML_ENTITY_REF_NODE:
6184 xmlBufferAdd(buf, BAD_CAST "&", 1);
6185 xmlBufferAdd(buf, children->name, xmlStrlen(children->name));
6186 xmlBufferAdd(buf, BAD_CAST ";", 1);
6187 break;
6188 default:
6189 /* should not happen unless we have a badly built tree */
6190 break;
6191 }
6192 children = children->next;
6193 }
6194}
6195
6196/**
Owen Taylor3473f882001-02-23 17:55:21 +00006197 * xmlAttrDump:
6198 * @buf: the XML buffer output
6199 * @doc: the document
6200 * @cur: the attribute pointer
6201 *
6202 * Dump an XML attribute
6203 */
6204static void
6205xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +00006206 if (cur == NULL) {
6207#ifdef DEBUG_TREE
6208 xmlGenericError(xmlGenericErrorContext,
6209 "xmlAttrDump : property == NULL\n");
6210#endif
6211 return;
6212 }
6213 xmlBufferWriteChar(buf, " ");
6214 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6215 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6216 xmlBufferWriteChar(buf, ":");
6217 }
6218 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006219 xmlBufferWriteChar(buf, "=\"");
6220 xmlAttrSerializeContent(buf, doc, cur);
6221 xmlBufferWriteChar(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006222}
6223
6224/**
6225 * xmlAttrListDump:
6226 * @buf: the XML buffer output
6227 * @doc: the document
6228 * @cur: the first attribute pointer
6229 *
6230 * Dump a list of XML attributes
6231 */
6232static void
6233xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
6234 if (cur == NULL) {
6235#ifdef DEBUG_TREE
6236 xmlGenericError(xmlGenericErrorContext,
6237 "xmlAttrListDump : property == NULL\n");
6238#endif
6239 return;
6240 }
6241 while (cur != NULL) {
6242 xmlAttrDump(buf, doc, cur);
6243 cur = cur->next;
6244 }
6245}
6246
6247
6248
6249/**
6250 * xmlNodeListDump:
6251 * @buf: the XML buffer output
6252 * @doc: the document
6253 * @cur: the first node
6254 * @level: the imbrication level for indenting
6255 * @format: is formatting allowed
6256 *
6257 * Dump an XML node list, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006258 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6259 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006260 */
6261static void
6262xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6263 int format) {
6264 int i;
6265
6266 if (cur == NULL) {
6267#ifdef DEBUG_TREE
6268 xmlGenericError(xmlGenericErrorContext,
6269 "xmlNodeListDump : node == NULL\n");
6270#endif
6271 return;
6272 }
6273 while (cur != NULL) {
6274 if ((format) && (xmlIndentTreeOutput) &&
6275 (cur->type == XML_ELEMENT_NODE))
6276 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006277 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006278 xmlNodeDump(buf, doc, cur, level, format);
6279 if (format) {
6280 xmlBufferWriteChar(buf, "\n");
6281 }
6282 cur = cur->next;
6283 }
6284}
6285
6286/**
6287 * xmlNodeDump:
6288 * @buf: the XML buffer output
6289 * @doc: the document
6290 * @cur: the current node
6291 * @level: the imbrication level for indenting
6292 * @format: is formatting allowed
6293 *
6294 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006295 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6296 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006297 */
6298void
6299xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
6300 int format) {
6301 int i;
6302 xmlNodePtr tmp;
6303
6304 if (cur == NULL) {
6305#ifdef DEBUG_TREE
6306 xmlGenericError(xmlGenericErrorContext,
6307 "xmlNodeDump : node == NULL\n");
6308#endif
6309 return;
6310 }
6311 if (cur->type == XML_XINCLUDE_START)
6312 return;
6313 if (cur->type == XML_XINCLUDE_END)
6314 return;
6315 if (cur->type == XML_DTD_NODE) {
6316 xmlDtdDump(buf, (xmlDtdPtr) cur);
6317 return;
6318 }
6319 if (cur->type == XML_ELEMENT_DECL) {
6320 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
6321 return;
6322 }
Daniel Veillard78d12092001-10-11 09:12:24 +00006323 if (cur->type == XML_ATTRIBUTE_NODE){
6324 xmlAttrDump(buf, doc, (xmlAttrPtr)cur);
6325 return;
6326 }
Owen Taylor3473f882001-02-23 17:55:21 +00006327 if (cur->type == XML_ATTRIBUTE_DECL) {
6328 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
6329 return;
6330 }
6331 if (cur->type == XML_ENTITY_DECL) {
6332 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
6333 return;
6334 }
6335 if (cur->type == XML_TEXT_NODE) {
6336 if (cur->content != NULL) {
6337 if ((cur->name == xmlStringText) ||
6338 (cur->name != xmlStringTextNoenc)) {
6339 xmlChar *buffer;
6340
Owen Taylor3473f882001-02-23 17:55:21 +00006341 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006342 if (buffer != NULL) {
6343 xmlBufferWriteCHAR(buf, buffer);
6344 xmlFree(buffer);
6345 }
6346 } else {
6347 /*
6348 * Disable escaping, needed for XSLT
6349 */
Owen Taylor3473f882001-02-23 17:55:21 +00006350 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006351 }
6352 }
6353 return;
6354 }
6355 if (cur->type == XML_PI_NODE) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006356 xmlBufferWriteChar(buf, "<?");
6357 xmlBufferWriteCHAR(buf, cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006358 if (cur->content != NULL) {
Daniel Veillard2c748c62002-01-16 15:37:50 +00006359 xmlBufferWriteChar(buf, " ");
Daniel Veillard2c748c62002-01-16 15:37:50 +00006360 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006361 }
Daniel Veillard2c748c62002-01-16 15:37:50 +00006362 xmlBufferWriteChar(buf, "?>");
Owen Taylor3473f882001-02-23 17:55:21 +00006363 return;
6364 }
6365 if (cur->type == XML_COMMENT_NODE) {
6366 if (cur->content != NULL) {
6367 xmlBufferWriteChar(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006368 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006369 xmlBufferWriteChar(buf, "-->");
6370 }
6371 return;
6372 }
6373 if (cur->type == XML_ENTITY_REF_NODE) {
6374 xmlBufferWriteChar(buf, "&");
6375 xmlBufferWriteCHAR(buf, cur->name);
6376 xmlBufferWriteChar(buf, ";");
6377 return;
6378 }
6379 if (cur->type == XML_CDATA_SECTION_NODE) {
6380 xmlBufferWriteChar(buf, "<![CDATA[");
6381 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006382 xmlBufferWriteCHAR(buf, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006383 xmlBufferWriteChar(buf, "]]>");
6384 return;
6385 }
6386
6387 if (format == 1) {
6388 tmp = cur->children;
6389 while (tmp != NULL) {
6390 if ((tmp->type == XML_TEXT_NODE) ||
6391 (tmp->type == XML_ENTITY_REF_NODE)) {
6392 format = 0;
6393 break;
6394 }
6395 tmp = tmp->next;
6396 }
6397 }
6398 xmlBufferWriteChar(buf, "<");
6399 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6400 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6401 xmlBufferWriteChar(buf, ":");
6402 }
6403
6404 xmlBufferWriteCHAR(buf, cur->name);
6405 if (cur->nsDef)
6406 xmlNsListDump(buf, cur->nsDef);
6407 if (cur->properties != NULL)
6408 xmlAttrListDump(buf, doc, cur->properties);
6409
Daniel Veillard7db37732001-07-12 01:20:08 +00006410 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6411 (cur->children == NULL) &&
Owen Taylor3473f882001-02-23 17:55:21 +00006412 (!xmlSaveNoEmptyTags)) {
6413 xmlBufferWriteChar(buf, "/>");
6414 return;
6415 }
6416 xmlBufferWriteChar(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006417 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006418 xmlChar *buffer;
6419
Owen Taylor3473f882001-02-23 17:55:21 +00006420 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006421 if (buffer != NULL) {
6422 xmlBufferWriteCHAR(buf, buffer);
6423 xmlFree(buffer);
6424 }
6425 }
6426 if (cur->children != NULL) {
6427 if (format) xmlBufferWriteChar(buf, "\n");
6428 xmlNodeListDump(buf, doc, cur->children,
6429 (level >= 0?level+1:-1), format);
6430 if ((xmlIndentTreeOutput) && (format))
6431 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006432 xmlBufferWriteChar(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006433 }
6434 xmlBufferWriteChar(buf, "</");
6435 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6436 xmlBufferWriteCHAR(buf, cur->ns->prefix);
6437 xmlBufferWriteChar(buf, ":");
6438 }
6439
6440 xmlBufferWriteCHAR(buf, cur->name);
6441 xmlBufferWriteChar(buf, ">");
6442}
6443
6444/**
6445 * xmlElemDump:
6446 * @f: the FILE * for the output
6447 * @doc: the document
6448 * @cur: the current node
6449 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006450 * Dump an XML/HTML node, recursive behaviour, children are printed too.
Owen Taylor3473f882001-02-23 17:55:21 +00006451 */
6452void
6453xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
6454 xmlBufferPtr buf;
6455
6456 if (cur == NULL) {
6457#ifdef DEBUG_TREE
6458 xmlGenericError(xmlGenericErrorContext,
6459 "xmlElemDump : cur == NULL\n");
6460#endif
6461 return;
6462 }
Owen Taylor3473f882001-02-23 17:55:21 +00006463#ifdef DEBUG_TREE
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006464 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006465 xmlGenericError(xmlGenericErrorContext,
6466 "xmlElemDump : doc == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006467 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00006468#endif
Daniel Veillard78d12092001-10-11 09:12:24 +00006469
Owen Taylor3473f882001-02-23 17:55:21 +00006470 buf = xmlBufferCreate();
6471 if (buf == NULL) return;
6472 if ((doc != NULL) &&
6473 (doc->type == XML_HTML_DOCUMENT_NODE)) {
6474#ifdef LIBXML_HTML_ENABLED
6475 htmlNodeDump(buf, doc, cur);
6476#else
6477 xmlGenericError(xmlGenericErrorContext,
6478 "HTML support not compiled in\n");
6479#endif /* LIBXML_HTML_ENABLED */
6480 } else
6481 xmlNodeDump(buf, doc, cur, 0, 1);
6482 xmlBufferDump(f, buf);
6483 xmlBufferFree(buf);
6484}
6485
6486/************************************************************************
6487 * *
6488 * Dumping XML tree content to an I/O output buffer *
6489 * *
6490 ************************************************************************/
6491
Owen Taylor3473f882001-02-23 17:55:21 +00006492static void
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006493xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6494 int level, int format, const char *encoding);
6495static void
Owen Taylor3473f882001-02-23 17:55:21 +00006496xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6497 int level, int format, const char *encoding);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006498static void
6499xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6500 xmlNodePtr cur, int level, int format, const char *encoding);
6501
Owen Taylor3473f882001-02-23 17:55:21 +00006502/**
6503 * xmlNsDumpOutput:
6504 * @buf: the XML buffer output
6505 * @cur: a namespace
6506 *
6507 * Dump a local Namespace definition.
6508 * Should be called in the context of attributes dumps.
6509 */
6510static void
6511xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6512 if (cur == NULL) {
6513#ifdef DEBUG_TREE
6514 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006515 "xmlNsDumpOutput : Ns == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006516#endif
6517 return;
6518 }
6519 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillard6f46f6c2002-08-01 12:22:24 +00006520 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
6521 return;
6522
Owen Taylor3473f882001-02-23 17:55:21 +00006523 /* Within the context of an element attributes */
6524 if (cur->prefix != NULL) {
6525 xmlOutputBufferWriteString(buf, " xmlns:");
6526 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
6527 } else
6528 xmlOutputBufferWriteString(buf, " xmlns");
6529 xmlOutputBufferWriteString(buf, "=");
6530 xmlBufferWriteQuotedString(buf->buffer, cur->href);
6531 }
6532}
6533
6534/**
6535 * xmlNsListDumpOutput:
6536 * @buf: the XML buffer output
6537 * @cur: the first namespace
6538 *
6539 * Dump a list of local Namespace definitions.
6540 * Should be called in the context of attributes dumps.
6541 */
6542static void
6543xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
6544 while (cur != NULL) {
6545 xmlNsDumpOutput(buf, cur);
6546 cur = cur->next;
6547 }
6548}
6549
6550/**
6551 * xmlDtdDumpOutput:
6552 * @buf: the XML buffer output
6553 * @doc: the document
6554 * @encoding: an optional encoding string
6555 *
6556 * Dump the XML document DTD, if any.
6557 */
6558static void
6559xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
6560 if (dtd == NULL) {
6561#ifdef DEBUG_TREE
6562 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006563 "xmlDtdDumpOutput : no internal subset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006564#endif
6565 return;
6566 }
6567 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
6568 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
6569 if (dtd->ExternalID != NULL) {
6570 xmlOutputBufferWriteString(buf, " PUBLIC ");
6571 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
6572 xmlOutputBufferWriteString(buf, " ");
6573 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6574 } else if (dtd->SystemID != NULL) {
6575 xmlOutputBufferWriteString(buf, " SYSTEM ");
6576 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
6577 }
6578 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
6579 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
6580 xmlOutputBufferWriteString(buf, ">");
6581 return;
6582 }
6583 xmlOutputBufferWriteString(buf, " [\n");
6584 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
6585 xmlOutputBufferWriteString(buf, "]>");
6586}
6587
6588/**
6589 * xmlAttrDumpOutput:
6590 * @buf: the XML buffer output
6591 * @doc: the document
6592 * @cur: the attribute pointer
6593 * @encoding: an optional encoding string
6594 *
6595 * Dump an XML attribute
6596 */
6597static void
6598xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006599 const char *encoding ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006600 if (cur == NULL) {
6601#ifdef DEBUG_TREE
6602 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006603 "xmlAttrDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006604#endif
6605 return;
6606 }
6607 xmlOutputBufferWriteString(buf, " ");
6608 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6609 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6610 xmlOutputBufferWriteString(buf, ":");
6611 }
6612 xmlOutputBufferWriteString(buf, (const char *)cur->name);
Daniel Veillarda6d05382002-02-13 13:07:41 +00006613 xmlOutputBufferWriteString(buf, "=\"");
6614 xmlAttrSerializeContent(buf->buffer, doc, cur);
6615 xmlOutputBufferWriteString(buf, "\"");
Owen Taylor3473f882001-02-23 17:55:21 +00006616}
6617
6618/**
6619 * xmlAttrListDumpOutput:
6620 * @buf: the XML buffer output
6621 * @doc: the document
6622 * @cur: the first attribute pointer
6623 * @encoding: an optional encoding string
6624 *
6625 * Dump a list of XML attributes
6626 */
6627static void
6628xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6629 xmlAttrPtr cur, const char *encoding) {
6630 if (cur == NULL) {
6631#ifdef DEBUG_TREE
6632 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006633 "xmlAttrListDumpOutput : property == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006634#endif
6635 return;
6636 }
6637 while (cur != NULL) {
6638 xmlAttrDumpOutput(buf, doc, cur, encoding);
6639 cur = cur->next;
6640 }
6641}
6642
6643
6644
6645/**
6646 * xmlNodeListDumpOutput:
6647 * @buf: the XML buffer output
6648 * @doc: the document
6649 * @cur: the first node
6650 * @level: the imbrication level for indenting
6651 * @format: is formatting allowed
6652 * @encoding: an optional encoding string
6653 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006654 * Dump an XML node list, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006655 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6656 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006657 */
6658static void
6659xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
6660 xmlNodePtr cur, int level, int format, const char *encoding) {
6661 int i;
6662
6663 if (cur == NULL) {
6664#ifdef DEBUG_TREE
6665 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006666 "xmlNodeListDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006667#endif
6668 return;
6669 }
6670 while (cur != NULL) {
6671 if ((format) && (xmlIndentTreeOutput) &&
6672 (cur->type == XML_ELEMENT_NODE))
6673 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006674 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006675 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006676 if (format) {
6677 xmlOutputBufferWriteString(buf, "\n");
6678 }
6679 cur = cur->next;
6680 }
6681}
6682
6683/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006684 * xmlNodeDumpOutputInternal:
Owen Taylor3473f882001-02-23 17:55:21 +00006685 * @buf: the XML buffer output
6686 * @doc: the document
6687 * @cur: the current node
6688 * @level: the imbrication level for indenting
6689 * @format: is formatting allowed
6690 * @encoding: an optional encoding string
6691 *
Daniel Veillardd1640922001-12-17 15:30:10 +00006692 * Dump an XML node, recursive behaviour, children are printed too.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006693 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6694 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006695 */
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006696static void
6697xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc,
6698 xmlNodePtr cur, int level, int format, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00006699 int i;
6700 xmlNodePtr tmp;
6701
6702 if (cur == NULL) {
6703#ifdef DEBUG_TREE
6704 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00006705 "xmlNodeDumpOutput : node == NULL\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006706#endif
6707 return;
6708 }
6709 if (cur->type == XML_XINCLUDE_START)
6710 return;
6711 if (cur->type == XML_XINCLUDE_END)
6712 return;
6713 if (cur->type == XML_DTD_NODE) {
6714 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
6715 return;
6716 }
6717 if (cur->type == XML_ELEMENT_DECL) {
6718 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
6719 return;
6720 }
6721 if (cur->type == XML_ATTRIBUTE_DECL) {
6722 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
6723 return;
6724 }
6725 if (cur->type == XML_ENTITY_DECL) {
6726 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
6727 return;
6728 }
6729 if (cur->type == XML_TEXT_NODE) {
6730 if (cur->content != NULL) {
6731 if ((cur->name == xmlStringText) ||
6732 (cur->name != xmlStringTextNoenc)) {
6733 xmlChar *buffer;
6734
Owen Taylor3473f882001-02-23 17:55:21 +00006735 if (encoding == NULL)
6736 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6737 else
6738 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006739 if (buffer != NULL) {
6740 xmlOutputBufferWriteString(buf, (const char *)buffer);
6741 xmlFree(buffer);
6742 }
6743 } else {
6744 /*
6745 * Disable escaping, needed for XSLT
6746 */
Owen Taylor3473f882001-02-23 17:55:21 +00006747 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006748 }
6749 }
6750
6751 return;
6752 }
6753 if (cur->type == XML_PI_NODE) {
6754 if (cur->content != NULL) {
6755 xmlOutputBufferWriteString(buf, "<?");
6756 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6757 if (cur->content != NULL) {
6758 xmlOutputBufferWriteString(buf, " ");
Owen Taylor3473f882001-02-23 17:55:21 +00006759 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006760 }
6761 xmlOutputBufferWriteString(buf, "?>");
6762 } else {
6763 xmlOutputBufferWriteString(buf, "<?");
6764 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6765 xmlOutputBufferWriteString(buf, "?>");
6766 }
6767 return;
6768 }
6769 if (cur->type == XML_COMMENT_NODE) {
6770 if (cur->content != NULL) {
6771 xmlOutputBufferWriteString(buf, "<!--");
Owen Taylor3473f882001-02-23 17:55:21 +00006772 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006773 xmlOutputBufferWriteString(buf, "-->");
6774 }
6775 return;
6776 }
6777 if (cur->type == XML_ENTITY_REF_NODE) {
6778 xmlOutputBufferWriteString(buf, "&");
6779 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6780 xmlOutputBufferWriteString(buf, ";");
6781 return;
6782 }
6783 if (cur->type == XML_CDATA_SECTION_NODE) {
6784 xmlOutputBufferWriteString(buf, "<![CDATA[");
6785 if (cur->content != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006786 xmlOutputBufferWriteString(buf, (const char *)cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006787 xmlOutputBufferWriteString(buf, "]]>");
6788 return;
6789 }
6790
6791 if (format == 1) {
6792 tmp = cur->children;
6793 while (tmp != NULL) {
6794 if ((tmp->type == XML_TEXT_NODE) ||
6795 (tmp->type == XML_ENTITY_REF_NODE)) {
6796 format = 0;
6797 break;
6798 }
6799 tmp = tmp->next;
6800 }
6801 }
6802 xmlOutputBufferWriteString(buf, "<");
6803 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6804 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6805 xmlOutputBufferWriteString(buf, ":");
6806 }
6807
6808 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6809 if (cur->nsDef)
6810 xmlNsListDumpOutput(buf, cur->nsDef);
6811 if (cur->properties != NULL)
6812 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
6813
Daniel Veillard7db37732001-07-12 01:20:08 +00006814 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
6815 (cur->children == NULL) && (!xmlSaveNoEmptyTags)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006816 xmlOutputBufferWriteString(buf, "/>");
6817 return;
6818 }
6819 xmlOutputBufferWriteString(buf, ">");
Daniel Veillard7db37732001-07-12 01:20:08 +00006820 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006821 xmlChar *buffer;
6822
Owen Taylor3473f882001-02-23 17:55:21 +00006823 if (encoding == NULL)
6824 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
6825 else
6826 buffer = xmlEncodeSpecialChars(doc, cur->content);
Owen Taylor3473f882001-02-23 17:55:21 +00006827 if (buffer != NULL) {
6828 xmlOutputBufferWriteString(buf, (const char *)buffer);
6829 xmlFree(buffer);
6830 }
6831 }
6832 if (cur->children != NULL) {
6833 if (format) xmlOutputBufferWriteString(buf, "\n");
6834 xmlNodeListDumpOutput(buf, doc, cur->children,
6835 (level >= 0?level+1:-1), format, encoding);
6836 if ((xmlIndentTreeOutput) && (format))
6837 for (i = 0;i < level;i++)
Aleksey Sanin23002562002-05-24 07:18:40 +00006838 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
Owen Taylor3473f882001-02-23 17:55:21 +00006839 }
6840 xmlOutputBufferWriteString(buf, "</");
6841 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
6842 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
6843 xmlOutputBufferWriteString(buf, ":");
6844 }
6845
6846 xmlOutputBufferWriteString(buf, (const char *)cur->name);
6847 xmlOutputBufferWriteString(buf, ">");
6848}
6849
6850/**
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006851 * xmlNodeDumpOutput:
6852 * @buf: the XML buffer output
6853 * @doc: the document
6854 * @cur: the current node
6855 * @level: the imbrication level for indenting
6856 * @format: is formatting allowed
6857 * @encoding: an optional encoding string
6858 *
6859 * Dump an XML node, recursive behaviour, children are printed too.
6860 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6861 * or xmlKeepBlanksDefault(0) was called
6862 */
6863void
6864xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
6865 int level, int format, const char *encoding) {
6866#ifdef LIBXML_HTML_ENABLED
6867 xmlDtdPtr dtd;
6868 int is_xhtml = 0;
6869
6870 dtd = xmlGetIntSubset(doc);
6871 if (dtd != NULL) {
6872 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6873 if (is_xhtml < 0) is_xhtml = 0;
6874 if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) &&
6875 (cur->type == XML_ELEMENT_NODE) &&
6876 (xmlStrEqual(cur->name, BAD_CAST "html"))) {
6877 if (encoding != NULL)
6878 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
6879 else
6880 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
6881 }
6882 }
6883
6884 if (is_xhtml)
6885 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
6886 else
6887#endif
6888 xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding);
6889}
6890
6891/**
Owen Taylor3473f882001-02-23 17:55:21 +00006892 * xmlDocContentDumpOutput:
6893 * @buf: the XML buffer output
6894 * @cur: the document
6895 * @encoding: an optional encoding string
6896 * @format: should formatting spaces been added
6897 *
6898 * Dump an XML document.
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00006899 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
6900 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00006901 */
6902static void
6903xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
6904 const char *encoding, int format) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006905#ifdef LIBXML_HTML_ENABLED
6906 xmlDtdPtr dtd;
6907 int is_xhtml = 0;
6908#endif
6909
Owen Taylor3473f882001-02-23 17:55:21 +00006910 xmlOutputBufferWriteString(buf, "<?xml version=");
6911 if (cur->version != NULL)
6912 xmlBufferWriteQuotedString(buf->buffer, cur->version);
6913 else
6914 xmlOutputBufferWriteString(buf, "\"1.0\"");
6915 if (encoding == NULL) {
6916 if (cur->encoding != NULL)
6917 encoding = (const char *) cur->encoding;
6918 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
6919 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
6920 }
6921 if (encoding != NULL) {
6922 xmlOutputBufferWriteString(buf, " encoding=");
6923 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
6924 }
6925 switch (cur->standalone) {
6926 case 0:
6927 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
6928 break;
6929 case 1:
6930 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
6931 break;
6932 }
6933 xmlOutputBufferWriteString(buf, "?>\n");
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006934
6935#ifdef LIBXML_HTML_ENABLED
6936 dtd = xmlGetIntSubset(cur);
6937 if (dtd != NULL) {
6938 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
6939 if (is_xhtml < 0) is_xhtml = 0;
6940 }
6941 if (is_xhtml) {
6942 if (encoding != NULL)
6943 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
6944 else
6945 htmlSetMetaEncoding(cur, BAD_CAST "UTF-8");
6946 }
6947#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006948 if (cur->children != NULL) {
6949 xmlNodePtr child = cur->children;
6950
6951 while (child != NULL) {
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006952#ifdef LIBXML_HTML_ENABLED
6953 if (is_xhtml)
6954 xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
6955 else
6956#endif
6957 xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding);
Owen Taylor3473f882001-02-23 17:55:21 +00006958 xmlOutputBufferWriteString(buf, "\n");
6959 child = child->next;
6960 }
6961 }
6962}
6963
Daniel Veillardd5c2f922002-11-21 14:10:52 +00006964#ifdef LIBXML_HTML_ENABLED
6965/************************************************************************
6966 * *
6967 * Functions specific to XHTML serialization *
6968 * *
6969 ************************************************************************/
6970
6971#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
6972 "-//W3C//DTD XHTML 1.0 Strict//EN"
6973#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
6974 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
6975#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
6976 "-//W3C//DTD XHTML 1.0 Frameset//EN"
6977#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
6978 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
6979#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
6980 "-//W3C//DTD XHTML 1.0 Transitional//EN"
6981#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
6982 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
6983
6984#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
6985/**
6986 * xmlIsXHTML:
6987 * @systemID: the system identifier
6988 * @publicID: the public identifier
6989 *
6990 * Try to find if the document correspond to an XHTML DTD
6991 *
6992 * Returns 1 if true, 0 if not and -1 in case of error
6993 */
6994int
6995xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
6996 if ((systemID == NULL) && (publicID == NULL))
6997 return(-1);
6998 if (publicID != NULL) {
6999 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
7000 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
7001 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
7002 }
7003 if (systemID != NULL) {
7004 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
7005 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
7006 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
7007 }
7008 return(0);
7009}
7010
7011/**
7012 * xhtmlIsEmpty:
7013 * @node: the node
7014 *
7015 * Check if a node is an empty xhtml node
7016 *
7017 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
7018 */
7019static int
7020xhtmlIsEmpty(xmlNodePtr node) {
7021 if (node == NULL)
7022 return(-1);
7023 if (node->type != XML_ELEMENT_NODE)
7024 return(0);
7025 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
7026 return(0);
7027 if (node->children != NULL)
7028 return(0);
7029 switch (node->name[0]) {
7030 case 'a':
7031 if (xmlStrEqual(node->name, BAD_CAST "area"))
7032 return(1);
7033 return(0);
7034 case 'b':
7035 if (xmlStrEqual(node->name, BAD_CAST "br"))
7036 return(1);
7037 if (xmlStrEqual(node->name, BAD_CAST "base"))
7038 return(1);
7039 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
7040 return(1);
7041 return(0);
7042 case 'c':
7043 if (xmlStrEqual(node->name, BAD_CAST "col"))
7044 return(1);
7045 return(0);
7046 case 'f':
7047 if (xmlStrEqual(node->name, BAD_CAST "frame"))
7048 return(1);
7049 return(0);
7050 case 'h':
7051 if (xmlStrEqual(node->name, BAD_CAST "hr"))
7052 return(1);
7053 return(0);
7054 case 'i':
7055 if (xmlStrEqual(node->name, BAD_CAST "img"))
7056 return(1);
7057 if (xmlStrEqual(node->name, BAD_CAST "input"))
7058 return(1);
7059 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
7060 return(1);
7061 return(0);
7062 case 'l':
7063 if (xmlStrEqual(node->name, BAD_CAST "link"))
7064 return(1);
7065 return(0);
7066 case 'm':
7067 if (xmlStrEqual(node->name, BAD_CAST "meta"))
7068 return(1);
7069 return(0);
7070 case 'p':
7071 if (xmlStrEqual(node->name, BAD_CAST "param"))
7072 return(1);
7073 return(0);
7074 }
7075 return(0);
7076}
7077
7078/**
7079 * xhtmlAttrListDumpOutput:
7080 * @buf: the XML buffer output
7081 * @doc: the document
7082 * @cur: the first attribute pointer
7083 * @encoding: an optional encoding string
7084 *
7085 * Dump a list of XML attributes
7086 */
7087static void
7088xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7089 xmlAttrPtr cur, const char *encoding) {
7090 xmlAttrPtr xml_lang = NULL;
7091 xmlAttrPtr lang = NULL;
7092 xmlAttrPtr name = NULL;
7093 xmlAttrPtr id = NULL;
7094
7095 if (cur == NULL) {
7096#ifdef DEBUG_TREE
7097 xmlGenericError(xmlGenericErrorContext,
7098 "xmlAttrListDumpOutput : property == NULL\n");
7099#endif
7100 return;
7101 }
7102 while (cur != NULL) {
7103 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
7104 id = cur;
7105 else
7106 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
7107 name = cur;
7108 else
7109 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
7110 lang = cur;
7111 else
7112 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
7113 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
7114 xml_lang = cur;
7115 else if ((cur->ns == NULL) &&
7116 ((cur->children == NULL) ||
7117 (cur->children->content == NULL) ||
7118 (cur->children->content[0] == 0)) &&
7119 (htmlIsBooleanAttr(cur->name))) {
7120 if (cur->children != NULL)
7121 xmlFreeNode(cur->children);
7122 cur->children = xmlNewText(cur->name);
7123 if (cur->children != NULL)
7124 cur->children->parent = (xmlNodePtr) cur;
7125 }
7126 xmlAttrDumpOutput(buf, doc, cur, encoding);
7127 cur = cur->next;
7128 }
7129 /*
7130 * C.8
7131 */
7132 if ((name != NULL) && (id == NULL)) {
7133 xmlOutputBufferWriteString(buf, " id=\"");
7134 xmlAttrSerializeContent(buf->buffer, doc, name);
7135 xmlOutputBufferWriteString(buf, "\"");
7136 }
7137 /*
7138 * C.7.
7139 */
7140 if ((lang != NULL) && (xml_lang == NULL)) {
7141 xmlOutputBufferWriteString(buf, " xml:lang=\"");
7142 xmlAttrSerializeContent(buf->buffer, doc, lang);
7143 xmlOutputBufferWriteString(buf, "\"");
7144 } else
7145 if ((xml_lang != NULL) && (lang == NULL)) {
7146 xmlOutputBufferWriteString(buf, " lang=\"");
7147 xmlAttrSerializeContent(buf->buffer, doc, xml_lang);
7148 xmlOutputBufferWriteString(buf, "\"");
7149 }
7150}
7151
7152/**
7153 * xhtmlNodeListDumpOutput:
7154 * @buf: the XML buffer output
7155 * @doc: the XHTML document
7156 * @cur: the first node
7157 * @level: the imbrication level for indenting
7158 * @format: is formatting allowed
7159 * @encoding: an optional encoding string
7160 *
7161 * Dump an XML node list, recursive behaviour, children are printed too.
7162 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7163 * or xmlKeepBlanksDefault(0) was called
7164 */
7165static void
7166xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
7167 xmlNodePtr cur, int level, int format, const char *encoding) {
7168 int i;
7169
7170 if (cur == NULL) {
7171#ifdef DEBUG_TREE
7172 xmlGenericError(xmlGenericErrorContext,
7173 "xhtmlNodeListDumpOutput : node == NULL\n");
7174#endif
7175 return;
7176 }
7177 while (cur != NULL) {
7178 if ((format) && (xmlIndentTreeOutput) &&
7179 (cur->type == XML_ELEMENT_NODE))
7180 for (i = 0;i < level;i++)
7181 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7182 xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
7183 if (format) {
7184 xmlOutputBufferWriteString(buf, "\n");
7185 }
7186 cur = cur->next;
7187 }
7188}
7189
7190/**
7191 * xhtmlNodeDumpOutput:
7192 * @buf: the XML buffer output
7193 * @doc: the XHTML document
7194 * @cur: the current node
7195 * @level: the imbrication level for indenting
7196 * @format: is formatting allowed
7197 * @encoding: an optional encoding string
7198 *
7199 * Dump an XHTML node, recursive behaviour, children are printed too.
7200 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7201 * or xmlKeepBlanksDefault(0) was called
7202 */
7203static void
7204xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
7205 int level, int format, const char *encoding) {
7206 int i;
7207 xmlNodePtr tmp;
7208
7209 if (cur == NULL) {
7210#ifdef DEBUG_TREE
7211 xmlGenericError(xmlGenericErrorContext,
7212 "xmlNodeDumpOutput : node == NULL\n");
7213#endif
7214 return;
7215 }
7216 if (cur->type == XML_XINCLUDE_START)
7217 return;
7218 if (cur->type == XML_XINCLUDE_END)
7219 return;
7220 if (cur->type == XML_DTD_NODE) {
7221 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
7222 return;
7223 }
7224 if (cur->type == XML_ELEMENT_DECL) {
7225 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
7226 return;
7227 }
7228 if (cur->type == XML_ATTRIBUTE_DECL) {
7229 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
7230 return;
7231 }
7232 if (cur->type == XML_ENTITY_DECL) {
7233 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
7234 return;
7235 }
7236 if (cur->type == XML_TEXT_NODE) {
7237 if (cur->content != NULL) {
7238 if ((cur->name == xmlStringText) ||
7239 (cur->name != xmlStringTextNoenc)) {
7240 xmlChar *buffer;
7241
7242 if (encoding == NULL)
7243 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7244 else
7245 buffer = xmlEncodeSpecialChars(doc, cur->content);
7246 if (buffer != NULL) {
7247 xmlOutputBufferWriteString(buf, (const char *)buffer);
7248 xmlFree(buffer);
7249 }
7250 } else {
7251 /*
7252 * Disable escaping, needed for XSLT
7253 */
7254 xmlOutputBufferWriteString(buf, (const char *) cur->content);
7255 }
7256 }
7257
7258 return;
7259 }
7260 if (cur->type == XML_PI_NODE) {
7261 if (cur->content != NULL) {
7262 xmlOutputBufferWriteString(buf, "<?");
7263 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7264 if (cur->content != NULL) {
7265 xmlOutputBufferWriteString(buf, " ");
7266 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7267 }
7268 xmlOutputBufferWriteString(buf, "?>");
7269 } else {
7270 xmlOutputBufferWriteString(buf, "<?");
7271 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7272 xmlOutputBufferWriteString(buf, "?>");
7273 }
7274 return;
7275 }
7276 if (cur->type == XML_COMMENT_NODE) {
7277 if (cur->content != NULL) {
7278 xmlOutputBufferWriteString(buf, "<!--");
7279 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7280 xmlOutputBufferWriteString(buf, "-->");
7281 }
7282 return;
7283 }
7284 if (cur->type == XML_ENTITY_REF_NODE) {
7285 xmlOutputBufferWriteString(buf, "&");
7286 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7287 xmlOutputBufferWriteString(buf, ";");
7288 return;
7289 }
7290 if (cur->type == XML_CDATA_SECTION_NODE) {
7291 xmlOutputBufferWriteString(buf, "<![CDATA[");
7292 if (cur->content != NULL)
7293 xmlOutputBufferWriteString(buf, (const char *)cur->content);
7294 xmlOutputBufferWriteString(buf, "]]>");
7295 return;
7296 }
7297
7298 if (format == 1) {
7299 tmp = cur->children;
7300 while (tmp != NULL) {
7301 if ((tmp->type == XML_TEXT_NODE) ||
7302 (tmp->type == XML_ENTITY_REF_NODE)) {
7303 format = 0;
7304 break;
7305 }
7306 tmp = tmp->next;
7307 }
7308 }
7309 xmlOutputBufferWriteString(buf, "<");
7310 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7311 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7312 xmlOutputBufferWriteString(buf, ":");
7313 }
7314
7315 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7316 if (cur->nsDef)
7317 xmlNsListDumpOutput(buf, cur->nsDef);
7318 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
7319 (cur->ns == NULL) && (cur->nsDef == NULL))) {
7320 /*
7321 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
7322 */
7323 xmlOutputBufferWriteString(buf,
7324 " xmlns=\"http://www.w3.org/1999/xhtml\"");
7325 }
7326 if (cur->properties != NULL)
7327 xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
7328
7329 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
7330 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
7331 (xhtmlIsEmpty(cur) == 1)) {
7332 /*
7333 * C.2. Empty Elements
7334 */
7335 xmlOutputBufferWriteString(buf, " />");
7336 } else {
7337 /*
7338 * C.3. Element Minimization and Empty Element Content
7339 */
7340 xmlOutputBufferWriteString(buf, "></");
7341 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7342 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7343 xmlOutputBufferWriteString(buf, ":");
7344 }
7345 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7346 xmlOutputBufferWriteString(buf, ">");
7347 }
7348 return;
7349 }
7350 xmlOutputBufferWriteString(buf, ">");
7351 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
7352 xmlChar *buffer;
7353
7354 if (encoding == NULL)
7355 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
7356 else
7357 buffer = xmlEncodeSpecialChars(doc, cur->content);
7358 if (buffer != NULL) {
7359 xmlOutputBufferWriteString(buf, (const char *)buffer);
7360 xmlFree(buffer);
7361 }
7362 }
7363
7364 /*
7365 * 4.8. Script and Style elements
7366 */
7367 if ((cur->type == XML_ELEMENT_NODE) &&
7368 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
7369 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
7370 ((cur->ns == NULL) ||
7371 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
7372 xmlNodePtr child = cur->children;
7373
7374 while (child != NULL) {
7375 if ((child->type == XML_TEXT_NODE) ||
7376 (child->type == XML_CDATA_SECTION_NODE)) {
7377 xmlOutputBufferWriteString(buf, "<![CDATA[");
7378 if (child->content != NULL)
7379 xmlOutputBufferWriteString(buf,
7380 (const char *)child->content);
7381 xmlOutputBufferWriteString(buf, "]]>");
7382 } else {
7383 xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding);
7384 }
7385 child = child->next;
7386 }
7387 } else if (cur->children != NULL) {
7388 if (format) xmlOutputBufferWriteString(buf, "\n");
7389 xhtmlNodeListDumpOutput(buf, doc, cur->children,
7390 (level >= 0?level+1:-1), format, encoding);
7391 if ((xmlIndentTreeOutput) && (format))
7392 for (i = 0;i < level;i++)
7393 xmlOutputBufferWriteString(buf, xmlTreeIndentString);
7394 }
7395 xmlOutputBufferWriteString(buf, "</");
7396 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
7397 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
7398 xmlOutputBufferWriteString(buf, ":");
7399 }
7400
7401 xmlOutputBufferWriteString(buf, (const char *)cur->name);
7402 xmlOutputBufferWriteString(buf, ">");
7403}
7404#endif
7405
Owen Taylor3473f882001-02-23 17:55:21 +00007406/************************************************************************
7407 * *
7408 * Saving functions front-ends *
7409 * *
7410 ************************************************************************/
7411
7412/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00007413 * xmlDocDumpFormatMemoryEnc:
Owen Taylor3473f882001-02-23 17:55:21 +00007414 * @out_doc: Document to generate XML text from
7415 * @doc_txt_ptr: Memory pointer for allocated XML text
7416 * @doc_txt_len: Length of the generated XML text
7417 * @txt_encoding: Character encoding to use when generating XML text
7418 * @format: should formatting spaces been added
7419 *
7420 * Dump the current DOM tree into memory using the character encoding specified
7421 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007422 * allocated memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007423 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7424 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007425 */
7426
7427void
7428xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007429 int * doc_txt_len, const char * txt_encoding,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007430 int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007431 int dummy = 0;
7432
7433 xmlCharEncoding doc_charset;
7434 xmlOutputBufferPtr out_buff = NULL;
7435 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
7436
7437 if (doc_txt_len == NULL) {
7438 doc_txt_len = &dummy; /* Continue, caller just won't get length */
7439 }
7440
7441 if (doc_txt_ptr == NULL) {
7442 *doc_txt_len = 0;
7443 xmlGenericError(xmlGenericErrorContext,
7444 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
7445 return;
7446 }
7447
7448 *doc_txt_ptr = NULL;
7449 *doc_txt_len = 0;
7450
7451 if (out_doc == NULL) {
7452 /* No document, no output */
7453 xmlGenericError(xmlGenericErrorContext,
7454 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
7455 return;
7456 }
7457
7458 /*
7459 * Validate the encoding value, if provided.
7460 * This logic is copied from xmlSaveFileEnc.
7461 */
7462
7463 if (txt_encoding == NULL)
7464 txt_encoding = (const char *) out_doc->encoding;
7465 if (txt_encoding != NULL) {
7466 doc_charset = xmlParseCharEncoding(txt_encoding);
7467
7468 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
7469 xmlGenericError(xmlGenericErrorContext,
7470 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
7471 return;
7472
7473 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
7474 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
7475 if ( conv_hdlr == NULL ) {
7476 xmlGenericError(xmlGenericErrorContext,
7477 "%s: %s %s '%s'\n",
7478 "xmlDocDumpFormatMemoryEnc",
7479 "Failed to identify encoding handler for",
7480 "character set",
7481 txt_encoding);
7482 return;
7483 }
7484 }
7485 }
7486
7487 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
7488 xmlGenericError(xmlGenericErrorContext,
7489 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
7490 return;
7491 }
7492
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007493 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007494 xmlOutputBufferFlush(out_buff);
7495 if (out_buff->conv != NULL) {
7496 *doc_txt_len = out_buff->conv->use;
7497 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
7498 } else {
7499 *doc_txt_len = out_buff->buffer->use;
7500 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
7501 }
7502 (void)xmlOutputBufferClose(out_buff);
7503
7504 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
7505 *doc_txt_len = 0;
7506 xmlGenericError(xmlGenericErrorContext,
7507 "xmlDocDumpFormatMemoryEnc: %s\n",
7508 "Failed to allocate memory for document text representation.");
7509 }
7510
7511 return;
7512}
7513
7514/**
7515 * xmlDocDumpMemory:
7516 * @cur: the document
7517 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007518 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007519 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007520 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007521 * It's up to the caller to free the memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007522 */
7523void
7524xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
7525 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
7526}
7527
7528/**
7529 * xmlDocDumpFormatMemory:
7530 * @cur: the document
7531 * @mem: OUT: the memory pointer
Daniel Veillard60087f32001-10-10 09:45:09 +00007532 * @size: OUT: the memory length
Owen Taylor3473f882001-02-23 17:55:21 +00007533 * @format: should formatting spaces been added
7534 *
7535 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007536 * Dump an XML document in memory and return the #xmlChar * and it's size.
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007537 * It's up to the caller to free the memory with xmlFree().
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00007538 * Note that format = 1 provide node indenting only if xmlIndentTreeOutput = 1
7539 * or xmlKeepBlanksDefault(0) was called
Owen Taylor3473f882001-02-23 17:55:21 +00007540 */
7541void
7542xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
7543 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
7544}
7545
7546/**
7547 * xmlDocDumpMemoryEnc:
7548 * @out_doc: Document to generate XML text from
7549 * @doc_txt_ptr: Memory pointer for allocated XML text
7550 * @doc_txt_len: Length of the generated XML text
7551 * @txt_encoding: Character encoding to use when generating XML text
7552 *
7553 * Dump the current DOM tree into memory using the character encoding specified
7554 * by the caller. Note it is up to the caller of this function to free the
Daniel Veillardbd9afb52002-09-25 22:25:35 +00007555 * allocated memory with xmlFree().
Owen Taylor3473f882001-02-23 17:55:21 +00007556 */
7557
7558void
7559xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
7560 int * doc_txt_len, const char * txt_encoding) {
7561 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007562 txt_encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007563}
7564
7565/**
7566 * xmlGetDocCompressMode:
7567 * @doc: the document
7568 *
7569 * get the compression ratio for a document, ZLIB based
7570 * Returns 0 (uncompressed) to 9 (max compression)
7571 */
7572int
7573xmlGetDocCompressMode (xmlDocPtr doc) {
7574 if (doc == NULL) return(-1);
7575 return(doc->compression);
7576}
7577
7578/**
7579 * xmlSetDocCompressMode:
7580 * @doc: the document
7581 * @mode: the compression ratio
7582 *
7583 * set the compression ratio for a document, ZLIB based
7584 * Correct values: 0 (uncompressed) to 9 (max compression)
7585 */
7586void
7587xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7588 if (doc == NULL) return;
7589 if (mode < 0) doc->compression = 0;
7590 else if (mode > 9) doc->compression = 9;
7591 else doc->compression = mode;
7592}
7593
7594/**
7595 * xmlGetCompressMode:
7596 *
7597 * get the default compression mode used, ZLIB based.
7598 * Returns 0 (uncompressed) to 9 (max compression)
7599 */
7600int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007601xmlGetCompressMode(void)
7602{
7603 return (xmlCompressMode);
Owen Taylor3473f882001-02-23 17:55:21 +00007604}
7605
7606/**
7607 * xmlSetCompressMode:
7608 * @mode: the compression ratio
7609 *
7610 * set the default compression mode used, ZLIB based
7611 * Correct values: 0 (uncompressed) to 9 (max compression)
7612 */
7613void
7614xmlSetCompressMode(int mode) {
7615 if (mode < 0) xmlCompressMode = 0;
7616 else if (mode > 9) xmlCompressMode = 9;
7617 else xmlCompressMode = mode;
7618}
7619
7620/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007621 * xmlDocFormatDump:
Owen Taylor3473f882001-02-23 17:55:21 +00007622 * @f: the FILE*
7623 * @cur: the document
Daniel Veillard9e412302002-06-10 15:59:44 +00007624 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007625 *
7626 * Dump an XML document to an open FILE.
7627 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007628 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007629 */
7630int
Daniel Veillard9e412302002-06-10 15:59:44 +00007631xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
Owen Taylor3473f882001-02-23 17:55:21 +00007632 xmlOutputBufferPtr buf;
7633 const char * encoding;
7634 xmlCharEncodingHandlerPtr handler = NULL;
7635 int ret;
7636
7637 if (cur == NULL) {
7638#ifdef DEBUG_TREE
7639 xmlGenericError(xmlGenericErrorContext,
7640 "xmlDocDump : document == NULL\n");
7641#endif
7642 return(-1);
7643 }
7644 encoding = (const char *) cur->encoding;
7645
7646 if (encoding != NULL) {
7647 xmlCharEncoding enc;
7648
7649 enc = xmlParseCharEncoding(encoding);
7650
7651 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7652 xmlGenericError(xmlGenericErrorContext,
7653 "xmlDocDump: document not in UTF8\n");
7654 return(-1);
7655 }
7656 if (enc != XML_CHAR_ENCODING_UTF8) {
7657 handler = xmlFindCharEncodingHandler(encoding);
7658 if (handler == NULL) {
7659 xmlFree((char *) cur->encoding);
7660 cur->encoding = NULL;
7661 }
7662 }
7663 }
7664 buf = xmlOutputBufferCreateFile(f, handler);
7665 if (buf == NULL) return(-1);
Daniel Veillard9e412302002-06-10 15:59:44 +00007666 xmlDocContentDumpOutput(buf, cur, NULL, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007667
7668 ret = xmlOutputBufferClose(buf);
7669 return(ret);
7670}
7671
7672/**
Daniel Veillard9e412302002-06-10 15:59:44 +00007673 * xmlDocDump:
7674 * @f: the FILE*
7675 * @cur: the document
7676 *
7677 * Dump an XML document to an open FILE.
7678 *
7679 * returns: the number of bytes written or -1 in case of failure.
7680 */
7681int
7682xmlDocDump(FILE *f, xmlDocPtr cur) {
7683 return(xmlDocFormatDump (f, cur, 0));
7684}
7685
7686/**
Owen Taylor3473f882001-02-23 17:55:21 +00007687 * xmlSaveFileTo:
7688 * @buf: an output I/O buffer
7689 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007690 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Owen Taylor3473f882001-02-23 17:55:21 +00007691 *
7692 * Dump an XML document to an I/O buffer.
7693 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007694 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007695 */
7696int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007697xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
Owen Taylor3473f882001-02-23 17:55:21 +00007698 int ret;
7699
7700 if (buf == NULL) return(0);
Daniel Veillard1731d6a2001-04-10 16:38:06 +00007701 xmlDocContentDumpOutput(buf, cur, encoding, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00007702 ret = xmlOutputBufferClose(buf);
7703 return(ret);
7704}
7705
7706/**
Daniel Veillardeefd4492001-04-28 16:55:50 +00007707 * xmlSaveFormatFileTo:
7708 * @buf: an output I/O buffer
7709 * @cur: the document
Daniel Veillardd1640922001-12-17 15:30:10 +00007710 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
Daniel Veillardeefd4492001-04-28 16:55:50 +00007711 * @format: should formatting spaces been added
7712 *
7713 * Dump an XML document to an I/O buffer.
7714 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007715 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardeefd4492001-04-28 16:55:50 +00007716 */
7717int
CET 2001 Daniel Veillard5a37bde2001-11-01 14:31:22 +00007718xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) {
Daniel Veillardeefd4492001-04-28 16:55:50 +00007719 int ret;
7720
7721 if (buf == NULL) return(0);
7722 xmlDocContentDumpOutput(buf, cur, encoding, format);
7723 ret = xmlOutputBufferClose(buf);
7724 return(ret);
7725}
7726
7727/**
Daniel Veillardf012a642001-07-23 19:10:52 +00007728 * xmlSaveFormatFileEnc
7729 * @filename: the filename or URL to output
7730 * @cur: the document being saved
7731 * @encoding: the name of the encoding to use or NULL.
7732 * @format: should formatting spaces be added.
Daniel Veillardd1640922001-12-17 15:30:10 +00007733 *
7734 * Returns the number of bytes written or -1 in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00007735 */
7736int
Daniel Veillardf012a642001-07-23 19:10:52 +00007737xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
7738 const char * encoding, int format ) {
Owen Taylor3473f882001-02-23 17:55:21 +00007739 xmlOutputBufferPtr buf;
7740 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillard81418e32001-05-22 15:08:55 +00007741 xmlCharEncoding enc;
Owen Taylor3473f882001-02-23 17:55:21 +00007742 int ret;
7743
Daniel Veillardfb25a512002-01-13 20:32:08 +00007744 if (encoding == NULL)
7745 encoding = (const char *) cur->encoding;
7746
Owen Taylor3473f882001-02-23 17:55:21 +00007747 if (encoding != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00007748
7749 enc = xmlParseCharEncoding(encoding);
7750 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
7751 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd1640922001-12-17 15:30:10 +00007752 "xmlSaveFormatFileEnc: document not in UTF8\n");
Owen Taylor3473f882001-02-23 17:55:21 +00007753 return(-1);
7754 }
7755 if (enc != XML_CHAR_ENCODING_UTF8) {
7756 handler = xmlFindCharEncodingHandler(encoding);
Daniel Veillard81418e32001-05-22 15:08:55 +00007757 if (handler == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007758 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007759 }
7760 }
7761
Daniel Veillardf012a642001-07-23 19:10:52 +00007762#ifdef HAVE_ZLIB_H
7763 if (cur->compression < 0) cur->compression = xmlCompressMode;
7764#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007765 /*
7766 * save the content to a temp buffer.
7767 */
Daniel Veillardf012a642001-07-23 19:10:52 +00007768 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Owen Taylor3473f882001-02-23 17:55:21 +00007769 if (buf == NULL) return(-1);
7770
Daniel Veillardf012a642001-07-23 19:10:52 +00007771 xmlDocContentDumpOutput(buf, cur, encoding, format);
Owen Taylor3473f882001-02-23 17:55:21 +00007772
7773 ret = xmlOutputBufferClose(buf);
7774 return(ret);
7775}
7776
Daniel Veillardf012a642001-07-23 19:10:52 +00007777
7778/**
7779 * xmlSaveFileEnc:
7780 * @filename: the filename (or URL)
7781 * @cur: the document
7782 * @encoding: the name of an encoding (or NULL)
7783 *
7784 * Dump an XML document, converting it to the given encoding
7785 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007786 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillardf012a642001-07-23 19:10:52 +00007787 */
7788int
7789xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
7790 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
7791}
7792
Owen Taylor3473f882001-02-23 17:55:21 +00007793/**
Daniel Veillard67fee942001-04-26 18:59:03 +00007794 * xmlSaveFormatFile:
Owen Taylor3473f882001-02-23 17:55:21 +00007795 * @filename: the filename (or URL)
7796 * @cur: the document
Daniel Veillard67fee942001-04-26 18:59:03 +00007797 * @format: should formatting spaces been added
Owen Taylor3473f882001-02-23 17:55:21 +00007798 *
7799 * Dump an XML document to a file. Will use compression if
7800 * compiled in and enabled. If @filename is "-" the stdout file is
Daniel Veillardd1640922001-12-17 15:30:10 +00007801 * used. If @format is set then the document will be indented on output.
Daniel Veillard67fee942001-04-26 18:59:03 +00007802 *
Daniel Veillardd1640922001-12-17 15:30:10 +00007803 * returns: the number of bytes written or -1 in case of failure.
Owen Taylor3473f882001-02-23 17:55:21 +00007804 */
7805int
Daniel Veillard67fee942001-04-26 18:59:03 +00007806xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007807 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
Owen Taylor3473f882001-02-23 17:55:21 +00007808}
7809
Daniel Veillard67fee942001-04-26 18:59:03 +00007810/**
7811 * xmlSaveFile:
7812 * @filename: the filename (or URL)
7813 * @cur: the document
7814 *
7815 * Dump an XML document to a file. Will use compression if
7816 * compiled in and enabled. If @filename is "-" the stdout file is
7817 * used.
Daniel Veillardd1640922001-12-17 15:30:10 +00007818 * returns: the number of bytes written or -1 in case of failure.
Daniel Veillard67fee942001-04-26 18:59:03 +00007819 */
7820int
7821xmlSaveFile(const char *filename, xmlDocPtr cur) {
Daniel Veillardf012a642001-07-23 19:10:52 +00007822 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
Daniel Veillard67fee942001-04-26 18:59:03 +00007823}
7824