blob: b0799bed3c2c7e2c69188d003ab2a105293d002f [file] [log] [blame]
Daniel Veillard260a68f1998-08-13 03:39:55 +00001/*
2 * tree.c : implemetation of access function for an XML tree.
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006 * Daniel.Veillard@w3.org
Daniel Veillardce6e98d2000-11-25 09:54:49 +00007 *
8 * 14 Nov 2000 ht - Changed the name of function xmlBufferWriteChar under VMS
9 * as it was similar to xmlBufferWriteCHAR when compiling without case
10 * sensitivity.
11 *
Daniel Veillard260a68f1998-08-13 03:39:55 +000012 */
13
Daniel Veillard7f7d1111999-09-22 09:46:25 +000014#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000015#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000016#else
Daniel Veillard151b1b01998-09-23 00:49:46 +000017#include "config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#endif
19
Daniel Veillard260a68f1998-08-13 03:39:55 +000020#include <stdio.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000021#include <string.h> /* for memset() only ! */
22
Daniel Veillard7f7d1111999-09-22 09:46:25 +000023#ifdef HAVE_CTYPE_H
24#include <ctype.h>
25#endif
26#ifdef HAVE_STDLIB_H
27#include <stdlib.h>
28#endif
Daniel Veillard151b1b01998-09-23 00:49:46 +000029#ifdef HAVE_ZLIB_H
30#include <zlib.h>
31#endif
32
Daniel Veillard361d8452000-04-03 19:48:13 +000033#include <libxml/xmlmemory.h>
34#include <libxml/tree.h>
35#include <libxml/parser.h>
36#include <libxml/entities.h>
37#include <libxml/valid.h>
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000038#include <libxml/xmlerror.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000039
Daniel Veillarddd6b3671999-09-23 22:19:22 +000040static xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardcf461992000-03-14 18:30:20 +000041static xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
Daniel Veillard260a68f1998-08-13 03:39:55 +000042int oldXMLWDcompatibility = 0;
Daniel Veillardcf461992000-03-14 18:30:20 +000043int xmlIndentTreeOutput = 0;
Daniel Veillardf5c2c871999-12-01 09:51:45 +000044xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT;
Daniel Veillard260a68f1998-08-13 03:39:55 +000045
Daniel Veillard15a8df41998-09-24 19:15:06 +000046static int xmlCompressMode = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +000047static int xmlCheckDTD = 1;
Daniel Veillarde41f2b72000-01-30 20:00:07 +000048int xmlSaveNoEmptyTags = 0;
Daniel Veillard3e6d2372000-03-04 11:39:43 +000049
50#define IS_BLANK(c) \
51 (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
Daniel Veillard15a8df41998-09-24 19:15:06 +000052
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000053#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
Daniel Veillardcf461992000-03-14 18:30:20 +000054 xmlNodePtr ulccur = (n)->children; \
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000055 if (ulccur == NULL) { \
56 (n)->last = NULL; \
57 } else { \
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000058 while (ulccur->next != NULL) { \
59 ulccur->parent = (n); \
60 ulccur = ulccur->next; \
61 } \
62 ulccur->parent = (n); \
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000063 (n)->last = ulccur; \
Daniel Veillard1e346af1999-02-22 10:33:01 +000064}}
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000065
Daniel Veillardad8f99d2000-01-15 14:20:03 +000066/* #define DEBUG_BUFFER */
67/* #define DEBUG_TREE */
68
Daniel Veillard260a68f1998-08-13 03:39:55 +000069/************************************************************************
70 * *
71 * Allocation and deallocation of basic structures *
72 * *
73 ************************************************************************/
74
Daniel Veillard97b58771998-10-20 06:14:16 +000075/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +000076 * xmlSetBufferAllocationScheme:
77 * @scheme: allocation method to use
78 *
79 * Set the buffer allocation method. Types are
80 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
81 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
82 * improves performance
83 */
84void
85xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
86 xmlBufferAllocScheme = scheme;
87}
88
89/**
90 * xmlGetBufferAllocationScheme:
91 *
92 * Types are
93 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
94 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
95 * improves performance
96 *
97 * Returns the current allocation scheme
98 */
99xmlBufferAllocationScheme
100xmlGetBufferAllocationScheme() {
101 return xmlBufferAllocScheme;
102}
103
104/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000105 * xmlNewNs:
106 * @node: the element carrying the namespace
107 * @href: the URI associated
108 * @prefix: the prefix for the namespace
109 *
Daniel Veillard686d6b62000-01-03 11:08:02 +0000110 * Creation of a new Namespace. This function will refuse to create
111 * a namespace with a similar prefix than an existing one present on this
112 * node.
Daniel Veillarde0854c32000-08-27 21:12:29 +0000113 * We use href==NULL in the case of an element creation where the namespace
114 * was not defined.
Daniel Veillard686d6b62000-01-03 11:08:02 +0000115 * Returns returns a new namespace pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000116 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000117xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000118xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000119 xmlNsPtr cur;
120
Daniel Veillard260a68f1998-08-13 03:39:55 +0000121 /*
Daniel Veillardcf461992000-03-14 18:30:20 +0000122 * Allocate a new Namespace and fill the fields.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000123 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000124 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000125 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000126 xmlGenericError(xmlGenericErrorContext,
127 "xmlNewNs : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000128 return(NULL);
129 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000130 memset(cur, 0, sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000131 cur->type = XML_LOCAL_NAMESPACE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000132
Daniel Veillard260a68f1998-08-13 03:39:55 +0000133 if (href != NULL)
134 cur->href = xmlStrdup(href);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000135 if (prefix != NULL)
136 cur->prefix = xmlStrdup(prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000137
138 /*
139 * Add it at the end to preserve parsing order ...
Daniel Veillard686d6b62000-01-03 11:08:02 +0000140 * and checks for existing use of the prefix
Daniel Veillard260a68f1998-08-13 03:39:55 +0000141 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000142 if (node != NULL) {
143 if (node->nsDef == NULL) {
144 node->nsDef = cur;
145 } else {
146 xmlNsPtr prev = node->nsDef;
147
Daniel Veillard0142b842000-01-14 14:45:24 +0000148 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000149 (xmlStrEqual(prev->prefix, cur->prefix))) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000150 xmlFreeNs(cur);
151 return(NULL);
152 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000153 while (prev->next != NULL) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000154 prev = prev->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +0000155 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000156 (xmlStrEqual(prev->prefix, cur->prefix))) {
Daniel Veillard686d6b62000-01-03 11:08:02 +0000157 xmlFreeNs(cur);
158 return(NULL);
159 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000160 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000161 prev->next = cur;
162 }
163 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000164 return(cur);
165}
166
Daniel Veillard97b58771998-10-20 06:14:16 +0000167/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000168 * xmlSetNs:
169 * @node: a node in the document
170 * @ns: a namespace pointer
171 *
172 * Associate a namespace to a node, a posteriori.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000173 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000174void
175xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000176 if (node == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000177#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000178 xmlGenericError(xmlGenericErrorContext,
179 "xmlSetNs: node == NULL\n");
Daniel Veillardcf461992000-03-14 18:30:20 +0000180#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000181 return;
182 }
183 node->ns = ns;
184}
185
Daniel Veillard97b58771998-10-20 06:14:16 +0000186/**
187 * xmlFreeNs:
188 * @cur: the namespace pointer
189 *
190 * Free up the structures associated to a namespace
Daniel Veillard260a68f1998-08-13 03:39:55 +0000191 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000192void
193xmlFreeNs(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000194 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000195#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000196 xmlGenericError(xmlGenericErrorContext,
197 "xmlFreeNs : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000198#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000199 return;
200 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000201 if (cur->href != NULL) xmlFree((char *) cur->href);
202 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000203 memset(cur, -1, sizeof(xmlNs));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000204 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000205}
206
Daniel Veillard97b58771998-10-20 06:14:16 +0000207/**
208 * xmlFreeNsList:
209 * @cur: the first namespace pointer
210 *
211 * Free up all the structures associated to the chained namespaces.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000212 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000213void
214xmlFreeNsList(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000215 xmlNsPtr next;
216 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000217#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000218 xmlGenericError(xmlGenericErrorContext,
219 "xmlFreeNsList : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000220#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000221 return;
222 }
223 while (cur != NULL) {
224 next = cur->next;
225 xmlFreeNs(cur);
226 cur = next;
227 }
228}
229
Daniel Veillard97b58771998-10-20 06:14:16 +0000230/**
231 * xmlNewDtd:
232 * @doc: the document pointer
233 * @name: the DTD name
234 * @ExternalID: the external ID
235 * @SystemID: the system ID
236 *
Daniel Veillardcf461992000-03-14 18:30:20 +0000237 * Creation of a new DTD for the external subset. To create an
238 * internal subset, use xmlCreateIntSubset().
239 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000240 * Returns a pointer to the new DTD structure
Daniel Veillard260a68f1998-08-13 03:39:55 +0000241 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000242xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000243xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
244 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000245 xmlDtdPtr cur;
246
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000247 if ((doc != NULL) && (doc->extSubset != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000248#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000249 xmlGenericError(xmlGenericErrorContext,
250 "xmlNewDtd(%s): document %s already have a DTD %s\n",
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000251 /* !!! */ (char *) name, doc->name,
252 /* !!! */ (char *)doc->extSubset->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000253#endif
254 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000255 }
256
257 /*
258 * Allocate a new DTD and fill the fields.
259 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000260 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000261 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000262 xmlGenericError(xmlGenericErrorContext,
263 "xmlNewDtd : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000264 return(NULL);
265 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000266 memset(cur, 0 , sizeof(xmlDtd));
267 cur->type = XML_DTD_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000268
269 if (name != NULL)
270 cur->name = xmlStrdup(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000271 if (ExternalID != NULL)
272 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000273 if (SystemID != NULL)
274 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000275 if (doc != NULL)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000276 doc->extSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000277 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000278
279 return(cur);
280}
281
282/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000283 * xmlGetIntSubset:
284 * @doc: the document pointer
285 *
286 * Get the internal subset of a document
287 * Returns a pointer to the DTD structure or NULL if not found
288 */
289
290xmlDtdPtr
291xmlGetIntSubset(xmlDocPtr doc) {
292 xmlNodePtr cur;
293
294 if (doc == NULL)
295 return(NULL);
296 cur = doc->children;
297 while (cur != NULL) {
298 if (cur->type == XML_DTD_NODE)
299 return((xmlDtdPtr) cur);
300 cur = cur->next;
301 }
302 return((xmlDtdPtr) doc->intSubset);
303}
304
305/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000306 * xmlCreateIntSubset:
307 * @doc: the document pointer
308 * @name: the DTD name
309 * @ExternalID: the external ID
310 * @SystemID: the system ID
311 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000312 * Create the internal subset of a document
313 * Returns a pointer to the new DTD structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000314 */
315xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000316xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
317 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000318 xmlDtdPtr cur;
319
Daniel Veillardcf461992000-03-14 18:30:20 +0000320 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000321#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000322 xmlGenericError(xmlGenericErrorContext,
323
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000324 "xmlCreateIntSubset(): document %s already have an internal subset\n",
325 doc->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000326#endif
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000327 return(NULL);
328 }
329
330 /*
331 * Allocate a new DTD and fill the fields.
332 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000333 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000334 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000335 xmlGenericError(xmlGenericErrorContext,
336 "xmlNewDtd : malloc failed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000337 return(NULL);
338 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000339 memset(cur, 0, sizeof(xmlDtd));
340 cur->type = XML_DTD_NODE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000341
342 if (name != NULL)
343 cur->name = xmlStrdup(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000344 if (ExternalID != NULL)
345 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000346 if (SystemID != NULL)
347 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000348 if (doc != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000349 doc->intSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000350 cur->parent = doc;
351 cur->doc = doc;
352 if (doc->children == NULL) {
353 doc->children = (xmlNodePtr) cur;
354 doc->last = (xmlNodePtr) cur;
355 } else {
356 xmlNodePtr prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000357
Daniel Veillardb8f25c92000-08-19 19:52:36 +0000358 if (doc->type == XML_HTML_DOCUMENT_NODE) {
359 prev = doc->children;
360 prev->prev = (xmlNodePtr) cur;
361 cur->next = prev;
362 doc->children = (xmlNodePtr) cur;
363 } else {
364 prev = doc->last;
365 prev->next = (xmlNodePtr) cur;
366 cur->prev = prev;
367 doc->last = (xmlNodePtr) cur;
368 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000369 }
370 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000371 return(cur);
372}
373
Daniel Veillard97b58771998-10-20 06:14:16 +0000374/**
375 * xmlFreeDtd:
376 * @cur: the DTD structure to free up
377 *
378 * Free a DTD structure.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000379 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000380void
381xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000382 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000383#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000384 xmlGenericError(xmlGenericErrorContext,
385 "xmlFreeDtd : DTD == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000386#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000387 return;
388 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000389 if (cur->children != NULL) {
390 xmlNodePtr next, c = cur->children;
391
392 /*
393 * Cleanup all the DTD comments they are not in the Dtd
394 * indexes.
395 */
396 while (c != NULL) {
397 next = c->next;
398 if (c->type == XML_COMMENT_NODE) {
399 xmlUnlinkNode(c);
400 xmlFreeNode(c);
401 }
402 c = next;
403 }
404 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000405 if (cur->name != NULL) xmlFree((char *) cur->name);
406 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
407 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000408 /* TODO !!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000409 if (cur->notations != NULL)
410 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
Daniel Veillardcf461992000-03-14 18:30:20 +0000411
Daniel Veillard260a68f1998-08-13 03:39:55 +0000412 if (cur->elements != NULL)
Daniel Veillard3b9def11999-01-31 22:15:06 +0000413 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000414 if (cur->attributes != NULL)
415 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000416 if (cur->entities != NULL)
417 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
Daniel Veillard126f2792000-10-24 17:10:12 +0000418 if (cur->pentities != NULL)
419 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
Daniel Veillardcf461992000-03-14 18:30:20 +0000420
Daniel Veillard260a68f1998-08-13 03:39:55 +0000421 memset(cur, -1, sizeof(xmlDtd));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000422 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000423}
424
Daniel Veillard97b58771998-10-20 06:14:16 +0000425/**
426 * xmlNewDoc:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000427 * @version: xmlChar string giving the version of XML "1.0"
Daniel Veillard97b58771998-10-20 06:14:16 +0000428 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000429 * Returns a new document
Daniel Veillard260a68f1998-08-13 03:39:55 +0000430 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000431xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000432xmlNewDoc(const xmlChar *version) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000433 xmlDocPtr cur;
434
Daniel Veillard7eda8452000-10-14 23:38:43 +0000435 if (version == NULL)
436 version = (const xmlChar *) "1.0";
Daniel Veillard260a68f1998-08-13 03:39:55 +0000437
438 /*
439 * Allocate a new document and fill the fields.
440 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000441 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000442 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000443 xmlGenericError(xmlGenericErrorContext,
444 "xmlNewDoc : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000445 return(NULL);
446 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000447 memset(cur, 0, sizeof(xmlDoc));
Daniel Veillard33942841998-10-18 19:12:41 +0000448 cur->type = XML_DOCUMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000449
Daniel Veillard260a68f1998-08-13 03:39:55 +0000450 cur->version = xmlStrdup(version);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000451 cur->standalone = -1;
Daniel Veillard11a48ec1999-11-23 10:40:46 +0000452 cur->compression = -1; /* not initialized */
Daniel Veillardcf461992000-03-14 18:30:20 +0000453 cur->doc = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000454 return(cur);
455}
456
Daniel Veillard97b58771998-10-20 06:14:16 +0000457/**
458 * xmlFreeDoc:
459 * @cur: pointer to the document
460 * @:
461 *
462 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000463 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000464void
465xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000466 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000467#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000468 xmlGenericError(xmlGenericErrorContext,
469 "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000470#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000471 return;
472 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000473 if (cur->version != NULL) xmlFree((char *) cur->version);
474 if (cur->name != NULL) xmlFree((char *) cur->name);
475 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Daniel Veillardcf461992000-03-14 18:30:20 +0000476 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000477 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
478 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000479 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000480 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000481 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
Daniel Veillardcf461992000-03-14 18:30:20 +0000482 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000483 memset(cur, -1, sizeof(xmlDoc));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000484 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000485}
486
Daniel Veillard97b58771998-10-20 06:14:16 +0000487/**
Daniel Veillard16253641998-10-28 22:58:05 +0000488 * xmlStringLenGetNodeList:
489 * @doc: the document
490 * @value: the value of the text
Daniel Veillard1e346af1999-02-22 10:33:01 +0000491 * @len: the length of the string value
Daniel Veillard16253641998-10-28 22:58:05 +0000492 *
493 * Parse the value string and build the node list associated. Should
494 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000495 * Returns a pointer to the first child
Daniel Veillard16253641998-10-28 22:58:05 +0000496 */
497xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000498xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
Daniel Veillard16253641998-10-28 22:58:05 +0000499 xmlNodePtr ret = NULL, last = NULL;
500 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000501 xmlChar *val;
502 const xmlChar *cur = value;
503 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000504 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000505
506 if (value == NULL) return(NULL);
507
508 q = cur;
509 while ((*cur != 0) && (cur - value < len)) {
510 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000511 /*
512 * Save the current text.
513 */
Daniel Veillard16253641998-10-28 22:58:05 +0000514 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000515 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
516 xmlNodeAddContentLen(last, q, cur - q);
517 } else {
518 node = xmlNewDocTextLen(doc, q, cur - q);
519 if (node == NULL) return(ret);
520 if (last == NULL)
521 last = ret = node;
522 else {
523 last->next = node;
524 node->prev = last;
525 last = node;
526 }
Daniel Veillard16253641998-10-28 22:58:05 +0000527 }
528 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000529 /*
530 * Read the entity string
531 */
Daniel Veillard16253641998-10-28 22:58:05 +0000532 cur++;
533 q = cur;
534 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
535 if ((*cur == 0) || (cur - value >= len)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000536#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000537 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard011b63c1999-06-02 17:44:04 +0000538 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000539#endif
Daniel Veillard16253641998-10-28 22:58:05 +0000540 return(ret);
541 }
542 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000543 /*
544 * Predefined entities don't generate nodes
545 */
Daniel Veillard16253641998-10-28 22:58:05 +0000546 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000547 ent = xmlGetDocEntity(doc, val);
548 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000549 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000550 if (last == NULL) {
551 node = xmlNewDocText(doc, ent->content);
552 last = ret = node;
553 } else
554 xmlNodeAddContent(last, ent->content);
555
556 } else {
557 /*
558 * Create a new REFERENCE_REF node
559 */
560 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000561 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000562 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000563 return(ret);
564 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000565 if (last == NULL)
566 last = ret = node;
567 else {
568 last->next = node;
569 node->prev = last;
570 last = node;
571 }
Daniel Veillard16253641998-10-28 22:58:05 +0000572 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000573 xmlFree(val);
Daniel Veillard16253641998-10-28 22:58:05 +0000574 }
575 cur++;
576 q = cur;
577 } else
578 cur++;
579 }
580 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000581 /*
582 * Handle the last piece of text.
583 */
584 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
585 xmlNodeAddContentLen(last, q, cur - q);
586 } else {
587 node = xmlNewDocTextLen(doc, q, cur - q);
588 if (node == NULL) return(ret);
589 if (last == NULL)
590 last = ret = node;
591 else {
592 last->next = node;
593 node->prev = last;
594 last = node;
595 }
Daniel Veillard16253641998-10-28 22:58:05 +0000596 }
597 }
598 return(ret);
599}
600
601/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000602 * xmlStringGetNodeList:
603 * @doc: the document
604 * @value: the value of the attribute
605 *
606 * Parse the value string and build the node list associated. Should
607 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000608 * Returns a pointer to the first child
Daniel Veillardccb09631998-10-27 06:21:04 +0000609 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000610xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000611xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000612 xmlNodePtr ret = NULL, last = NULL;
613 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000614 xmlChar *val;
615 const xmlChar *cur = value;
616 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000617 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000618
619 if (value == NULL) return(NULL);
620
621 q = cur;
622 while (*cur != 0) {
623 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000624 /*
625 * Save the current text.
626 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000627 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000628 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
629 xmlNodeAddContentLen(last, q, cur - q);
630 } else {
631 node = xmlNewDocTextLen(doc, q, cur - q);
632 if (node == NULL) return(ret);
633 if (last == NULL)
634 last = ret = node;
635 else {
636 last->next = node;
637 node->prev = last;
638 last = node;
639 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000640 }
641 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000642 /*
643 * Read the entity string
644 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000645 cur++;
646 q = cur;
647 while ((*cur != 0) && (*cur != ';')) cur++;
648 if (*cur == 0) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000649#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000650 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardccb09631998-10-27 06:21:04 +0000651 "xmlStringGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000652#endif
Daniel Veillardccb09631998-10-27 06:21:04 +0000653 return(ret);
654 }
655 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000656 /*
657 * Predefined entities don't generate nodes
658 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000659 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000660 ent = xmlGetDocEntity(doc, val);
661 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000662 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000663 if (last == NULL) {
664 node = xmlNewDocText(doc, ent->content);
665 last = ret = node;
666 } else
667 xmlNodeAddContent(last, ent->content);
668
669 } else {
670 /*
671 * Create a new REFERENCE_REF node
672 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000673 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000674 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000675 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000676 return(ret);
677 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000678 if (last == NULL)
679 last = ret = node;
680 else {
681 last->next = node;
682 node->prev = last;
683 last = node;
684 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000685 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000686 xmlFree(val);
Daniel Veillardccb09631998-10-27 06:21:04 +0000687 }
688 cur++;
689 q = cur;
690 } else
691 cur++;
692 }
693 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000694 /*
695 * Handle the last piece of text.
696 */
697 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
698 xmlNodeAddContentLen(last, q, cur - q);
699 } else {
700 node = xmlNewDocTextLen(doc, q, cur - q);
701 if (node == NULL) return(ret);
702 if (last == NULL)
703 last = ret = node;
704 else {
705 last->next = node;
706 node->prev = last;
707 last = node;
708 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000709 }
710 }
711 return(ret);
712}
713
714/**
715 * xmlNodeListGetString:
716 * @doc: the document
717 * @list: a Node list
718 * @inLine: should we replace entity contents or show their external form
719 *
720 * Returns the string equivalent to the text contained in the Node list
721 * made of TEXTs and ENTITY_REFs
Daniel Veillard1e346af1999-02-22 10:33:01 +0000722 * Returns a pointer to the string copy, the calller must free it.
Daniel Veillardccb09631998-10-27 06:21:04 +0000723 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000724xmlChar *
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000725xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000726 xmlNodePtr node = list;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000727 xmlChar *ret = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000728 xmlEntityPtr ent;
729
730 if (list == NULL) return(NULL);
731
732 while (node != NULL) {
Daniel Veillard87b95392000-08-12 21:12:04 +0000733 if ((node->type == XML_TEXT_NODE) ||
734 (node->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard71b656e2000-01-05 14:46:17 +0000735 if (inLine) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000736#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000737 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000738#else
739 ret = xmlStrcat(ret, xmlBufferContent(node->content));
740#endif
741 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000742 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +0000743
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000744#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +0000745 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000746#else
747 buffer = xmlEncodeEntitiesReentrant(doc,
748 xmlBufferContent(node->content));
749#endif
Daniel Veillard14fff061999-06-22 21:49:07 +0000750 if (buffer != NULL) {
751 ret = xmlStrcat(ret, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000752 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +0000753 }
754 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000755 } else if (node->type == XML_ENTITY_REF_NODE) {
756 if (inLine) {
757 ent = xmlGetDocEntity(doc, node->name);
758 if (ent != NULL)
759 ret = xmlStrcat(ret, ent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000760 else {
761#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000762 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000763#else
764 ret = xmlStrcat(ret, xmlBufferContent(node->content));
765#endif
766 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000767 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000768 xmlChar buf[2];
Daniel Veillardccb09631998-10-27 06:21:04 +0000769 buf[0] = '&'; buf[1] = 0;
770 ret = xmlStrncat(ret, buf, 1);
771 ret = xmlStrcat(ret, node->name);
772 buf[0] = ';'; buf[1] = 0;
773 ret = xmlStrncat(ret, buf, 1);
774 }
775 }
776#if 0
777 else {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000778 xmlGenericError(xmlGenericErrorContext,
779 "xmlGetNodeListString : invalide node type %d\n",
Daniel Veillardccb09631998-10-27 06:21:04 +0000780 node->type);
781 }
782#endif
783 node = node->next;
784 }
785 return(ret);
786}
787
788/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000789 * xmlNodeListGetRawString:
790 * @doc: the document
791 * @list: a Node list
792 * @inLine: should we replace entity contents or show their external form
793 *
794 * Returns the string equivalent to the text contained in the Node list
795 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
796 * this function doesn't do any character encoding handling.
797 *
798 * Returns a pointer to the string copy, the calller must free it.
799 */
800xmlChar *
801xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
802 xmlNodePtr node = list;
803 xmlChar *ret = NULL;
804 xmlEntityPtr ent;
805
806 if (list == NULL) return(NULL);
807
808 while (node != NULL) {
809 if (node->type == XML_TEXT_NODE) {
810 if (inLine) {
811#ifndef XML_USE_BUFFER_CONTENT
812 ret = xmlStrcat(ret, node->content);
813#else
814 ret = xmlStrcat(ret, xmlBufferContent(node->content));
815#endif
816 } else {
817 xmlChar *buffer;
818
819#ifndef XML_USE_BUFFER_CONTENT
820 buffer = xmlEncodeSpecialChars(doc, node->content);
821#else
822 buffer = xmlEncodeSpecialChars(doc,
823 xmlBufferContent(node->content));
824#endif
825 if (buffer != NULL) {
826 ret = xmlStrcat(ret, buffer);
827 xmlFree(buffer);
828 }
829 }
830 } else if (node->type == XML_ENTITY_REF_NODE) {
831 if (inLine) {
832 ent = xmlGetDocEntity(doc, node->name);
833 if (ent != NULL)
834 ret = xmlStrcat(ret, ent->content);
835 else {
836#ifndef XML_USE_BUFFER_CONTENT
837 ret = xmlStrcat(ret, node->content);
838#else
839 ret = xmlStrcat(ret, xmlBufferContent(node->content));
840#endif
841 }
842 } else {
843 xmlChar buf[2];
844 buf[0] = '&'; buf[1] = 0;
845 ret = xmlStrncat(ret, buf, 1);
846 ret = xmlStrcat(ret, node->name);
847 buf[0] = ';'; buf[1] = 0;
848 ret = xmlStrncat(ret, buf, 1);
849 }
850 }
851#if 0
852 else {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000853 xmlGenericError(xmlGenericErrorContext,
854 "xmlGetNodeListString : invalide node type %d\n",
Daniel Veillardbe803962000-06-28 23:40:59 +0000855 node->type);
856 }
857#endif
858 node = node->next;
859 }
860 return(ret);
861}
862
863/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000864 * xmlNewProp:
865 * @node: the holding node
866 * @name: the name of the attribute
867 * @value: the value of the attribute
868 *
869 * Create a new property carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000870 * Returns a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000871 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000872xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000873xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000874 xmlAttrPtr cur;
875
876 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000877#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000878 xmlGenericError(xmlGenericErrorContext,
879 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000880#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000881 return(NULL);
882 }
883
884 /*
885 * Allocate a new property and fill the fields.
886 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000887 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000888 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000889 xmlGenericError(xmlGenericErrorContext,
890 "xmlNewProp : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000891 return(NULL);
892 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000893 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillard33942841998-10-18 19:12:41 +0000894 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000895
896 cur->parent = node;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000897 cur->name = xmlStrdup(name);
Daniel Veillard51e3b151999-11-12 17:02:31 +0000898 if (value != NULL) {
899 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +0000900 xmlNodePtr tmp;
901
Daniel Veillard51e3b151999-11-12 17:02:31 +0000902 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +0000903 cur->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000904 cur->last = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +0000905 tmp = cur->children;
906 while (tmp != NULL) {
907 tmp->parent = (xmlNodePtr) cur;
908 if (tmp->next == NULL)
909 cur->last = tmp;
910 tmp = tmp->next;
911 }
Daniel Veillard51e3b151999-11-12 17:02:31 +0000912 xmlFree(buffer);
913 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000914
915 /*
916 * Add it at the end to preserve parsing order ...
917 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000918 if (node != NULL) {
919 if (node->properties == NULL) {
920 node->properties = cur;
921 } else {
922 xmlAttrPtr prev = node->properties;
923
924 while (prev->next != NULL) prev = prev->next;
925 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000926 cur->prev = prev;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000927 }
928 }
929 return(cur);
930}
931
932/**
933 * xmlNewNsProp:
934 * @node: the holding node
935 * @ns: the namespace
936 * @name: the name of the attribute
937 * @value: the value of the attribute
938 *
939 * Create a new property tagged with a namespace and carried by a node.
940 * Returns a pointer to the attribute
941 */
942xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000943xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
944 const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000945 xmlAttrPtr cur;
946
947 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000948#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000949 xmlGenericError(xmlGenericErrorContext,
950 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000951#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +0000952 return(NULL);
953 }
954
955 /*
956 * Allocate a new property and fill the fields.
957 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000958 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000959 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000960 xmlGenericError(xmlGenericErrorContext,
961 "xmlNewProp : malloc failed\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +0000962 return(NULL);
963 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000964 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000965 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000966
967 cur->parent = node;
968 if (node != NULL)
969 cur->doc = node->doc;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000970 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000971 cur->name = xmlStrdup(name);
Daniel Veillardcf461992000-03-14 18:30:20 +0000972 if (value != NULL) {
973 xmlChar *buffer;
974 xmlNodePtr tmp;
975
976 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
977 cur->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000978 cur->last = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +0000979 tmp = cur->children;
980 while (tmp != NULL) {
981 tmp->parent = (xmlNodePtr) cur;
982 if (tmp->next == NULL)
983 cur->last = tmp;
984 tmp = tmp->next;
985 }
986 xmlFree(buffer);
987 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000988
989 /*
990 * Add it at the end to preserve parsing order ...
991 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000992 if (node != NULL) {
993 if (node->properties == NULL) {
994 node->properties = cur;
995 } else {
996 xmlAttrPtr prev = node->properties;
997
998 while (prev->next != NULL) prev = prev->next;
999 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00001000 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001001 }
1002 }
1003 return(cur);
1004}
1005
Daniel Veillard97b58771998-10-20 06:14:16 +00001006/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001007 * xmlNewDocProp:
1008 * @doc: the document
1009 * @name: the name of the attribute
1010 * @value: the value of the attribute
1011 *
1012 * Create a new property carried by a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001013 * Returns a pointer to the attribute
Daniel Veillardccb09631998-10-27 06:21:04 +00001014 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001015xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001016xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001017 xmlAttrPtr cur;
1018
1019 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001020#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001021 xmlGenericError(xmlGenericErrorContext,
1022 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001023#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00001024 return(NULL);
1025 }
1026
1027 /*
1028 * Allocate a new property and fill the fields.
1029 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001030 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001031 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001032 xmlGenericError(xmlGenericErrorContext,
1033 "xmlNewProp : malloc failed\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00001034 return(NULL);
1035 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001036 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001037 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardccb09631998-10-27 06:21:04 +00001038
Daniel Veillardcf461992000-03-14 18:30:20 +00001039 cur->name = xmlStrdup(name);
1040 cur->doc = doc;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001041 if (value != NULL) {
1042 xmlNodePtr tmp;
1043
Daniel Veillardcf461992000-03-14 18:30:20 +00001044 cur->children = xmlStringGetNodeList(doc, value);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001045 cur->last = NULL;
1046
1047 tmp = cur->children;
1048 while (tmp != NULL) {
1049 tmp->parent = (xmlNodePtr) cur;
1050 if (tmp->next == NULL)
1051 cur->last = tmp;
1052 tmp = tmp->next;
1053 }
1054 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001055 return(cur);
1056}
1057
1058/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001059 * xmlFreePropList:
1060 * @cur: the first property in the list
1061 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001062 * Free a property and all its siblings, all the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001063 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001064void
1065xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001066 xmlAttrPtr next;
1067 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001068#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001069 xmlGenericError(xmlGenericErrorContext,
1070 "xmlFreePropList : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001071#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001072 return;
1073 }
1074 while (cur != NULL) {
1075 next = cur->next;
1076 xmlFreeProp(cur);
1077 cur = next;
1078 }
1079}
1080
Daniel Veillard97b58771998-10-20 06:14:16 +00001081/**
1082 * xmlFreeProp:
Daniel Veillard686d6b62000-01-03 11:08:02 +00001083 * @cur: an attribute
Daniel Veillard97b58771998-10-20 06:14:16 +00001084 *
Daniel Veillard686d6b62000-01-03 11:08:02 +00001085 * Free one attribute, all the content is freed too
Daniel Veillard260a68f1998-08-13 03:39:55 +00001086 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001087void
1088xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001089 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001090#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001091 xmlGenericError(xmlGenericErrorContext,
1092 "xmlFreeProp : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001093#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001094 return;
1095 }
Daniel Veillard71b656e2000-01-05 14:46:17 +00001096 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardcf461992000-03-14 18:30:20 +00001097 if ((cur->parent != NULL) &&
1098 (xmlIsID(cur->parent->doc, cur->parent, cur)))
1099 xmlRemoveID(cur->parent->doc, cur);
Daniel Veillard6454aec1999-09-02 22:04:43 +00001100 if (cur->name != NULL) xmlFree((char *) cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001101 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001102 memset(cur, -1, sizeof(xmlAttr));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001103 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001104}
1105
Daniel Veillard97b58771998-10-20 06:14:16 +00001106/**
Daniel Veillard686d6b62000-01-03 11:08:02 +00001107 * xmlRemoveProp:
1108 * @cur: an attribute
1109 *
1110 * Unlink and free one attribute, all the content is freed too
1111 * Note this doesn't work for namespace definition attributes
1112 *
1113 * Returns 0 if success and -1 in case of error.
1114 */
1115int
1116xmlRemoveProp(xmlAttrPtr cur) {
1117 xmlAttrPtr tmp;
1118 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001119#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001120 xmlGenericError(xmlGenericErrorContext,
1121 "xmlRemoveProp : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001122#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001123 return(-1);
1124 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001125 if (cur->parent == NULL) {
1126#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001127 xmlGenericError(xmlGenericErrorContext,
1128 "xmlRemoveProp : cur->parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001129#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001130 return(-1);
1131 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001132 tmp = cur->parent->properties;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001133 if (tmp == cur) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001134 cur->parent->properties = cur->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001135 xmlFreeProp(cur);
1136 return(0);
1137 }
1138 while (tmp != NULL) {
1139 if (tmp->next == cur) {
1140 tmp->next = cur->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00001141 if (tmp->next != NULL)
1142 tmp->next->prev = tmp;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001143 xmlFreeProp(cur);
1144 return(0);
1145 }
1146 tmp = tmp->next;
1147 }
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001148#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001149 xmlGenericError(xmlGenericErrorContext,
1150 "xmlRemoveProp : attribute not owned by its node\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001151#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001152 return(-1);
1153}
1154
1155/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001156 * xmlNewPI:
1157 * @name: the processing instruction name
1158 * @content: the PI content
1159 *
1160 * Creation of a processing instruction element.
1161 * Returns a pointer to the new node object.
1162 */
1163xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001164xmlNewPI(const xmlChar *name, const xmlChar *content) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001165 xmlNodePtr cur;
1166
1167 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001168#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001169 xmlGenericError(xmlGenericErrorContext,
1170 "xmlNewPI : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001171#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001172 return(NULL);
1173 }
1174
1175 /*
1176 * Allocate a new node and fill the fields.
1177 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001178 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001179 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001180 xmlGenericError(xmlGenericErrorContext,
1181 "xmlNewPI : malloc failed\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00001182 return(NULL);
1183 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001184 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001185 cur->type = XML_PI_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001186
Daniel Veillardb96e6431999-08-29 21:02:19 +00001187 cur->name = xmlStrdup(name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001188 if (content != NULL) {
1189#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00001190 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001191#else
1192 cur->content = xmlBufferCreateSize(0);
1193 xmlBufferSetAllocationScheme(cur->content,
1194 xmlGetBufferAllocationScheme());
1195 xmlBufferAdd(cur->content, content, -1);
1196#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001197 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001198 return(cur);
1199}
1200
1201/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001202 * xmlNewNode:
1203 * @ns: namespace if any
1204 * @name: the node name
Daniel Veillard97b58771998-10-20 06:14:16 +00001205 *
Daniel Veillarde0854c32000-08-27 21:12:29 +00001206 * Creation of a new node element. @ns is optionnal (NULL).
1207 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001208 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001209 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001210xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001211xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001212 xmlNodePtr cur;
1213
1214 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001215#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001216 xmlGenericError(xmlGenericErrorContext,
1217 "xmlNewNode : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001218#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001219 return(NULL);
1220 }
1221
1222 /*
1223 * Allocate a new node and fill the fields.
1224 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001225 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001226 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001227 xmlGenericError(xmlGenericErrorContext,
1228 "xmlNewNode : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001229 return(NULL);
1230 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001231 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard33942841998-10-18 19:12:41 +00001232 cur->type = XML_ELEMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001233
Daniel Veillard260a68f1998-08-13 03:39:55 +00001234 cur->name = xmlStrdup(name);
1235 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001236 return(cur);
1237}
1238
Daniel Veillard97b58771998-10-20 06:14:16 +00001239/**
1240 * xmlNewDocNode:
1241 * @doc: the document
1242 * @ns: namespace if any
1243 * @name: the node name
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001244 * @content: the XML text content if any
Daniel Veillard97b58771998-10-20 06:14:16 +00001245 *
1246 * Creation of a new node element within a document. @ns and @content
1247 * are optionnal (NULL).
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001248 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1249 * references, but XML special chars need to be escaped first by using
1250 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1251 * need entities support.
1252 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001253 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001254 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001255xmlNodePtr
1256xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001257 const xmlChar *name, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001258 xmlNodePtr cur;
1259
Daniel Veillardccb09631998-10-27 06:21:04 +00001260 cur = xmlNewNode(ns, name);
1261 if (cur != NULL) {
1262 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001263 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001264 cur->children = xmlStringGetNodeList(doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001265 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001266 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001267 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001268 return(cur);
1269}
1270
1271
Daniel Veillard97b58771998-10-20 06:14:16 +00001272/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001273 * xmlNewDocRawNode:
1274 * @doc: the document
1275 * @ns: namespace if any
1276 * @name: the node name
1277 * @content: the text content if any
1278 *
1279 * Creation of a new node element within a document. @ns and @content
1280 * are optionnal (NULL).
1281 *
1282 * Returns a pointer to the new node object.
1283 */
1284xmlNodePtr
1285xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1286 const xmlChar *name, const xmlChar *content) {
1287 xmlNodePtr cur;
1288
1289 cur = xmlNewNode(ns, name);
1290 if (cur != NULL) {
1291 cur->doc = doc;
1292 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001293 cur->children = xmlNewDocText(doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001294 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001295 }
1296 }
1297 return(cur);
1298}
1299
Daniel Veillard2eac5032000-01-09 21:08:56 +00001300/**
1301 * xmlNewDocFragment:
1302 * @doc: the document owning the fragment
1303 *
1304 * Creation of a new Fragment node.
1305 * Returns a pointer to the new node object.
1306 */
1307xmlNodePtr
1308xmlNewDocFragment(xmlDocPtr doc) {
1309 xmlNodePtr cur;
1310
1311 /*
1312 * Allocate a new DocumentFragment node and fill the fields.
1313 */
1314 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1315 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001316 xmlGenericError(xmlGenericErrorContext,
1317 "xmlNewDocFragment : malloc failed\n");
Daniel Veillard2eac5032000-01-09 21:08:56 +00001318 return(NULL);
1319 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001320 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard2eac5032000-01-09 21:08:56 +00001321 cur->type = XML_DOCUMENT_FRAG_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001322
Daniel Veillard2eac5032000-01-09 21:08:56 +00001323 cur->doc = doc;
Daniel Veillard2eac5032000-01-09 21:08:56 +00001324 return(cur);
1325}
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001326
1327/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001328 * xmlNewText:
1329 * @content: the text content
1330 *
1331 * Creation of a new text node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001332 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001333 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001334xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001335xmlNewText(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001336 xmlNodePtr cur;
1337
1338 /*
1339 * Allocate a new node and fill the fields.
1340 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001341 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001342 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001343 xmlGenericError(xmlGenericErrorContext,
1344 "xmlNewText : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001345 return(NULL);
1346 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001347 memset(cur, 0, sizeof(xmlNode));
1348 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001349
Daniel Veillard260a68f1998-08-13 03:39:55 +00001350 cur->name = xmlStrdup(xmlStringText);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001351 if (content != NULL) {
1352#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001353 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001354#else
1355 cur->content = xmlBufferCreateSize(0);
1356 xmlBufferSetAllocationScheme(cur->content,
1357 xmlGetBufferAllocationScheme());
1358 xmlBufferAdd(cur->content, content, -1);
1359#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001360 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001361 return(cur);
1362}
1363
Daniel Veillard97b58771998-10-20 06:14:16 +00001364/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001365 * xmlNewTextChild:
1366 * @parent: the parent node
1367 * @ns: a namespace if any
1368 * @name: the name of the child
1369 * @content: the text content of the child if any.
1370 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001371 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001372 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1373 * a child TEXT node will be created containing the string content.
1374 *
1375 * Returns a pointer to the new node object.
1376 */
1377xmlNodePtr
1378xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1379 const xmlChar *name, const xmlChar *content) {
1380 xmlNodePtr cur, prev;
1381
1382 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001383#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001384 xmlGenericError(xmlGenericErrorContext,
1385 "xmlNewTextChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001386#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001387 return(NULL);
1388 }
1389
1390 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001391#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001392 xmlGenericError(xmlGenericErrorContext,
1393 "xmlNewTextChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001394#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001395 return(NULL);
1396 }
1397
1398 /*
1399 * Allocate a new node
1400 */
1401 if (ns == NULL)
1402 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1403 else
1404 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1405 if (cur == NULL) return(NULL);
1406
1407 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001408 * add the new element at the end of the children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001409 */
1410 cur->type = XML_ELEMENT_NODE;
1411 cur->parent = parent;
1412 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001413 if (parent->children == NULL) {
1414 parent->children = cur;
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001415 parent->last = cur;
1416 } else {
1417 prev = parent->last;
1418 prev->next = cur;
1419 cur->prev = prev;
1420 parent->last = cur;
1421 }
1422
1423 return(cur);
1424}
1425
1426/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001427 * xmlNewCharRef:
1428 * @doc: the document
1429 * @name: the char ref string, starting with # or "&# ... ;"
1430 *
1431 * Creation of a new character reference node.
1432 * Returns a pointer to the new node object.
1433 */
1434xmlNodePtr
1435xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1436 xmlNodePtr cur;
1437
1438 /*
1439 * Allocate a new node and fill the fields.
1440 */
1441 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1442 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001443 xmlGenericError(xmlGenericErrorContext,
1444 "xmlNewText : malloc failed\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00001445 return(NULL);
1446 }
1447 memset(cur, 0, sizeof(xmlNode));
1448 cur->type = XML_ENTITY_REF_NODE;
1449
1450 cur->doc = doc;
1451 if (name[0] == '&') {
1452 int len;
1453 name++;
1454 len = xmlStrlen(name);
1455 if (name[len - 1] == ';')
1456 cur->name = xmlStrndup(name, len - 1);
1457 else
1458 cur->name = xmlStrndup(name, len);
1459 } else
1460 cur->name = xmlStrdup(name);
1461 return(cur);
1462}
1463
1464/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001465 * xmlNewReference:
1466 * @doc: the document
1467 * @name: the reference name, or the reference string with & and ;
1468 *
1469 * Creation of a new reference node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001470 * Returns a pointer to the new node object.
Daniel Veillardccb09631998-10-27 06:21:04 +00001471 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001472xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001473xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001474 xmlNodePtr cur;
1475 xmlEntityPtr ent;
1476
1477 /*
1478 * Allocate a new node and fill the fields.
1479 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001480 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001481 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001482 xmlGenericError(xmlGenericErrorContext,
1483 "xmlNewText : malloc failed\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00001484 return(NULL);
1485 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001486 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001487 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001488
Daniel Veillard10c6a8f1998-10-28 01:00:12 +00001489 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +00001490 if (name[0] == '&') {
1491 int len;
1492 name++;
1493 len = xmlStrlen(name);
1494 if (name[len - 1] == ';')
1495 cur->name = xmlStrndup(name, len - 1);
1496 else
1497 cur->name = xmlStrndup(name, len);
1498 } else
1499 cur->name = xmlStrdup(name);
Daniel Veillardccb09631998-10-27 06:21:04 +00001500
1501 ent = xmlGetDocEntity(doc, cur->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001502 if (ent != NULL) {
1503#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00001504 cur->content = ent->content;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001505#else
1506 /*
1507 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1508 * a copy of this pointer. Let's hope we don't manipulate it
1509 * later
1510 */
1511 cur->content = xmlBufferCreateSize(0);
1512 xmlBufferSetAllocationScheme(cur->content,
1513 xmlGetBufferAllocationScheme());
1514 if (ent->content != NULL)
1515 xmlBufferAdd(cur->content, ent->content, -1);
1516#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001517 /*
1518 * The parent pointer in entity is a Dtd pointer and thus is NOT
1519 * updated. Not sure if this is 100% correct.
1520 * -George
1521 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001522 cur->children = (xmlNodePtr) ent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001523 cur->last = (xmlNodePtr) ent;
Daniel Veillardcf461992000-03-14 18:30:20 +00001524 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001525 return(cur);
1526}
1527
1528/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001529 * xmlNewDocText:
1530 * @doc: the document
1531 * @content: the text content
1532 *
1533 * Creation of a new text node within a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001534 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001535 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001536xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001537xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001538 xmlNodePtr cur;
1539
1540 cur = xmlNewText(content);
1541 if (cur != NULL) cur->doc = doc;
1542 return(cur);
1543}
1544
Daniel Veillard97b58771998-10-20 06:14:16 +00001545/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001546 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001547 * @content: the text content
1548 * @len: the text len.
1549 *
1550 * Creation of a new text node with an extra parameter for the content's lenght
Daniel Veillard1e346af1999-02-22 10:33:01 +00001551 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001552 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001553xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001554xmlNewTextLen(const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001555 xmlNodePtr cur;
1556
1557 /*
1558 * Allocate a new node and fill the fields.
1559 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001560 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001561 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001562 xmlGenericError(xmlGenericErrorContext,
1563 "xmlNewText : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001564 return(NULL);
1565 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001566 memset(cur, 0, sizeof(xmlNode));
1567 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001568
Daniel Veillard260a68f1998-08-13 03:39:55 +00001569 cur->name = xmlStrdup(xmlStringText);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001570 if (content != NULL) {
1571#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001572 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001573#else
1574 cur->content = xmlBufferCreateSize(len);
1575 xmlBufferSetAllocationScheme(cur->content,
1576 xmlGetBufferAllocationScheme());
1577 xmlBufferAdd(cur->content, content, len);
1578#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001579 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001580 return(cur);
1581}
1582
Daniel Veillard97b58771998-10-20 06:14:16 +00001583/**
1584 * xmlNewDocTextLen:
1585 * @doc: the document
1586 * @content: the text content
1587 * @len: the text len.
1588 *
1589 * Creation of a new text node with an extra content lenght parameter. The
1590 * text node pertain to a given document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001591 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001592 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001593xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001594xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001595 xmlNodePtr cur;
1596
1597 cur = xmlNewTextLen(content, len);
1598 if (cur != NULL) cur->doc = doc;
1599 return(cur);
1600}
1601
Daniel Veillard97b58771998-10-20 06:14:16 +00001602/**
1603 * xmlNewComment:
1604 * @content: the comment content
1605 *
1606 * Creation of a new node containing a comment.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001607 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001608 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001609xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001610xmlNewComment(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001611 xmlNodePtr cur;
1612
1613 /*
1614 * Allocate a new node and fill the fields.
1615 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001616 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001617 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001618 xmlGenericError(xmlGenericErrorContext,
1619 "xmlNewComment : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001620 return(NULL);
1621 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001622 memset(cur, 0, sizeof(xmlNode));
1623 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001624
Daniel Veillardcf461992000-03-14 18:30:20 +00001625 cur->name = xmlStrdup(xmlStringComment);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001626 if (content != NULL) {
1627#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001628 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001629#else
1630 cur->content = xmlBufferCreateSize(0);
1631 xmlBufferSetAllocationScheme(cur->content,
1632 xmlGetBufferAllocationScheme());
1633 xmlBufferAdd(cur->content, content, -1);
1634#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001635 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001636 return(cur);
1637}
1638
Daniel Veillard97b58771998-10-20 06:14:16 +00001639/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001640 * xmlNewCDataBlock:
1641 * @doc: the document
1642 * @content: the CData block content content
1643 * @len: the length of the block
1644 *
1645 * Creation of a new node containing a CData block.
1646 * Returns a pointer to the new node object.
1647 */
1648xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001649xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001650 xmlNodePtr cur;
1651
1652 /*
1653 * Allocate a new node and fill the fields.
1654 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001655 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001656 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001657 xmlGenericError(xmlGenericErrorContext,
1658 "xmlNewCDataBlock : malloc failed\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +00001659 return(NULL);
1660 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001661 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001662 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001663
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001664 if (content != NULL) {
1665#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00001666 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001667#else
1668 cur->content = xmlBufferCreateSize(len);
1669 xmlBufferSetAllocationScheme(cur->content,
1670 xmlGetBufferAllocationScheme());
1671 xmlBufferAdd(cur->content, content, len);
1672#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001673 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001674 return(cur);
1675}
1676
1677/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001678 * xmlNewDocComment:
Daniel Veillard97b58771998-10-20 06:14:16 +00001679 * @doc: the document
1680 * @content: the comment content
1681 *
1682 * Creation of a new node containing a commentwithin a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001683 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001684 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001685xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001686xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001687 xmlNodePtr cur;
1688
1689 cur = xmlNewComment(content);
1690 if (cur != NULL) cur->doc = doc;
1691 return(cur);
1692}
1693
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001694/**
1695 * xmlSetTreeDoc:
1696 * @tree: the top element
1697 * @doc: the document
1698 *
1699 * update all nodes under the tree to point to the right document
1700 */
1701void
1702xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
1703 if (tree == NULL)
1704 return;
1705 if (tree->type == XML_ENTITY_DECL)
1706 return;
1707 if (tree->doc != doc) {
1708 if (tree->children != NULL)
1709 xmlSetListDoc(tree->children, doc);
1710 tree->doc = doc;
1711 }
1712}
1713
1714/**
1715 * xmlSetListDoc:
1716 * @tree: the first element
1717 * @doc: the document
1718 *
1719 * update all nodes in the list to point to the right document
1720 */
1721void
1722xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1723 xmlNodePtr cur;
1724
1725 if (list == NULL)
1726 return;
1727 cur = list;
1728 while (cur != NULL) {
1729 if (cur->doc != doc)
1730 xmlSetTreeDoc(cur, doc);
1731 cur = cur->next;
1732 }
1733}
1734
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001735
Daniel Veillard97b58771998-10-20 06:14:16 +00001736/**
1737 * xmlNewChild:
1738 * @parent: the parent node
1739 * @ns: a namespace if any
1740 * @name: the name of the child
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001741 * @content: the XML content of the child if any.
Daniel Veillard97b58771998-10-20 06:14:16 +00001742 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001743 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001744 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1745 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001746 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1747 * references, but XML special chars need to be escaped first by using
1748 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1749 * support is not needed.
1750 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001751 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001752 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001753xmlNodePtr
1754xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001755 const xmlChar *name, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001756 xmlNodePtr cur, prev;
1757
1758 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001759#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001760 xmlGenericError(xmlGenericErrorContext,
1761 "xmlNewChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001762#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001763 return(NULL);
1764 }
1765
1766 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001767#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001768 xmlGenericError(xmlGenericErrorContext,
1769 "xmlNewChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001770#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001771 return(NULL);
1772 }
1773
1774 /*
1775 * Allocate a new node
1776 */
1777 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001778 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001779 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001780 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001781 if (cur == NULL) return(NULL);
1782
1783 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001784 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001785 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001786 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001787 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001788 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001789 if (parent->children == NULL) {
1790 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001791 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001792 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001793 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001794 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001795 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001796 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001797 }
1798
1799 return(cur);
1800}
1801
Daniel Veillard97b58771998-10-20 06:14:16 +00001802/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001803 * xmlAddNextSibling:
1804 * @cur: the child node
1805 * @elem: the new node
1806 *
1807 * Add a new element @elem as the next siblings of @cur
1808 * If the new element was already inserted in a document it is
1809 * first unlinked from its existing context.
Daniel Veillard683cb022000-10-22 12:04:13 +00001810 * As a result of text merging @elem may be freed.
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001811 *
1812 * Returns the new element or NULL in case of error.
1813 */
1814xmlNodePtr
1815xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1816 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001817#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001818 xmlGenericError(xmlGenericErrorContext,
1819 "xmlAddNextSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001820#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001821 return(NULL);
1822 }
1823 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001824#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001825 xmlGenericError(xmlGenericErrorContext,
1826 "xmlAddNextSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001827#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001828 return(NULL);
1829 }
1830
1831 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00001832
1833 if (elem->type == XML_TEXT_NODE) {
1834 if (cur->type == XML_TEXT_NODE) {
1835#ifndef XML_USE_BUFFER_CONTENT
1836 xmlNodeAddContent(cur, elem->content);
1837#else
1838 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1839#endif
1840 xmlFreeNode(elem);
1841 return(cur);
1842 }
1843 if ((cur->next != NULL) && (cur->type == XML_TEXT_NODE)) {
1844#ifndef XML_USE_BUFFER_CONTENT
1845 xmlChar *tmp;
1846
1847 tmp = xmlStrdup(elem->content);
1848 tmp = xmlStrcat(tmp, cur->next->content);
1849 xmlNodeSetContent(cur->next, tmp);
1850 xmlFree(tmp);
1851#else
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001852 xmlBufferAddHead(cur->next->content,
1853 xmlBufferContent(elem->content),
Daniel Veillard683cb022000-10-22 12:04:13 +00001854 xmlBufferLength(elem->content));
1855#endif
1856 xmlFreeNode(elem);
1857 return(cur->next);
1858 }
1859 }
1860
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001861 if (elem->doc != cur->doc) {
1862 xmlSetTreeDoc(elem, cur->doc);
1863 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001864 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001865 elem->prev = cur;
1866 elem->next = cur->next;
1867 cur->next = elem;
1868 if (elem->next != NULL)
1869 elem->next->prev = elem;
1870 if ((elem->parent != NULL) && (elem->parent->last == cur))
1871 elem->parent->last = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001872 return(elem);
1873}
1874
1875/**
1876 * xmlAddPrevSibling:
1877 * @cur: the child node
1878 * @elem: the new node
1879 *
1880 * Add a new element @elem as the previous siblings of @cur
Daniel Veillard683cb022000-10-22 12:04:13 +00001881 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001882 * If the new element was already inserted in a document it is
1883 * first unlinked from its existing context.
1884 *
1885 * Returns the new element or NULL in case of error.
1886 */
1887xmlNodePtr
1888xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
1889 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001890#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001891 xmlGenericError(xmlGenericErrorContext,
1892 "xmlAddPrevSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001893#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001894 return(NULL);
1895 }
1896 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001897#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001898 xmlGenericError(xmlGenericErrorContext,
1899 "xmlAddPrevSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001900#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001901 return(NULL);
1902 }
1903
1904 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00001905
1906 if (elem->type == XML_TEXT_NODE) {
1907 if (cur->type == XML_TEXT_NODE) {
1908#ifndef XML_USE_BUFFER_CONTENT
1909 xmlChar *tmp;
1910
1911 tmp = xmlStrdup(elem->content);
1912 tmp = xmlStrcat(tmp, cur->content);
1913 xmlNodeSetContent(cur, tmp);
1914 xmlFree(tmp);
1915#else
1916 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
1917 xmlBufferLength(elem->content));
1918#endif
1919 xmlFreeNode(elem);
1920 return(cur);
1921 }
1922 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE)) {
1923#ifndef XML_USE_BUFFER_CONTENT
1924 xmlNodeAddContent(cur->prev, elem->content);
1925#else
1926 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
1927#endif
1928 xmlFreeNode(elem);
1929 return(cur->prev);
1930 }
1931 }
1932
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001933 if (elem->doc != cur->doc) {
1934 xmlSetTreeDoc(elem, cur->doc);
1935 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001936 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001937 elem->next = cur;
1938 elem->prev = cur->prev;
1939 cur->prev = elem;
1940 if (elem->prev != NULL)
1941 elem->prev->next = elem;
1942 if ((elem->parent != NULL) && (elem->parent->children == cur))
1943 elem->parent->children = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001944 return(elem);
1945}
1946
1947/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001948 * xmlAddSibling:
1949 * @cur: the child node
1950 * @elem: the new node
1951 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001952 * Add a new element @elem to the list of siblings of @cur
Daniel Veillard683cb022000-10-22 12:04:13 +00001953 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001954 * If the new element was already inserted in a document it is
1955 * first unlinked from its existing context.
1956 *
1957 * Returns the new element or NULL in case of error.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001958 */
1959xmlNodePtr
1960xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
1961 xmlNodePtr parent;
1962
1963 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001964#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001965 xmlGenericError(xmlGenericErrorContext,
1966 "xmlAddSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001967#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001968 return(NULL);
1969 }
1970
1971 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001972#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001973 xmlGenericError(xmlGenericErrorContext,
1974 "xmlAddSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001975#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001976 return(NULL);
1977 }
1978
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001979 /*
1980 * Constant time is we can rely on the ->parent->last to find
1981 * the last sibling.
1982 */
1983 if ((cur->parent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +00001984 (cur->parent->children != NULL) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001985 (cur->parent->last != NULL) &&
1986 (cur->parent->last->next == NULL)) {
1987 cur = cur->parent->last;
1988 } else {
1989 while (cur->next != NULL) cur = cur->next;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001990 }
1991
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001992 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00001993
1994 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
1995#ifndef XML_USE_BUFFER_CONTENT
1996 xmlNodeAddContent(cur, elem->content);
1997#else
1998 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1999#endif
2000 xmlFreeNode(elem);
2001 return(cur);
2002 }
2003
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002004 if (elem->doc != cur->doc) {
2005 xmlSetTreeDoc(elem, cur->doc);
2006 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002007 parent = cur->parent;
2008 elem->prev = cur;
2009 elem->next = NULL;
2010 elem->parent = parent;
2011 cur->next = elem;
2012 if (parent != NULL)
2013 parent->last = elem;
2014
2015 return(elem);
2016}
2017
2018/**
Daniel Veillard87b95392000-08-12 21:12:04 +00002019 * xmlAddChildList:
2020 * @parent: the parent node
2021 * @cur: the first node in the list
2022 *
2023 * Add a list of node at the end of the child list of the parent
Daniel Veillard683cb022000-10-22 12:04:13 +00002024 * merging adjacent TEXT nodes (@cur may be freed)
Daniel Veillard87b95392000-08-12 21:12:04 +00002025 *
2026 * Returns the last child or NULL in case of error.
2027 */
2028xmlNodePtr
2029xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2030 xmlNodePtr prev;
2031
2032 if (parent == NULL) {
2033#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002034 xmlGenericError(xmlGenericErrorContext,
2035 "xmlAddChild : parent == NULL\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002036#endif
2037 return(NULL);
2038 }
2039
2040 if (cur == NULL) {
2041#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002042 xmlGenericError(xmlGenericErrorContext,
2043 "xmlAddChild : child == NULL\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002044#endif
2045 return(NULL);
2046 }
2047
2048 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2049 (cur->doc != parent->doc)) {
2050#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002051 xmlGenericError(xmlGenericErrorContext,
2052 "Elements moved to a different document\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002053#endif
2054 }
2055
2056 /*
2057 * add the first element at the end of the children list.
2058 */
2059 if (parent->children == NULL) {
2060 parent->children = cur;
2061 } else {
Daniel Veillard683cb022000-10-22 12:04:13 +00002062 /*
2063 * If cur and parent->last both are TEXT nodes, then merge them.
2064 */
2065 if ((cur->type == XML_TEXT_NODE) &&
2066 (parent->last->type == XML_TEXT_NODE)) {
2067#ifndef XML_USE_BUFFER_CONTENT
2068 xmlNodeAddContent(parent->last, cur->content);
2069#else
2070 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2071#endif
2072 /*
2073 * if it's the only child, nothing more to be done.
2074 */
2075 if (cur->next == NULL) {
2076 xmlFreeNode(cur);
2077 return(parent->last);
2078 }
2079 prev = cur;
2080 cur = cur->next;
2081 xmlFreeNode(prev);
2082 }
Daniel Veillard87b95392000-08-12 21:12:04 +00002083 prev = parent->last;
2084 prev->next = cur;
2085 cur->prev = prev;
2086 }
2087 while (cur->next != NULL) {
2088 cur->parent = parent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002089 if (cur->doc != parent->doc) {
2090 xmlSetTreeDoc(cur, parent->doc);
2091 }
Daniel Veillard87b95392000-08-12 21:12:04 +00002092 cur = cur->next;
2093 }
2094 cur->parent = parent;
2095 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2096 parent->last = cur;
2097
2098 return(cur);
2099}
2100
2101/**
Daniel Veillard97b58771998-10-20 06:14:16 +00002102 * xmlAddChild:
2103 * @parent: the parent node
2104 * @cur: the child node
2105 *
Daniel Veillard683cb022000-10-22 12:04:13 +00002106 * Add a new child element, to @parent, at the end of the child list
2107 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillard1e346af1999-02-22 10:33:01 +00002108 * Returns the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002109 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002110xmlNodePtr
2111xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002112 xmlNodePtr prev;
2113
2114 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002115#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002116 xmlGenericError(xmlGenericErrorContext,
2117 "xmlAddChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002118#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002119 return(NULL);
2120 }
2121
2122 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002123#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002124 xmlGenericError(xmlGenericErrorContext,
2125 "xmlAddChild : child == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002126#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002127 return(NULL);
2128 }
2129
Daniel Veillard0bef1311998-10-14 02:36:47 +00002130 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2131 (cur->doc != parent->doc)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002132#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002133 xmlGenericError(xmlGenericErrorContext,
2134 "Elements moved to a different document\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002135#endif
Daniel Veillard0bef1311998-10-14 02:36:47 +00002136 }
2137
Daniel Veillard260a68f1998-08-13 03:39:55 +00002138 /*
Daniel Veillard683cb022000-10-22 12:04:13 +00002139 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
2140 * or with parent->content if parent->content != NULL.
2141 * cur is then freed.
2142 */
2143 if (cur->type == XML_TEXT_NODE) {
2144 if (((parent->type == XML_ELEMENT_NODE) ||
2145 (parent->type == XML_TEXT_NODE)) &&
2146 (parent->content != NULL)) {
2147#ifndef XML_USE_BUFFER_CONTENT
2148 xmlNodeAddContent(parent, cur->content);
2149#else
2150 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2151#endif
2152 xmlFreeNode(cur);
2153 return(parent);
2154 }
2155 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE)) {
2156#ifndef XML_USE_BUFFER_CONTENT
2157 xmlNodeAddContent(parent->last, cur->content);
2158#else
2159 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2160#endif
2161 xmlFreeNode(cur);
2162 return(parent->last);
2163 }
2164 }
2165
2166 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00002167 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002168 */
2169 cur->parent = parent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002170 if (cur->doc != parent->doc) {
2171 xmlSetTreeDoc(cur, parent->doc);
2172 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002173
Daniel Veillardccb09631998-10-27 06:21:04 +00002174 /*
2175 * Handle the case where parent->content != NULL, in that case it will
2176 * create a intermediate TEXT node.
2177 */
Daniel Veillardcf461992000-03-14 18:30:20 +00002178 if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
2179 (parent->content != NULL)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002180 xmlNodePtr text;
2181
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002182#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00002183 text = xmlNewDocText(parent->doc, parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002184#else
2185 text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
2186#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002187 if (text != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002188 text->next = parent->children;
Daniel Veillardccb09631998-10-27 06:21:04 +00002189 if (text->next != NULL)
2190 text->next->prev = text;
Daniel Veillardcf461992000-03-14 18:30:20 +00002191 parent->children = text;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002192 UPDATE_LAST_CHILD_AND_PARENT(parent)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002193#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002194 xmlFree(parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002195#else
2196 xmlBufferFree(parent->content);
2197#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002198 parent->content = NULL;
2199 }
2200 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002201 if (parent->children == NULL) {
2202 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002203 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002204 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002205 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002206 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00002207 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002208 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002209 }
2210
2211 return(cur);
2212}
2213
Daniel Veillard97b58771998-10-20 06:14:16 +00002214/**
2215 * xmlGetLastChild:
2216 * @parent: the parent node
2217 *
2218 * Search the last child of a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002219 * Returns the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002220 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002221xmlNodePtr
2222xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002223 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002224#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002225 xmlGenericError(xmlGenericErrorContext,
2226 "xmlGetLastChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002227#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002228 return(NULL);
2229 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002230 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002231}
2232
Daniel Veillard97b58771998-10-20 06:14:16 +00002233/**
2234 * xmlFreeNodeList:
2235 * @cur: the first node in the list
2236 *
2237 * Free a node and all its siblings, this is a recursive behaviour, all
Daniel Veillardcf461992000-03-14 18:30:20 +00002238 * the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002239 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002240void
2241xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002242 xmlNodePtr next;
2243 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002244#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002245 xmlGenericError(xmlGenericErrorContext,
2246 "xmlFreeNodeList : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002247#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002248 return;
2249 }
2250 while (cur != NULL) {
2251 next = cur->next;
2252 xmlFreeNode(cur);
2253 cur = next;
2254 }
2255}
2256
Daniel Veillard97b58771998-10-20 06:14:16 +00002257/**
2258 * xmlFreeNode:
2259 * @cur: the node
2260 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002261 * Free a node, this is a recursive behaviour, all the children are freed too.
2262 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002263 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002264void
2265xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002266 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002267#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002268 xmlGenericError(xmlGenericErrorContext,
2269 "xmlFreeNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002270#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002271 return;
2272 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002273 if (cur->type == XML_DTD_NODE)
2274 return;
Daniel Veillardccb09631998-10-27 06:21:04 +00002275 cur->doc = NULL;
2276 cur->parent = NULL;
2277 cur->next = NULL;
2278 cur->prev = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002279 if ((cur->children != NULL) &&
2280 (cur->type != XML_ENTITY_REF_NODE))
2281 xmlFreeNodeList(cur->children);
Daniel Veillardccb09631998-10-27 06:21:04 +00002282 if (cur->properties != NULL) xmlFreePropList(cur->properties);
2283 if (cur->type != XML_ENTITY_REF_NODE)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002284#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002285 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002286#else
2287 if (cur->content != NULL) xmlBufferFree(cur->content);
2288#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00002289 if (cur->name != NULL) xmlFree((char *) cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002290 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
2291 memset(cur, -1, sizeof(xmlNode));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002292 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002293}
2294
Daniel Veillard16253641998-10-28 22:58:05 +00002295/**
2296 * xmlUnlinkNode:
2297 * @cur: the node
2298 *
2299 * Unlink a node from it's current context, the node is not freed
2300 */
2301void
2302xmlUnlinkNode(xmlNodePtr cur) {
2303 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002304#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002305 xmlGenericError(xmlGenericErrorContext,
2306 "xmlUnlinkNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002307#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002308 return;
2309 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002310 if ((cur->parent != NULL) && (cur->parent->children == cur))
2311 cur->parent->children = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002312 if ((cur->parent != NULL) && (cur->parent->last == cur))
2313 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00002314 if (cur->next != NULL)
2315 cur->next->prev = cur->prev;
2316 if (cur->prev != NULL)
2317 cur->prev->next = cur->next;
2318 cur->next = cur->prev = NULL;
2319 cur->parent = NULL;
2320}
2321
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002322/**
2323 * xmlReplaceNode:
2324 * @old: the old node
2325 * @cur: the node
2326 *
2327 * Unlink the old node from it's current context, prune the new one
2328 * at the same place. If cur was already inserted in a document it is
2329 * first unlinked from its existing context.
2330 *
2331 * Returns the old node
2332 */
2333xmlNodePtr
2334xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2335 if (old == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002336#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002337 xmlGenericError(xmlGenericErrorContext,
2338 "xmlReplaceNode : old == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002339#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002340 return(NULL);
2341 }
2342 if (cur == NULL) {
2343 xmlUnlinkNode(old);
2344 return(old);
2345 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002346 if (cur == old) {
2347 return(old);
2348 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002349 xmlUnlinkNode(cur);
2350 cur->doc = old->doc;
2351 cur->parent = old->parent;
2352 cur->next = old->next;
2353 if (cur->next != NULL)
2354 cur->next->prev = cur;
2355 cur->prev = old->prev;
2356 if (cur->prev != NULL)
2357 cur->prev->next = cur;
2358 if (cur->parent != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002359 if (cur->parent->children == old)
2360 cur->parent->children = cur;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002361 if (cur->parent->last == old)
2362 cur->parent->last = cur;
2363 }
2364 old->next = old->prev = NULL;
2365 old->parent = NULL;
2366 return(old);
2367}
2368
Daniel Veillard260a68f1998-08-13 03:39:55 +00002369/************************************************************************
2370 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002371 * Copy operations *
2372 * *
2373 ************************************************************************/
2374
2375/**
2376 * xmlCopyNamespace:
2377 * @cur: the namespace
2378 *
2379 * Do a copy of the namespace.
2380 *
2381 * Returns: a new xmlNsPtr, or NULL in case of error.
2382 */
2383xmlNsPtr
2384xmlCopyNamespace(xmlNsPtr cur) {
2385 xmlNsPtr ret;
2386
2387 if (cur == NULL) return(NULL);
2388 switch (cur->type) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002389 case XML_LOCAL_NAMESPACE:
2390 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2391 break;
2392 default:
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002393#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002394 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda4964b72000-10-31 18:23:44 +00002395 "xmlCopyNamespace: invalid type %d\n", cur->type);
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002396#endif
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002397 return(NULL);
2398 }
2399 return(ret);
2400}
2401
2402/**
2403 * xmlCopyNamespaceList:
2404 * @cur: the first namespace
2405 *
2406 * Do a copy of an namespace list.
2407 *
2408 * Returns: a new xmlNsPtr, or NULL in case of error.
2409 */
2410xmlNsPtr
2411xmlCopyNamespaceList(xmlNsPtr cur) {
2412 xmlNsPtr ret = NULL;
2413 xmlNsPtr p = NULL,q;
2414
2415 while (cur != NULL) {
2416 q = xmlCopyNamespace(cur);
2417 if (p == NULL) {
2418 ret = p = q;
2419 } else {
2420 p->next = q;
2421 p = q;
2422 }
2423 cur = cur->next;
2424 }
2425 return(ret);
2426}
2427
2428/**
2429 * xmlCopyProp:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002430 * @target: the element where the attribute will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002431 * @cur: the attribute
2432 *
2433 * Do a copy of the attribute.
2434 *
2435 * Returns: a new xmlAttrPtr, or NULL in case of error.
2436 */
2437xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002438xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002439 xmlAttrPtr ret;
2440
2441 if (cur == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002442 if (cur->parent != NULL)
2443 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2444 else if (cur->children != NULL)
2445 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002446 else
2447 ret = xmlNewDocProp(NULL, cur->name, NULL);
2448 if (ret == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002449 ret->parent = target;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002450
2451 if ((cur->ns != NULL) && (target != NULL)) {
2452 xmlNsPtr ns;
2453
2454 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2455 ret->ns = ns;
2456 } else
2457 ret->ns = NULL;
2458
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002459 if (cur->children != NULL) {
2460 xmlNodePtr tmp;
2461
Daniel Veillardcf461992000-03-14 18:30:20 +00002462 ret->children = xmlCopyNodeList(cur->children);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002463 ret->last = NULL;
2464 tmp = ret->children;
2465 while (tmp != NULL) {
2466 tmp->parent = (xmlNodePtr)ret;
2467 if (tmp->next == NULL)
2468 ret->last = tmp;
2469 tmp = tmp->next;
2470 }
2471 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002472 return(ret);
2473}
2474
2475/**
2476 * xmlCopyPropList:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002477 * @target: the element where the attributes will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002478 * @cur: the first attribute
2479 *
2480 * Do a copy of an attribute list.
2481 *
2482 * Returns: a new xmlAttrPtr, or NULL in case of error.
2483 */
2484xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002485xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002486 xmlAttrPtr ret = NULL;
2487 xmlAttrPtr p = NULL,q;
2488
2489 while (cur != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002490 q = xmlCopyProp(target, cur);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002491 if (p == NULL) {
2492 ret = p = q;
2493 } else {
2494 p->next = q;
Daniel Veillardcf461992000-03-14 18:30:20 +00002495 q->prev = p;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002496 p = q;
2497 }
2498 cur = cur->next;
2499 }
2500 return(ret);
2501}
2502
2503/*
Daniel Veillard11a48ec1999-11-23 10:40:46 +00002504 * NOTE abeut the CopyNode operations !
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002505 *
2506 * They are splitted into external and internal parts for one
2507 * tricky reason: namespaces. Doing a direct copy of a node
2508 * say RPM:Copyright without changing the namespace pointer to
2509 * something else can produce stale links. One way to do it is
2510 * to keep a reference counter but this doesn't work as soon
2511 * as one move the element or the subtree out of the scope of
2512 * the existing namespace. The actual solution seems to add
2513 * a copy of the namespace at the top of the copied tree if
2514 * not available in the subtree.
2515 * Hence two functions, the public front-end call the inner ones
2516 */
2517
2518static xmlNodePtr
2519xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2520
2521static xmlNodePtr
2522xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
2523 int recursive) {
2524 xmlNodePtr ret;
2525
2526 if (node == NULL) return(NULL);
2527 /*
2528 * Allocate a new node and fill the fields.
2529 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00002530 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002531 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002532 xmlGenericError(xmlGenericErrorContext,
2533 "xmlStaticCopyNode : malloc failed\n");
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002534 return(NULL);
2535 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002536 memset(ret, 0, sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002537 ret->type = node->type;
Daniel Veillardcf461992000-03-14 18:30:20 +00002538
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002539 ret->doc = doc;
2540 ret->parent = parent;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002541 if (node->name != NULL)
2542 ret->name = xmlStrdup(node->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002543 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
2544#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002545 ret->content = xmlStrdup(node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002546#else
2547 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2548 xmlBufferSetAllocationScheme(ret->content,
2549 xmlGetBufferAllocationScheme());
2550 xmlBufferAdd(ret->content,
2551 xmlBufferContent(node->content),
2552 xmlBufferLength(node->content));
2553#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002554 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002555 if (parent != NULL)
2556 xmlAddChild(parent, ret);
2557
2558 if (!recursive) return(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002559 if (node->nsDef != NULL)
2560 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2561
2562 if (node->ns != NULL) {
2563 xmlNsPtr ns;
2564
2565 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2566 if (ns == NULL) {
2567 /*
2568 * Humm, we are copying an element whose namespace is defined
2569 * out of the new tree scope. Search it in the original tree
2570 * and add it at the top of the new tree
2571 */
2572 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2573 if (ns != NULL) {
2574 xmlNodePtr root = ret;
2575
2576 while (root->parent != NULL) root = root->parent;
2577 xmlNewNs(root, ns->href, ns->prefix);
2578 }
2579 } else {
2580 /*
2581 * reference the existing namespace definition in our own tree.
2582 */
2583 ret->ns = ns;
2584 }
2585 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002586 if (node->properties != NULL)
2587 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardcf461992000-03-14 18:30:20 +00002588 if (node->children != NULL)
2589 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002590 UPDATE_LAST_CHILD_AND_PARENT(ret)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002591 return(ret);
2592}
2593
2594static xmlNodePtr
2595xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2596 xmlNodePtr ret = NULL;
2597 xmlNodePtr p = NULL,q;
2598
2599 while (node != NULL) {
2600 q = xmlStaticCopyNode(node, doc, parent, 1);
Daniel Veillard06047432000-04-24 11:33:38 +00002601 if (ret == NULL) {
2602 q->prev = NULL;
2603 ret = p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002604 } else {
Daniel Veillard06047432000-04-24 11:33:38 +00002605 p->next = q;
2606 q->prev = p;
2607 p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002608 }
2609 node = node->next;
2610 }
2611 return(ret);
2612}
2613
2614/**
2615 * xmlCopyNode:
2616 * @node: the node
2617 * @recursive: if 1 do a recursive copy.
2618 *
2619 * Do a copy of the node.
2620 *
2621 * Returns: a new xmlNodePtr, or NULL in case of error.
2622 */
2623xmlNodePtr
2624xmlCopyNode(xmlNodePtr node, int recursive) {
2625 xmlNodePtr ret;
2626
2627 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2628 return(ret);
2629}
2630
2631/**
2632 * xmlCopyNodeList:
2633 * @node: the first node in the list.
2634 *
2635 * Do a recursive copy of the node list.
2636 *
2637 * Returns: a new xmlNodePtr, or NULL in case of error.
2638 */
2639xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2640 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2641 return(ret);
2642}
2643
2644/**
2645 * xmlCopyElement:
2646 * @elem: the element
2647 *
2648 * Do a copy of the element definition.
2649 *
2650 * Returns: a new xmlElementPtr, or NULL in case of error.
2651xmlElementPtr
2652xmlCopyElement(xmlElementPtr elem) {
2653 xmlElementPtr ret;
2654
2655 if (elem == NULL) return(NULL);
2656 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
2657 if (ret == NULL) return(NULL);
2658 if (!recursive) return(ret);
2659 if (elem->properties != NULL)
2660 ret->properties = xmlCopyPropList(elem->properties);
2661
2662 if (elem->nsDef != NULL)
2663 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
Daniel Veillardcf461992000-03-14 18:30:20 +00002664 if (elem->children != NULL)
2665 ret->children = xmlCopyElementList(elem->children);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002666 return(ret);
2667}
2668 */
2669
2670/**
2671 * xmlCopyDtd:
2672 * @dtd: the dtd
2673 *
2674 * Do a copy of the dtd.
2675 *
2676 * Returns: a new xmlDtdPtr, or NULL in case of error.
2677 */
2678xmlDtdPtr
2679xmlCopyDtd(xmlDtdPtr dtd) {
2680 xmlDtdPtr ret;
2681
2682 if (dtd == NULL) return(NULL);
2683 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2684 if (ret == NULL) return(NULL);
2685 if (dtd->entities != NULL)
2686 ret->entities = (void *) xmlCopyEntitiesTable(
2687 (xmlEntitiesTablePtr) dtd->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002688 if (dtd->notations != NULL)
2689 ret->notations = (void *) xmlCopyNotationTable(
2690 (xmlNotationTablePtr) dtd->notations);
2691 if (dtd->elements != NULL)
2692 ret->elements = (void *) xmlCopyElementTable(
2693 (xmlElementTablePtr) dtd->elements);
2694 if (dtd->attributes != NULL)
2695 ret->attributes = (void *) xmlCopyAttributeTable(
2696 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002697 return(ret);
2698}
2699
2700/**
2701 * xmlCopyDoc:
2702 * @doc: the document
2703 * @recursive: if 1 do a recursive copy.
2704 *
2705 * Do a copy of the document info. If recursive, the content tree will
2706 * be copied too as well as Dtd, namespaces and entities.
2707 *
2708 * Returns: a new xmlDocPtr, or NULL in case of error.
2709 */
2710xmlDocPtr
2711xmlCopyDoc(xmlDocPtr doc, int recursive) {
2712 xmlDocPtr ret;
2713
2714 if (doc == NULL) return(NULL);
2715 ret = xmlNewDoc(doc->version);
2716 if (ret == NULL) return(NULL);
2717 if (doc->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002718 ret->name = xmlMemStrdup(doc->name);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002719 if (doc->encoding != NULL)
2720 ret->encoding = xmlStrdup(doc->encoding);
2721 ret->compression = doc->compression;
2722 ret->standalone = doc->standalone;
2723 if (!recursive) return(ret);
2724
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002725 if (doc->intSubset != NULL)
2726 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002727 if (doc->oldNs != NULL)
2728 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002729 if (doc->children != NULL) {
2730 xmlNodePtr tmp;
Daniel Veillard06047432000-04-24 11:33:38 +00002731 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2732 (xmlNodePtr)ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002733 ret->last = NULL;
2734 tmp = ret->children;
2735 while (tmp != NULL) {
2736 if (tmp->next == NULL)
2737 ret->last = tmp;
2738 tmp = tmp->next;
2739 }
2740 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002741 return(ret);
2742}
2743
2744/************************************************************************
2745 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002746 * Content access functions *
2747 * *
2748 ************************************************************************/
2749
Daniel Veillard97b58771998-10-20 06:14:16 +00002750/**
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002751 * xmlDocGetRootElement:
2752 * @doc: the document
2753 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002754 * Get the root element of the document (doc->children is a list
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002755 * containing possibly comments, PIs, etc ...).
2756 *
2757 * Returns the xmlNodePtr for the root or NULL
2758 */
2759xmlNodePtr
2760xmlDocGetRootElement(xmlDocPtr doc) {
2761 xmlNodePtr ret;
2762
2763 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002764 ret = doc->children;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002765 while (ret != NULL) {
2766 if (ret->type == XML_ELEMENT_NODE)
2767 return(ret);
2768 ret = ret->next;
2769 }
2770 return(ret);
2771}
2772
2773/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002774 * xmlDocSetRootElement:
2775 * @doc: the document
2776 * @root: the new document root element
2777 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002778 * Set the root element of the document (doc->children is a list
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002779 * containing possibly comments, PIs, etc ...).
2780 *
2781 * Returns the old root element if any was found
2782 */
2783xmlNodePtr
2784xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
2785 xmlNodePtr old = NULL;
2786
2787 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002788 old = doc->children;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002789 while (old != NULL) {
2790 if (old->type == XML_ELEMENT_NODE)
2791 break;
2792 old = old->next;
2793 }
2794 if (old == NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002795 if (doc->children == NULL) {
2796 doc->children = root;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002797 doc->last = root;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002798 } else {
Daniel Veillardcf461992000-03-14 18:30:20 +00002799 xmlAddSibling(doc->children, root);
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002800 }
2801 } else {
2802 xmlReplaceNode(old, root);
2803 }
2804 return(old);
2805}
2806
2807/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002808 * xmlNodeSetLang:
2809 * @cur: the node being changed
2810 * @lang: the langage description
2811 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002812 * Set the language of a node, i.e. the values of the xml:lang
2813 * attribute.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002814 */
2815void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002816xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002817 if (cur == NULL) return;
2818 switch(cur->type) {
2819 case XML_TEXT_NODE:
2820 case XML_CDATA_SECTION_NODE:
2821 case XML_COMMENT_NODE:
2822 case XML_DOCUMENT_NODE:
2823 case XML_DOCUMENT_TYPE_NODE:
2824 case XML_DOCUMENT_FRAG_NODE:
2825 case XML_NOTATION_NODE:
2826 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002827 case XML_DTD_NODE:
2828 case XML_ELEMENT_DECL:
2829 case XML_ATTRIBUTE_DECL:
2830 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002831 case XML_PI_NODE:
2832 case XML_ENTITY_REF_NODE:
2833 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002834 case XML_NAMESPACE_DECL:
Daniel Veillard04698d92000-09-17 16:00:22 +00002835#ifdef LIBXML_SGML_ENABLED
2836 case XML_SGML_DOCUMENT_NODE:
2837#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002838 case XML_XINCLUDE_START:
2839 case XML_XINCLUDE_END:
Daniel Veillard39c7d712000-09-10 16:14:55 +00002840 return;
2841 case XML_ELEMENT_NODE:
2842 case XML_ATTRIBUTE_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002843 break;
2844 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002845 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
2846}
2847
2848/**
2849 * xmlNodeGetLang:
2850 * @cur: the node being checked
2851 *
2852 * Searches the language of a node, i.e. the values of the xml:lang
2853 * attribute or the one carried by the nearest ancestor.
2854 *
2855 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillarda819dac1999-11-24 18:04:22 +00002856 * It's up to the caller to free the memory.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002857 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00002858xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00002859xmlNodeGetLang(xmlNodePtr cur) {
Daniel Veillarda819dac1999-11-24 18:04:22 +00002860 xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002861
2862 while (cur != NULL) {
2863 lang = xmlGetProp(cur, BAD_CAST "xml:lang");
2864 if (lang != NULL)
2865 return(lang);
2866 cur = cur->parent;
2867 }
2868 return(NULL);
2869}
2870
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002871
2872/**
2873 * xmlNodeSetSpacePreserve:
2874 * @cur: the node being changed
2875 * @val: the xml:space value ("0": default, 1: "preserve")
2876 *
2877 * Set (or reset) the space preserving behaviour of a node, i.e. the
2878 * value of the xml:space attribute.
2879 */
2880void
2881xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
2882 if (cur == NULL) return;
2883 switch(cur->type) {
2884 case XML_TEXT_NODE:
2885 case XML_CDATA_SECTION_NODE:
2886 case XML_COMMENT_NODE:
2887 case XML_DOCUMENT_NODE:
2888 case XML_DOCUMENT_TYPE_NODE:
2889 case XML_DOCUMENT_FRAG_NODE:
2890 case XML_NOTATION_NODE:
2891 case XML_HTML_DOCUMENT_NODE:
2892 case XML_DTD_NODE:
2893 case XML_ELEMENT_DECL:
2894 case XML_ATTRIBUTE_DECL:
2895 case XML_ENTITY_DECL:
2896 case XML_PI_NODE:
2897 case XML_ENTITY_REF_NODE:
2898 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002899 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002900 case XML_XINCLUDE_START:
2901 case XML_XINCLUDE_END:
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002902#ifdef LIBXML_SGML_ENABLED
2903 case XML_SGML_DOCUMENT_NODE:
2904#endif
2905 return;
2906 case XML_ELEMENT_NODE:
2907 case XML_ATTRIBUTE_NODE:
2908 break;
2909 }
2910 switch (val) {
2911 case 0:
2912 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
2913 break;
2914 case 1:
2915 xmlSetProp(cur, BAD_CAST "xml:space",
2916 BAD_CAST "preserve");
2917 break;
2918 }
2919}
2920
Daniel Veillardb96e6431999-08-29 21:02:19 +00002921/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002922 * xmlNodeGetSpacePreserve:
2923 * @cur: the node being checked
2924 *
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002925 * Searches the space preserving behaviour of a node, i.e. the values
2926 * of the xml:space attribute or the one carried by the nearest
2927 * ancestor.
Daniel Veillardcf461992000-03-14 18:30:20 +00002928 *
2929 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
2930 */
2931int
2932xmlNodeGetSpacePreserve(xmlNodePtr cur) {
2933 xmlChar *space;
2934
2935 while (cur != NULL) {
2936 space = xmlGetProp(cur, BAD_CAST "xml:space");
2937 if (space != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002938 if (xmlStrEqual(space, BAD_CAST "preserve")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002939 xmlFree(space);
2940 return(1);
2941 }
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002942 if (xmlStrEqual(space, BAD_CAST "default")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002943 xmlFree(space);
2944 return(0);
2945 }
2946 xmlFree(space);
2947 }
2948 cur = cur->parent;
2949 }
2950 return(-1);
2951}
2952
2953/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002954 * xmlNodeSetName:
2955 * @cur: the node being changed
2956 * @name: the new tag name
2957 *
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002958 * Set (or reset) the name of a node.
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002959 */
2960void
2961xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
2962 if (cur == NULL) return;
2963 if (name == NULL) return;
2964 switch(cur->type) {
2965 case XML_TEXT_NODE:
2966 case XML_CDATA_SECTION_NODE:
2967 case XML_COMMENT_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002968 case XML_DOCUMENT_TYPE_NODE:
2969 case XML_DOCUMENT_FRAG_NODE:
2970 case XML_NOTATION_NODE:
2971 case XML_HTML_DOCUMENT_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002972 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002973 case XML_XINCLUDE_START:
2974 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00002975#ifdef LIBXML_SGML_ENABLED
2976 case XML_SGML_DOCUMENT_NODE:
2977#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002978 return;
2979 case XML_ELEMENT_NODE:
2980 case XML_ATTRIBUTE_NODE:
2981 case XML_PI_NODE:
2982 case XML_ENTITY_REF_NODE:
2983 case XML_ENTITY_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002984 case XML_DTD_NODE:
2985 case XML_DOCUMENT_NODE:
2986 case XML_ELEMENT_DECL:
2987 case XML_ATTRIBUTE_DECL:
2988 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002989 break;
2990 }
2991 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
2992 cur->name = xmlStrdup(name);
2993}
2994
2995/**
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002996 * xmlNodeSetBase:
2997 * @cur: the node being changed
2998 * @uri: the new base URI
2999 *
3000 * Set (or reset) the base URI of a node, i.e. the value of the
3001 * xml:base attribute.
3002 */
3003void
3004xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3005 if (cur == NULL) return;
3006 switch(cur->type) {
3007 case XML_TEXT_NODE:
3008 case XML_CDATA_SECTION_NODE:
3009 case XML_COMMENT_NODE:
3010 case XML_DOCUMENT_NODE:
3011 case XML_DOCUMENT_TYPE_NODE:
3012 case XML_DOCUMENT_FRAG_NODE:
3013 case XML_NOTATION_NODE:
3014 case XML_HTML_DOCUMENT_NODE:
3015 case XML_DTD_NODE:
3016 case XML_ELEMENT_DECL:
3017 case XML_ATTRIBUTE_DECL:
3018 case XML_ENTITY_DECL:
3019 case XML_PI_NODE:
3020 case XML_ENTITY_REF_NODE:
3021 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003022 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003023 case XML_XINCLUDE_START:
3024 case XML_XINCLUDE_END:
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00003025#ifdef LIBXML_SGML_ENABLED
3026 case XML_SGML_DOCUMENT_NODE:
3027#endif
3028 return;
3029 case XML_ELEMENT_NODE:
3030 case XML_ATTRIBUTE_NODE:
3031 break;
3032 }
3033 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3034}
3035
3036/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003037 * xmlDocumentGetBase:
3038 * @doc: the document
3039 *
3040 * Searches for the Document BASE URL. The code should work on both XML
3041 * and HTML document.
3042 * It returns the base as defined in RFC 2396 section
3043 * 5.1.3. Base URI from the Retrieval URI
3044 * However it does not return the computed base (5.1.1 and 5.1.2), use
3045 * xmlNodeGetBase() for this
3046 *
3047 * Returns a pointer to the base URL, or NULL if not found
3048 * It's up to the caller to free the memory.
3049 */
3050xmlChar *
3051xmlDocumentGetBase(xmlDocPtr doc) {
3052 if (doc == NULL)
3053 return(NULL);
3054 if (doc->type == XML_HTML_DOCUMENT_NODE) {
3055 if (doc->URL != NULL)
3056 return(xmlStrdup(doc->URL));
3057 return(NULL);
3058 }
3059 if (doc->URL != NULL)
3060 return(xmlStrdup(doc->URL));
3061 return(NULL);
3062}
3063
3064/**
Daniel Veillard10a2c651999-12-12 13:03:50 +00003065 * xmlNodeGetBase:
3066 * @doc: the document the node pertains to
3067 * @cur: the node being checked
3068 *
3069 * Searches for the BASE URL. The code should work on both XML
3070 * and HTML document even if base mechanisms are completely different.
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003071 * It returns the base as defined in RFC 2396 sections
3072 * 5.1.1. Base URI within Document Content
3073 * and
3074 * 5.1.2. Base URI from the Encapsulating Entity
3075 * However it does not return the document base (5.1.3), use
3076 * xmlDocumentGetBase() for this
Daniel Veillard10a2c651999-12-12 13:03:50 +00003077 *
3078 * Returns a pointer to the base URL, or NULL if not found
3079 * It's up to the caller to free the memory.
3080 */
3081xmlChar *
3082xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
3083 xmlChar *base;
3084
3085 if ((cur == NULL) && (doc == NULL))
3086 return(NULL);
3087 if (doc == NULL) doc = cur->doc;
3088 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003089 cur = doc->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003090 while ((cur != NULL) && (cur->name != NULL)) {
3091 if (cur->type != XML_ELEMENT_NODE) {
3092 cur = cur->next;
3093 continue;
3094 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003095 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003096 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003097 continue;
3098 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003099 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003100 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003101 continue;
3102 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003103 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3104 return(xmlGetProp(cur, BAD_CAST "href"));
Daniel Veillard10a2c651999-12-12 13:03:50 +00003105 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003106 cur = cur->next;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003107 }
3108 return(NULL);
3109 }
3110 while (cur != NULL) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003111 if (cur->type == XML_ENTITY_DECL) {
3112 xmlEntityPtr ent = (xmlEntityPtr) cur;
3113 return(xmlStrdup(ent->URI));
3114 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003115 base = xmlGetProp(cur, BAD_CAST "xml:base");
3116 if (base != NULL)
3117 return(base);
3118 cur = cur->parent;
3119 }
3120 return(NULL);
3121}
3122
3123/**
Daniel Veillard16253641998-10-28 22:58:05 +00003124 * xmlNodeGetContent:
3125 * @cur: the node being read
3126 *
3127 * Read the value of a node, this can be either the text carried
3128 * directly by this node if it's a TEXT node or the aggregate string
3129 * of the values carried by this node child's (TEXT and ENTITY_REF).
3130 * Entity references are substitued.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003131 * Returns a new xmlChar * or NULL if no content is available.
Daniel Veillard5099ae81999-04-21 20:12:07 +00003132 * It's up to the caller to free the memory.
Daniel Veillard16253641998-10-28 22:58:05 +00003133 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003134xmlChar *
Daniel Veillard16253641998-10-28 22:58:05 +00003135xmlNodeGetContent(xmlNodePtr cur) {
3136 if (cur == NULL) return(NULL);
3137 switch (cur->type) {
3138 case XML_DOCUMENT_FRAG_NODE:
3139 case XML_ELEMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003140 return(xmlNodeListGetString(cur->doc, cur->children, 1));
Daniel Veillard16253641998-10-28 22:58:05 +00003141 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003142 case XML_ATTRIBUTE_NODE: {
3143 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00003144 if (attr->parent != NULL)
3145 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003146 else
Daniel Veillardcf461992000-03-14 18:30:20 +00003147 return(xmlNodeListGetString(NULL, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003148 break;
3149 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003150 case XML_COMMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003151 case XML_PI_NODE:
3152 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003153#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00003154 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003155#else
3156 return(xmlStrdup(xmlBufferContent(cur->content)));
3157#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00003158 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00003159 case XML_ENTITY_REF_NODE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003160 /*
3161 * Locate the entity, and get it's content
3162 * @@@
3163 */
3164 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00003165 case XML_ENTITY_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003166 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003167 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003168 case XML_DOCUMENT_TYPE_NODE:
3169 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003170 case XML_DTD_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003171 case XML_XINCLUDE_START:
3172 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003173#ifdef LIBXML_SGML_ENABLED
3174 case XML_SGML_DOCUMENT_NODE:
3175#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00003176 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00003177 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003178 return(xmlStrdup(((xmlNsPtr)cur)->href));
Daniel Veillardcf461992000-03-14 18:30:20 +00003179 case XML_ELEMENT_DECL:
3180 /* TODO !!! */
3181 return(NULL);
3182 case XML_ATTRIBUTE_DECL:
3183 /* TODO !!! */
3184 return(NULL);
3185 case XML_ENTITY_DECL:
3186 /* TODO !!! */
Daniel Veillard16253641998-10-28 22:58:05 +00003187 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003188 case XML_CDATA_SECTION_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003189 case XML_TEXT_NODE:
3190 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003191#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003192 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003193#else
3194 return(xmlStrdup(xmlBufferContent(cur->content)));
3195#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003196 return(NULL);
3197 }
3198 return(NULL);
3199}
3200
3201/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003202 * xmlNodeSetContent:
3203 * @cur: the node being modified
3204 * @content: the new value of the content
3205 *
3206 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003207 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003208void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003209xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003210 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003211#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003212 xmlGenericError(xmlGenericErrorContext,
3213 "xmlNodeSetContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003214#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003215 return;
3216 }
Daniel Veillard16253641998-10-28 22:58:05 +00003217 switch (cur->type) {
3218 case XML_DOCUMENT_FRAG_NODE:
3219 case XML_ELEMENT_NODE:
3220 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003221#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003222 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003223#else
3224 xmlBufferFree(cur->content);
3225#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003226 cur->content = NULL;
3227 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003228 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3229 cur->children = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003230 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00003231 break;
3232 case XML_ATTRIBUTE_NODE:
3233 break;
3234 case XML_TEXT_NODE:
3235 case XML_CDATA_SECTION_NODE:
3236 case XML_ENTITY_REF_NODE:
3237 case XML_ENTITY_NODE:
3238 case XML_PI_NODE:
3239 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003240 if (cur->content != NULL) {
3241#ifndef XML_USE_BUFFER_CONTENT
3242 xmlFree(cur->content);
3243#else
3244 xmlBufferFree(cur->content);
3245#endif
3246 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003247 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3248 cur->last = cur->children = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003249 if (content != NULL) {
3250#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003251 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003252#else
3253 cur->content = xmlBufferCreateSize(0);
3254 xmlBufferSetAllocationScheme(cur->content,
3255 xmlGetBufferAllocationScheme());
3256 xmlBufferAdd(cur->content, content, -1);
3257#endif
3258 } else
Daniel Veillard16253641998-10-28 22:58:05 +00003259 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003260 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003261 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003262 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003263 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003264 case XML_XINCLUDE_START:
3265 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003266#ifdef LIBXML_SGML_ENABLED
3267 case XML_SGML_DOCUMENT_NODE:
3268#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003269 break;
3270 case XML_NOTATION_NODE:
3271 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003272 case XML_DTD_NODE:
3273 break;
Daniel Veillarda4964b72000-10-31 18:23:44 +00003274 case XML_NAMESPACE_DECL:
3275 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003276 case XML_ELEMENT_DECL:
3277 /* TODO !!! */
3278 break;
3279 case XML_ATTRIBUTE_DECL:
3280 /* TODO !!! */
3281 break;
3282 case XML_ENTITY_DECL:
3283 /* TODO !!! */
3284 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003285 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003286}
3287
Daniel Veillard97b58771998-10-20 06:14:16 +00003288/**
3289 * xmlNodeSetContentLen:
3290 * @cur: the node being modified
3291 * @content: the new value of the content
3292 * @len: the size of @content
3293 *
3294 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003295 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003296void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003297xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003298 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003299#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003300 xmlGenericError(xmlGenericErrorContext,
3301 "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003302#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003303 return;
3304 }
Daniel Veillard16253641998-10-28 22:58:05 +00003305 switch (cur->type) {
3306 case XML_DOCUMENT_FRAG_NODE:
3307 case XML_ELEMENT_NODE:
3308 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003309#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003310 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003311#else
3312 xmlBufferFree(cur->content);
3313#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003314 cur->content = NULL;
3315 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003316 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3317 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003318 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00003319 break;
3320 case XML_ATTRIBUTE_NODE:
3321 break;
3322 case XML_TEXT_NODE:
3323 case XML_CDATA_SECTION_NODE:
3324 case XML_ENTITY_REF_NODE:
3325 case XML_ENTITY_NODE:
3326 case XML_PI_NODE:
3327 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003328 case XML_NOTATION_NODE:
3329 if (cur->content != NULL) {
3330#ifndef XML_USE_BUFFER_CONTENT
3331 xmlFree(cur->content);
3332#else
3333 xmlBufferFree(cur->content);
3334#endif
3335 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003336 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3337 cur->children = cur->last = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003338 if (content != NULL) {
3339#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003340 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003341#else
3342 cur->content = xmlBufferCreateSize(len);
3343 xmlBufferSetAllocationScheme(cur->content,
3344 xmlGetBufferAllocationScheme());
3345 xmlBufferAdd(cur->content, content, len);
3346#endif
3347 } else
Daniel Veillard16253641998-10-28 22:58:05 +00003348 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003349 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003350 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003351 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003352 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003353 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003354 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003355 case XML_XINCLUDE_START:
3356 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003357#ifdef LIBXML_SGML_ENABLED
3358 case XML_SGML_DOCUMENT_NODE:
3359#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003360 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003361 case XML_ELEMENT_DECL:
3362 /* TODO !!! */
3363 break;
3364 case XML_ATTRIBUTE_DECL:
3365 /* TODO !!! */
3366 break;
3367 case XML_ENTITY_DECL:
3368 /* TODO !!! */
3369 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003370 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003371}
3372
Daniel Veillard97b58771998-10-20 06:14:16 +00003373/**
3374 * xmlNodeAddContentLen:
3375 * @cur: the node being modified
3376 * @content: extra content
3377 * @len: the size of @content
3378 *
3379 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003380 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003381void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003382xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003383 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003384#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003385 xmlGenericError(xmlGenericErrorContext,
3386 "xmlNodeAddContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003387#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003388 return;
3389 }
3390 if (len <= 0) return;
3391 switch (cur->type) {
3392 case XML_DOCUMENT_FRAG_NODE:
3393 case XML_ELEMENT_NODE: {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003394 xmlNodePtr last = NULL, newNode;
Daniel Veillard16253641998-10-28 22:58:05 +00003395
Daniel Veillardcf461992000-03-14 18:30:20 +00003396 if (cur->children != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003397 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003398 } else {
3399 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003400#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardcf461992000-03-14 18:30:20 +00003401 cur->children = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003402#else
Daniel Veillardcf461992000-03-14 18:30:20 +00003403 cur->children = xmlStringGetNodeList(cur->doc,
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003404 xmlBufferContent(cur->content));
3405#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003406 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003407#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003408 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003409#else
3410 xmlBufferFree(cur->content);
3411#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003412 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003413 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003414 }
3415 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003416 newNode = xmlNewTextLen(content, len);
3417 if (newNode != NULL) {
3418 xmlAddChild(cur, newNode);
3419 if ((last != NULL) && (last->next == newNode)) {
3420 xmlTextMerge(last, newNode);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003421 }
Daniel Veillard16253641998-10-28 22:58:05 +00003422 }
3423 break;
3424 }
3425 case XML_ATTRIBUTE_NODE:
3426 break;
3427 case XML_TEXT_NODE:
3428 case XML_CDATA_SECTION_NODE:
3429 case XML_ENTITY_REF_NODE:
3430 case XML_ENTITY_NODE:
3431 case XML_PI_NODE:
3432 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003433 case XML_NOTATION_NODE:
3434 if (content != NULL) {
3435#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003436 cur->content = xmlStrncat(cur->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003437#else
3438 xmlBufferAdd(cur->content, content, len);
3439#endif
3440 }
Daniel Veillard16253641998-10-28 22:58:05 +00003441 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003442 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003443 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003444 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003445 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003446 case XML_XINCLUDE_START:
3447 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003448#ifdef LIBXML_SGML_ENABLED
3449 case XML_SGML_DOCUMENT_NODE:
3450#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003451 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003452 case XML_ELEMENT_DECL:
3453 case XML_ATTRIBUTE_DECL:
3454 case XML_ENTITY_DECL:
3455 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003456 }
3457}
3458
3459/**
3460 * xmlNodeAddContent:
3461 * @cur: the node being modified
3462 * @content: extra content
3463 *
3464 * Append the extra substring to the node content.
3465 */
3466void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003467xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard16253641998-10-28 22:58:05 +00003468 int len;
3469
3470 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003471#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003472 xmlGenericError(xmlGenericErrorContext,
3473 "xmlNodeAddContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003474#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003475 return;
3476 }
Daniel Veillard16253641998-10-28 22:58:05 +00003477 if (content == NULL) return;
3478 len = xmlStrlen(content);
3479 xmlNodeAddContentLen(cur, content, len);
3480}
3481
3482/**
3483 * xmlTextMerge:
3484 * @first: the first text node
3485 * @second: the second text node being merged
3486 *
3487 * Merge two text nodes into one
Daniel Veillard1e346af1999-02-22 10:33:01 +00003488 * Returns the first text node augmented
Daniel Veillard16253641998-10-28 22:58:05 +00003489 */
3490xmlNodePtr
3491xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3492 if (first == NULL) return(second);
3493 if (second == NULL) return(first);
3494 if (first->type != XML_TEXT_NODE) return(first);
3495 if (second->type != XML_TEXT_NODE) return(first);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003496#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003497 xmlNodeAddContent(first, second->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003498#else
3499 xmlNodeAddContent(first, xmlBufferContent(second->content));
3500#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003501 xmlUnlinkNode(second);
3502 xmlFreeNode(second);
3503 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003504}
3505
Daniel Veillard97b58771998-10-20 06:14:16 +00003506/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003507 * xmlGetNsList:
3508 * @doc: the document
3509 * @node: the current node
3510 *
3511 * Search all the namespace applying to a given element.
3512 * Returns an NULL terminated array of all the xmlNsPtr found
3513 * that need to be freed by the caller or NULL if no
3514 * namespace if defined
3515 */
3516xmlNsPtr *
3517xmlGetNsList(xmlDocPtr doc, xmlNodePtr node) {
3518 xmlNsPtr cur;
3519 xmlNsPtr *ret = NULL;
3520 int nbns = 0;
3521 int maxns = 10;
3522 int i;
3523
3524 while (node != NULL) {
3525 cur = node->nsDef;
3526 while (cur != NULL) {
3527 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003528 ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003529 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003530 xmlGenericError(xmlGenericErrorContext,
3531 "xmlGetNsList : out of memory!\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00003532 return(NULL);
3533 }
3534 ret[nbns] = NULL;
3535 }
3536 for (i = 0;i < nbns;i++) {
3537 if ((cur->prefix == ret[i]->prefix) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003538 (xmlStrEqual(cur->prefix, ret[i]->prefix))) break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003539 }
3540 if (i >= nbns) {
3541 if (nbns >= maxns) {
3542 maxns *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003543 ret = (xmlNsPtr *) xmlRealloc(ret,
Daniel Veillardb96e6431999-08-29 21:02:19 +00003544 (maxns + 1) * sizeof(xmlNsPtr));
3545 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003546 xmlGenericError(xmlGenericErrorContext,
3547 "xmlGetNsList : realloc failed!\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00003548 return(NULL);
3549 }
3550 }
3551 ret[nbns++] = cur;
3552 ret[nbns] = NULL;
3553 }
3554
3555 cur = cur->next;
3556 }
3557 node = node->parent;
3558 }
3559 return(ret);
3560}
3561
3562/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003563 * xmlSearchNs:
3564 * @doc: the document
3565 * @node: the current node
3566 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00003567 *
Daniel Veillard97b58771998-10-20 06:14:16 +00003568 * Search a Ns registered under a given name space for a document.
3569 * recurse on the parents until it finds the defined namespace
3570 * or return NULL otherwise.
3571 * @nameSpace can be NULL, this is a search for the default namespace.
Daniel Veillarde0854c32000-08-27 21:12:29 +00003572 * We don't allow to cross entities boundaries. If you don't declare
3573 * the namespace within those you will be in troubles !!! A warning
3574 * is generated to cover this case.
3575 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003576 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003577 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003578xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003579xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003580 xmlNsPtr cur;
3581
Daniel Veillard62ba71e1999-12-16 17:52:19 +00003582 if (node == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003583 while (node != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003584 if ((node->type == XML_ENTITY_REF_NODE) ||
3585 (node->type == XML_ENTITY_NODE) ||
3586 (node->type == XML_ENTITY_DECL))
3587 return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00003588 if (node->type == XML_ELEMENT_NODE) {
3589 cur = node->nsDef;
3590 while (cur != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003591 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3592 (cur->href != NULL))
Daniel Veillardcf461992000-03-14 18:30:20 +00003593 return(cur);
3594 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
Daniel Veillarde0854c32000-08-27 21:12:29 +00003595 (cur->href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003596 (xmlStrEqual(cur->prefix, nameSpace)))
Daniel Veillardcf461992000-03-14 18:30:20 +00003597 return(cur);
3598 cur = cur->next;
3599 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003600 }
3601 node = node->parent;
3602 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003603 return(NULL);
3604}
3605
Daniel Veillard97b58771998-10-20 06:14:16 +00003606/**
3607 * xmlSearchNsByHref:
3608 * @doc: the document
3609 * @node: the current node
3610 * @href: the namespace value
3611 *
3612 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3613 * the defined namespace or return NULL otherwise.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003614 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003615 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003616xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003617xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003618 xmlNsPtr cur;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003619 xmlNodePtr orig = node;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003620
Daniel Veillard10a2c651999-12-12 13:03:50 +00003621 if ((node == NULL) || (href == NULL)) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003622 while (node != NULL) {
3623 cur = node->nsDef;
3624 while (cur != NULL) {
3625 if ((cur->href != NULL) && (href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003626 (xmlStrEqual(cur->href, href))) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003627 /*
3628 * Check that the prefix is not shadowed between orig and node
3629 */
3630 xmlNodePtr check = orig;
3631 xmlNsPtr tst;
3632
3633 while (check != node) {
3634 tst = check->nsDef;
3635 while (tst != NULL) {
3636 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3637 goto shadowed;
3638 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003639 (xmlStrEqual(tst->prefix, cur->prefix)))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003640 goto shadowed;
3641 tst = tst->next;
3642 }
Daniel Veillardc4f4f0b2000-10-29 17:46:30 +00003643 check = check->parent;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003644 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003645 return(cur);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003646 }
3647shadowed:
Daniel Veillard260a68f1998-08-13 03:39:55 +00003648 cur = cur->next;
3649 }
3650 node = node->parent;
3651 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003652 return(NULL);
3653}
3654
3655/**
3656 * xmlNewReconciliedNs
3657 * @doc: the document
3658 * @tree: a node expected to hold the new namespace
3659 * @ns: the original namespace
3660 *
3661 * This function tries to locate a namespace definition in a tree
3662 * ancestors, or create a new namespace definition node similar to
3663 * @ns trying to reuse the same prefix. However if the given prefix is
3664 * null (default namespace) or reused within the subtree defined by
3665 * @tree or on one of its ancestors then a new prefix is generated.
3666 * Returns the (new) namespace definition or NULL in case of error
3667 */
3668xmlNsPtr
3669xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3670 xmlNsPtr def;
3671 xmlChar prefix[50];
3672 int counter = 1;
3673
3674 if (tree == NULL) {
3675#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003676 xmlGenericError(xmlGenericErrorContext,
3677 "xmlNewReconciliedNs : tree == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003678#endif
3679 return(NULL);
3680 }
3681 if (ns == NULL) {
3682#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003683 xmlGenericError(xmlGenericErrorContext,
3684 "xmlNewReconciliedNs : ns == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003685#endif
3686 return(NULL);
3687 }
3688 /*
3689 * Search an existing namespace definition inherited.
3690 */
3691 def = xmlSearchNsByHref(doc, tree, ns->href);
3692 if (def != NULL)
3693 return(def);
3694
3695 /*
3696 * Find a close prefix which is not already in use.
3697 * Let's strip namespace prefixes longer than 20 chars !
3698 */
3699 sprintf((char *) prefix, "%.20s", ns->prefix);
3700 def = xmlSearchNs(doc, tree, prefix);
3701 while (def != NULL) {
3702 if (counter > 1000) return(NULL);
3703 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
3704 def = xmlSearchNs(doc, tree, prefix);
3705 }
3706
3707 /*
3708 * Ok, now we are ready to create a new one.
3709 */
3710 def = xmlNewNs(tree, ns->href, prefix);
3711 return(def);
3712}
3713
3714/**
3715 * xmlReconciliateNs
3716 * @doc: the document
3717 * @tree: a node defining the subtree to reconciliate
3718 *
3719 * This function checks that all the namespaces declared within the given
3720 * tree are properly declared. This is needed for example after Copy or Cut
3721 * and then paste operations. The subtree may still hold pointers to
3722 * namespace declarations outside the subtree or invalid/masked. As much
3723 * as possible the function try tu reuse the existing namespaces found in
3724 * the new environment. If not possible the new namespaces are redeclared
3725 * on @tree at the top of the given subtree.
3726 * Returns the number of namespace declarations created or -1 in case of error.
3727 */
3728int
3729xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
3730 xmlNsPtr *oldNs = NULL;
3731 xmlNsPtr *newNs = NULL;
3732 int sizeCache = 0;
3733 int nbCache = 0;
3734
3735 xmlNsPtr n;
3736 xmlNodePtr node = tree;
3737 xmlAttrPtr attr;
3738 int ret = 0, i;
3739
3740 while (node != NULL) {
3741 /*
3742 * Reconciliate the node namespace
3743 */
3744 if (node->ns != NULL) {
3745 /*
3746 * initialize the cache if needed
3747 */
3748 if (sizeCache == 0) {
3749 sizeCache = 10;
3750 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3751 sizeof(xmlNsPtr));
3752 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003753 xmlGenericError(xmlGenericErrorContext,
3754 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003755 return(-1);
3756 }
3757 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3758 sizeof(xmlNsPtr));
3759 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003760 xmlGenericError(xmlGenericErrorContext,
3761 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003762 xmlFree(oldNs);
3763 return(-1);
3764 }
3765 }
3766 for (i = 0;i < nbCache;i++) {
3767 if (oldNs[i] == node->ns) {
3768 node->ns = newNs[i];
3769 break;
3770 }
3771 }
3772 if (i == nbCache) {
3773 /*
3774 * Ok we need to recreate a new namespace definition
3775 */
3776 n = xmlNewReconciliedNs(doc, tree, node->ns);
3777 if (n != NULL) { /* :-( what if else ??? */
3778 /*
3779 * check if we need to grow the cache buffers.
3780 */
3781 if (sizeCache <= nbCache) {
3782 sizeCache *= 2;
3783 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3784 sizeof(xmlNsPtr));
3785 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003786 xmlGenericError(xmlGenericErrorContext,
3787 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003788 xmlFree(newNs);
3789 return(-1);
3790 }
3791 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3792 sizeof(xmlNsPtr));
3793 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003794 xmlGenericError(xmlGenericErrorContext,
3795 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003796 xmlFree(oldNs);
3797 return(-1);
3798 }
3799 }
3800 newNs[nbCache] = n;
3801 oldNs[nbCache++] = node->ns;
3802 node->ns = n;
3803 }
3804 }
3805 }
3806 /*
3807 * now check for namespace hold by attributes on the node.
3808 */
3809 attr = node->properties;
3810 while (attr != NULL) {
3811 if (attr->ns != NULL) {
3812 /*
3813 * initialize the cache if needed
3814 */
3815 if (sizeCache == 0) {
3816 sizeCache = 10;
3817 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3818 sizeof(xmlNsPtr));
3819 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003820 xmlGenericError(xmlGenericErrorContext,
3821 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003822 return(-1);
3823 }
3824 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3825 sizeof(xmlNsPtr));
3826 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003827 xmlGenericError(xmlGenericErrorContext,
3828 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003829 xmlFree(oldNs);
3830 return(-1);
3831 }
3832 }
3833 for (i = 0;i < nbCache;i++) {
3834 if (oldNs[i] == attr->ns) {
3835 node->ns = newNs[i];
3836 break;
3837 }
3838 }
3839 if (i == nbCache) {
3840 /*
3841 * Ok we need to recreate a new namespace definition
3842 */
3843 n = xmlNewReconciliedNs(doc, tree, attr->ns);
3844 if (n != NULL) { /* :-( what if else ??? */
3845 /*
3846 * check if we need to grow the cache buffers.
3847 */
3848 if (sizeCache <= nbCache) {
3849 sizeCache *= 2;
3850 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3851 sizeof(xmlNsPtr));
3852 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003853 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003854 "xmlReconciliateNs : memory pbm\n");
3855 xmlFree(newNs);
3856 return(-1);
3857 }
3858 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3859 sizeof(xmlNsPtr));
3860 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003861 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003862 "xmlReconciliateNs : memory pbm\n");
3863 xmlFree(oldNs);
3864 return(-1);
3865 }
3866 }
3867 newNs[nbCache] = n;
3868 oldNs[nbCache++] = attr->ns;
3869 attr->ns = n;
3870 }
3871 }
3872 }
3873 attr = attr->next;
3874 }
3875
3876 /*
3877 * Browse the full subtree, deep first
3878 */
Daniel Veillardcf461992000-03-14 18:30:20 +00003879 if (node->children != NULL) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003880 /* deep first */
Daniel Veillardcf461992000-03-14 18:30:20 +00003881 node = node->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003882 } else if ((node != tree) && (node->next != NULL)) {
3883 /* then siblings */
3884 node = node->next;
3885 } else if (node != tree) {
3886 /* go up to parents->next if needed */
3887 while (node != tree) {
3888 if (node->parent != NULL)
3889 node = node->parent;
3890 if ((node != tree) && (node->next != NULL)) {
3891 node = node->next;
3892 break;
3893 }
3894 if (node->parent == NULL) {
3895 node = NULL;
3896 break;
3897 }
3898 }
3899 /* exit condition */
3900 if (node == tree)
3901 node = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003902 }
3903 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003904 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003905}
3906
Daniel Veillard97b58771998-10-20 06:14:16 +00003907/**
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003908 * xmlHasProp:
3909 * @node: the node
3910 * @name: the attribute name
3911 *
3912 * Search an attribute associated to a node
3913 * This function also looks in DTD attribute declaration for #FIXED or
3914 * default declaration values unless DTD use has been turned off.
3915 *
3916 * Returns the attribute or the attribute declaration or NULL if
3917 * neither was found.
3918 */
3919xmlAttrPtr
3920xmlHasProp(xmlNodePtr node, const xmlChar *name) {
3921 xmlAttrPtr prop;
3922 xmlDocPtr doc;
3923
3924 if ((node == NULL) || (name == NULL)) return(NULL);
3925 /*
3926 * Check on the properties attached to the node
3927 */
3928 prop = node->properties;
3929 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003930 if (xmlStrEqual(prop->name, name)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003931 return(prop);
3932 }
3933 prop = prop->next;
3934 }
3935 if (!xmlCheckDTD) return(NULL);
3936
3937 /*
3938 * Check if there is a default declaration in the internal
3939 * or external subsets
3940 */
3941 doc = node->doc;
3942 if (doc != NULL) {
3943 xmlAttributePtr attrDecl;
3944 if (doc->intSubset != NULL) {
3945 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3946 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3947 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
3948 if (attrDecl != NULL)
3949 return((xmlAttrPtr) attrDecl);
3950 }
3951 }
3952 return(NULL);
3953}
3954
3955/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003956 * xmlGetProp:
3957 * @node: the node
3958 * @name: the attribute name
3959 *
3960 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00003961 * This does the entity substitution.
Daniel Veillard10a2c651999-12-12 13:03:50 +00003962 * This function looks in DTD attribute declaration for #FIXED or
3963 * default declaration values unless DTD use has been turned off.
3964 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003965 * Returns the attribute value or NULL if not found.
Daniel Veillarda819dac1999-11-24 18:04:22 +00003966 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003967 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003968xmlChar *
3969xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003970 xmlAttrPtr prop;
3971 xmlDocPtr doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003972
Daniel Veillard10a2c651999-12-12 13:03:50 +00003973 if ((node == NULL) || (name == NULL)) return(NULL);
3974 /*
3975 * Check on the properties attached to the node
3976 */
3977 prop = node->properties;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003978 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003979 if (xmlStrEqual(prop->name, name)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003980 xmlChar *ret;
Daniel Veillard6800ef31999-02-08 18:33:22 +00003981
Daniel Veillardcf461992000-03-14 18:30:20 +00003982 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003983 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
Daniel Veillard6800ef31999-02-08 18:33:22 +00003984 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00003985 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003986 prop = prop->next;
3987 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003988 if (!xmlCheckDTD) return(NULL);
3989
3990 /*
3991 * Check if there is a default declaration in the internal
3992 * or external subsets
3993 */
3994 doc = node->doc;
3995 if (doc != NULL) {
3996 xmlAttributePtr attrDecl;
3997 if (doc->intSubset != NULL) {
3998 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3999 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4000 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillardf967b902000-01-17 16:06:10 +00004001 if (attrDecl != NULL)
4002 return(xmlStrdup(attrDecl->defaultValue));
Daniel Veillard10a2c651999-12-12 13:03:50 +00004003 }
4004 }
4005 return(NULL);
4006}
4007
4008/**
4009 * xmlGetNsProp:
4010 * @node: the node
4011 * @name: the attribute name
4012 * @namespace: the URI of the namespace
4013 *
4014 * Search and get the value of an attribute associated to a node
4015 * This attribute has to be anchored in the namespace specified.
4016 * This does the entity substitution.
4017 * This function looks in DTD attribute declaration for #FIXED or
4018 * default declaration values unless DTD use has been turned off.
4019 *
4020 * Returns the attribute value or NULL if not found.
4021 * It's up to the caller to free the memory.
4022 */
4023xmlChar *
4024xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
4025 xmlAttrPtr prop = node->properties;
4026 xmlDocPtr doc;
4027 xmlNsPtr ns;
4028
4029 if (namespace == NULL)
4030 return(xmlGetProp(node, name));
4031 while (prop != NULL) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00004032 /*
4033 * One need to have
4034 * - same attribute names
4035 * - and the attribute carrying that namespace
4036 * or
4037 * no namespace on the attribute and the element carrying it
4038 */
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004039 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00004040 (((prop->ns == NULL) && (node->ns != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004041 (xmlStrEqual(node->ns->href, namespace))) ||
4042 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, namespace))))) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00004043 xmlChar *ret;
4044
Daniel Veillardcf461992000-03-14 18:30:20 +00004045 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillard10a2c651999-12-12 13:03:50 +00004046 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4047 return(ret);
4048 }
4049 prop = prop->next;
4050 }
4051 if (!xmlCheckDTD) return(NULL);
4052
4053 /*
4054 * Check if there is a default declaration in the internal
4055 * or external subsets
4056 */
4057 doc = node->doc;
4058 if (doc != NULL) {
4059 xmlAttributePtr attrDecl;
4060 if (doc->intSubset != NULL) {
4061 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4062 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4063 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4064
4065 if (attrDecl->prefix != NULL) {
4066 /*
4067 * The DTD declaration only allows a prefix search
4068 */
4069 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004070 if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
Daniel Veillard10a2c651999-12-12 13:03:50 +00004071 return(xmlStrdup(attrDecl->defaultValue));
4072 }
4073 }
4074 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004075 return(NULL);
4076}
4077
Daniel Veillard97b58771998-10-20 06:14:16 +00004078/**
Daniel Veillardccb09631998-10-27 06:21:04 +00004079 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00004080 * @node: the node
4081 * @name: the attribute name
4082 * @value: the attribute value
4083 *
4084 * Set (or reset) an attribute carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00004085 * Returns the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004086 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004087xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004088xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004089 xmlAttrPtr prop = node->properties;
4090
4091 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004092 if (xmlStrEqual(prop->name, name)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00004093 if (prop->children != NULL)
4094 xmlFreeNodeList(prop->children);
4095 prop->children = NULL;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004096 prop->last = NULL;
Daniel Veillard51e3b151999-11-12 17:02:31 +00004097 if (value != NULL) {
4098 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +00004099 xmlNodePtr tmp;
4100
Daniel Veillard51e3b151999-11-12 17:02:31 +00004101 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +00004102 prop->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004103 prop->last = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00004104 tmp = prop->children;
4105 while (tmp != NULL) {
4106 tmp->parent = (xmlNodePtr) prop;
4107 if (tmp->next == NULL)
4108 prop->last = tmp;
4109 tmp = tmp->next;
4110 }
Daniel Veillard51e3b151999-11-12 17:02:31 +00004111 xmlFree(buffer);
4112 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004113 return(prop);
4114 }
4115 prop = prop->next;
4116 }
4117 prop = xmlNewProp(node, name, value);
4118 return(prop);
4119}
4120
Daniel Veillard97b58771998-10-20 06:14:16 +00004121/**
4122 * xmlNodeIsText:
4123 * @node: the node
4124 *
4125 * Is this node a Text node ?
Daniel Veillard1e346af1999-02-22 10:33:01 +00004126 * Returns 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00004127 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004128int
4129xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004130 if (node == NULL) return(0);
4131
Daniel Veillard0bef1311998-10-14 02:36:47 +00004132 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004133 return(0);
4134}
4135
Daniel Veillard97b58771998-10-20 06:14:16 +00004136/**
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004137 * xmlIsBlankNode:
4138 * @node: the node
4139 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004140 * Checks whether this node is an empty or whitespace only
4141 * (and possibly ignorable) text-node.
4142 *
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004143 * Returns 1 yes, 0 no
4144 */
4145int
4146xmlIsBlankNode(xmlNodePtr node) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004147 const xmlChar *cur;
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004148 if (node == NULL) return(0);
4149
4150 if (node->type != XML_TEXT_NODE) return(0);
Daniel Veillardcd429612000-10-11 15:57:05 +00004151 if (node->content == NULL) return(1);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004152#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004153 cur = node->content;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004154#else
4155 cur = xmlBufferContent(node->content);
4156#endif
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004157 while (*cur != 0) {
4158 if (!IS_BLANK(*cur)) return(0);
4159 cur++;
4160 }
4161
4162 return(1);
4163}
4164
4165/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00004166 * xmlTextConcat:
Daniel Veillard97b58771998-10-20 06:14:16 +00004167 * @node: the node
4168 * @content: the content
4169 * @len: @content lenght
4170 *
4171 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00004172 */
Daniel Veillard97b58771998-10-20 06:14:16 +00004173
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004174void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004175xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004176 if (node == NULL) return;
4177
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004178 if ((node->type != XML_TEXT_NODE) &&
4179 (node->type != XML_CDATA_SECTION_NODE)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004180#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004181 xmlGenericError(xmlGenericErrorContext,
4182 "xmlTextConcat: node is not text nor cdata\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004183#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004184 return;
4185 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004186#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00004187 node->content = xmlStrncat(node->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004188#else
4189 xmlBufferAdd(node->content, content, len);
4190#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004191}
4192
4193/************************************************************************
4194 * *
4195 * Output : to a FILE or in memory *
4196 * *
4197 ************************************************************************/
4198
Daniel Veillard5099ae81999-04-21 20:12:07 +00004199#define BASE_BUFFER_SIZE 4000
4200
4201/**
4202 * xmlBufferCreate:
4203 *
4204 * routine to create an XML buffer.
4205 * returns the new structure.
4206 */
4207xmlBufferPtr
4208xmlBufferCreate(void) {
4209 xmlBufferPtr ret;
4210
Daniel Veillard6454aec1999-09-02 22:04:43 +00004211 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
Daniel Veillard5099ae81999-04-21 20:12:07 +00004212 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004213 xmlGenericError(xmlGenericErrorContext,
4214 "xmlBufferCreate : out of memory!\n");
Daniel Veillard5099ae81999-04-21 20:12:07 +00004215 return(NULL);
4216 }
4217 ret->use = 0;
4218 ret->size = BASE_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004219 ret->alloc = xmlBufferAllocScheme;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004220 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
Daniel Veillard5099ae81999-04-21 20:12:07 +00004221 if (ret->content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004222 xmlGenericError(xmlGenericErrorContext,
4223 "xmlBufferCreate : out of memory!\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00004224 xmlFree(ret);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004225 return(NULL);
4226 }
4227 ret->content[0] = 0;
4228 return(ret);
4229}
4230
4231/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004232 * xmlBufferCreateSize:
4233 * @size: initial size of buffer
4234 *
4235 * routine to create an XML buffer.
4236 * returns the new structure.
4237 */
4238xmlBufferPtr
4239xmlBufferCreateSize(size_t size) {
4240 xmlBufferPtr ret;
4241
4242 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4243 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004244 xmlGenericError(xmlGenericErrorContext,
4245 "xmlBufferCreate : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004246 return(NULL);
4247 }
4248 ret->use = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004249 ret->alloc = xmlBufferAllocScheme;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004250 ret->size = (size ? size+2 : 0); /* +1 for ending null */
Daniel Veillard10a2c651999-12-12 13:03:50 +00004251 if (ret->size){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004252 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4253 if (ret->content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004254 xmlGenericError(xmlGenericErrorContext,
4255 "xmlBufferCreate : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004256 xmlFree(ret);
4257 return(NULL);
4258 }
4259 ret->content[0] = 0;
4260 } else
4261 ret->content = NULL;
4262 return(ret);
4263}
4264
4265/**
Daniel Veillard06047432000-04-24 11:33:38 +00004266 * xmlBufferSetAllocationScheme:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004267 * @buf: the buffer to free
4268 * @scheme: allocation scheme to use
4269 *
4270 * Sets the allocation scheme for this buffer
4271 */
4272void
4273xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4274 xmlBufferAllocationScheme scheme) {
4275 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004276#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004277 xmlGenericError(xmlGenericErrorContext,
4278 "xmlBufferSetAllocationScheme: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004279#endif
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004280 return;
4281 }
4282
4283 buf->alloc = scheme;
4284}
4285
4286/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004287 * xmlBufferFree:
4288 * @buf: the buffer to free
4289 *
4290 * Frees an XML buffer.
4291 */
4292void
4293xmlBufferFree(xmlBufferPtr buf) {
4294 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004295#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004296 xmlGenericError(xmlGenericErrorContext,
4297 "xmlBufferFree: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004298#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004299 return;
4300 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004301 if (buf->content != NULL) {
4302#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00004303 memset(buf->content, -1, BASE_BUFFER_SIZE);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004304#else
4305 memset(buf->content, -1, buf->size);
4306#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004307 xmlFree(buf->content);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004308 }
4309 memset(buf, -1, sizeof(xmlBuffer));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004310 xmlFree(buf);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004311}
4312
4313/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004314 * xmlBufferEmpty:
4315 * @buf: the buffer
4316 *
4317 * empty a buffer.
4318 */
4319void
4320xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +00004321 if (buf->content == NULL) return;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004322 buf->use = 0;
4323 memset(buf->content, -1, buf->size);/* just for debug */
4324}
4325
4326/**
4327 * xmlBufferShrink:
4328 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004329 * @len: the number of xmlChar to remove
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004330 *
4331 * Remove the beginning of an XML buffer.
4332 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004333 * Returns the number of xmlChar removed, or -1 in case of failure.
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004334 */
4335int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004336xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004337 if (len == 0) return(0);
4338 if (len > buf->use) return(-1);
4339
4340 buf->use -= len;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004341 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004342
4343 buf->content[buf->use] = 0;
4344 return(len);
4345}
4346
4347/**
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004348 * xmlBufferGrow:
4349 * @buf: the buffer
Daniel Veillard4a6845d2001-01-03 13:32:39 +00004350 * @len: the minimum free size to allocate
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004351 *
4352 * Grow the available space of an XML buffer.
4353 *
4354 * Returns the new available space or -1 in case of error
4355 */
4356int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004357xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004358 int size;
4359 xmlChar *newbuf;
4360
Daniel Veillard4a6845d2001-01-03 13:32:39 +00004361 if (len + buf->use < buf->size) return(0);
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004362
Daniel Veillardbe803962000-06-28 23:40:59 +00004363 size = buf->use + len + 100;
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004364
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004365 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004366 if (newbuf == NULL) return(-1);
4367 buf->content = newbuf;
4368 buf->size = size;
4369 return(buf->size - buf->use);
4370}
4371
4372/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004373 * xmlBufferDump:
4374 * @file: the file output
4375 * @buf: the buffer to dump
4376 *
4377 * Dumps an XML buffer to a FILE *.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004378 * Returns the number of xmlChar written
Daniel Veillard5099ae81999-04-21 20:12:07 +00004379 */
4380int
4381xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4382 int ret;
4383
4384 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004385#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004386 xmlGenericError(xmlGenericErrorContext,
4387 "xmlBufferDump: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004388#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004389 return(0);
4390 }
4391 if (buf->content == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004392#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004393 xmlGenericError(xmlGenericErrorContext,
4394 "xmlBufferDump: buf->content == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004395#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004396 return(0);
4397 }
4398 if (file == NULL) file = stdout;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004399 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004400 return(ret);
4401}
4402
4403/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004404 * xmlBufferContent:
4405 * @buf: the buffer to resize
4406 *
4407 * Returns the internal content
4408 */
4409
4410const xmlChar*
4411xmlBufferContent(const xmlBufferPtr buf)
4412{
4413 if(!buf)
4414 return NULL;
4415
4416 return buf->content;
4417}
4418
4419/**
4420 * xmlBufferLength:
4421 * @buf: the buffer
4422 *
4423 * Returns the length of data in the internal content
4424 */
4425
4426int
4427xmlBufferLength(const xmlBufferPtr buf)
4428{
4429 if(!buf)
4430 return 0;
4431
4432 return buf->use;
4433}
4434
4435/**
4436 * xmlBufferResize:
4437 * @buf: the buffer to resize
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004438 * @size: the desired size
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004439 *
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004440 * Resize a buffer to accomodate minimum size of @size.
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004441 *
4442 * Returns 0 in case of problems, 1 otherwise
4443 */
4444int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004445xmlBufferResize(xmlBufferPtr buf, unsigned int size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004446{
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004447 unsigned int newSize;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004448 xmlChar* rebuf = NULL;
4449
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004450 /*take care of empty case*/
4451 newSize = (buf->size ? buf->size*2 : size);
4452
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004453 /* Don't resize if we don't have to */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004454 if (size < buf->size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004455 return 1;
4456
4457 /* figure out new size */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004458 switch (buf->alloc){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004459 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004460 while (size > newSize) newSize *= 2;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004461 break;
4462 case XML_BUFFER_ALLOC_EXACT:
4463 newSize = size+10;
4464 break;
4465 default:
4466 newSize = size+10;
4467 break;
4468 }
4469
4470 if (buf->content == NULL)
4471 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
4472 else
4473 rebuf = (xmlChar *) xmlRealloc(buf->content,
4474 newSize * sizeof(xmlChar));
4475 if (rebuf == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004476 xmlGenericError(xmlGenericErrorContext,
4477 "xmlBufferAdd : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004478 return 0;
4479 }
4480 buf->content = rebuf;
4481 buf->size = newSize;
4482
4483 return 1;
4484}
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004485
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004486/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004487 * xmlBufferAdd:
4488 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004489 * @str: the xmlChar string
4490 * @len: the number of xmlChar to add
Daniel Veillard5099ae81999-04-21 20:12:07 +00004491 *
Daniel Veillard10a2c651999-12-12 13:03:50 +00004492 * Add a string range to an XML buffer. if len == -1, the lenght of
4493 * str is recomputed.
Daniel Veillard5099ae81999-04-21 20:12:07 +00004494 */
4495void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004496xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004497 unsigned int needSize;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004498
4499 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004500#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004501 xmlGenericError(xmlGenericErrorContext,
4502 "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004503#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004504 return;
4505 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00004506 if (len < -1) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004507#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004508 xmlGenericError(xmlGenericErrorContext,
4509 "xmlBufferAdd: len < 0\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004510#endif
Daniel Veillard10a2c651999-12-12 13:03:50 +00004511 return;
4512 }
4513 if (len == 0) return;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004514
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004515 if (len < 0)
Daniel Veillardcf461992000-03-14 18:30:20 +00004516 len = xmlStrlen(str);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004517
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004518 if (len <= 0) return;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004519
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004520 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004521 if (needSize > buf->size){
4522 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004523 xmlGenericError(xmlGenericErrorContext,
4524 "xmlBufferAdd : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004525 return;
4526 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004527 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004528
4529 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004530 buf->use += len;
4531 buf->content[buf->use] = 0;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004532}
4533
4534/**
Daniel Veillardbe803962000-06-28 23:40:59 +00004535 * xmlBufferAddHead:
4536 * @buf: the buffer
4537 * @str: the xmlChar string
4538 * @len: the number of xmlChar to add
4539 *
4540 * Add a string range to the beginning of an XML buffer.
4541 * if len == -1, the lenght of @str is recomputed.
4542 */
4543void
4544xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004545 unsigned int needSize;
Daniel Veillardbe803962000-06-28 23:40:59 +00004546
4547 if (str == NULL) {
4548#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004549 xmlGenericError(xmlGenericErrorContext,
4550 "xmlBufferAdd: str == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004551#endif
4552 return;
4553 }
4554 if (len < -1) {
4555#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004556 xmlGenericError(xmlGenericErrorContext,
4557 "xmlBufferAdd: len < 0\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004558#endif
4559 return;
4560 }
4561 if (len == 0) return;
4562
4563 if (len < 0)
4564 len = xmlStrlen(str);
4565
4566 if (len <= 0) return;
4567
4568 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004569 if (needSize > buf->size){
4570 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004571 xmlGenericError(xmlGenericErrorContext,
4572 "xmlBufferAddHead : out of memory!\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004573 return;
4574 }
4575 }
4576
4577 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
4578 memmove(&buf->content[0], str, len * sizeof(xmlChar));
4579 buf->use += len;
4580 buf->content[buf->use] = 0;
4581}
4582
4583/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004584 * xmlBufferCat:
4585 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004586 * @str: the xmlChar string
Daniel Veillard5099ae81999-04-21 20:12:07 +00004587 *
4588 * Append a zero terminated string to an XML buffer.
4589 */
4590void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004591xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004592 if (str != NULL)
4593 xmlBufferAdd(buf, str, -1);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004594}
4595
4596/**
4597 * xmlBufferCCat:
4598 * @buf: the buffer to dump
4599 * @str: the C char string
4600 *
4601 * Append a zero terminated C string to an XML buffer.
4602 */
4603void
4604xmlBufferCCat(xmlBufferPtr buf, const char *str) {
4605 const char *cur;
4606
4607 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004608#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004609 xmlGenericError(xmlGenericErrorContext,
4610 "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004611#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004612 return;
4613 }
4614 for (cur = str;*cur != 0;cur++) {
4615 if (buf->use + 10 >= buf->size) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004616 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004617 xmlGenericError(xmlGenericErrorContext,
4618 "xmlBufferCCat : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004619 return;
4620 }
4621 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004622 buf->content[buf->use++] = *cur;
4623 }
4624}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004625
Daniel Veillard97b58771998-10-20 06:14:16 +00004626/**
4627 * xmlBufferWriteCHAR:
Daniel Veillard5099ae81999-04-21 20:12:07 +00004628 * @buf: the XML buffer
Daniel Veillard97b58771998-10-20 06:14:16 +00004629 * @string: the string to add
4630 *
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004631 * routine which manages and grows an output buffer. This one adds
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004632 * xmlChars at the end of the buffer.
Daniel Veillard97b58771998-10-20 06:14:16 +00004633 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004634void
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004635#ifdef VMS
4636xmlBufferWriteXmlCHAR
4637#else
4638xmlBufferWriteCHAR
4639#endif
4640(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004641 xmlBufferCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004642}
4643
Daniel Veillard97b58771998-10-20 06:14:16 +00004644/**
4645 * xmlBufferWriteChar:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004646 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004647 * @string: the string to add
4648 *
4649 * routine which manage and grows an output buffer. This one add
4650 * C chars at the end of the array.
4651 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004652void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004653xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
4654 xmlBufferCCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004655}
4656
Daniel Veillard5099ae81999-04-21 20:12:07 +00004657
Daniel Veillard97b58771998-10-20 06:14:16 +00004658/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004659 * xmlBufferWriteQuotedString:
4660 * @buf: the XML buffer output
4661 * @string: the string to add
4662 *
4663 * routine which manage and grows an output buffer. This one writes
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004664 * a quoted or double quoted xmlChar string, checking first if it holds
Daniel Veillard011b63c1999-06-02 17:44:04 +00004665 * quote or double-quotes internally
4666 */
4667void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004668xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004669 if (xmlStrchr(string, '"')) {
4670 if (xmlStrchr(string, '\'')) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004671#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004672 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard011b63c1999-06-02 17:44:04 +00004673 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004674#endif
Daniel Veillard011b63c1999-06-02 17:44:04 +00004675 }
4676 xmlBufferCCat(buf, "'");
4677 xmlBufferCat(buf, string);
4678 xmlBufferCCat(buf, "'");
4679 } else {
4680 xmlBufferCCat(buf, "\"");
4681 xmlBufferCat(buf, string);
4682 xmlBufferCCat(buf, "\"");
4683 }
4684}
4685
4686
Daniel Veillardbe803962000-06-28 23:40:59 +00004687/************************************************************************
4688 * *
4689 * Dumping XML tree content to a simple buffer *
4690 * *
4691 ************************************************************************/
4692
Daniel Veillardb656ebe2000-09-22 13:51:48 +00004693void
Daniel Veillardcf461992000-03-14 18:30:20 +00004694xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4695 int format);
4696static void
4697xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4698 int format);
4699void
4700htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
4701
Daniel Veillard011b63c1999-06-02 17:44:04 +00004702/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004703 * xmlNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004704 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004705 * @cur: a namespace
4706 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004707 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00004708 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004709 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004710static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004711xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004712 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004713#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004714 xmlGenericError(xmlGenericErrorContext,
4715 "xmlNsDump : Ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004716#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004717 return;
4718 }
4719 if (cur->type == XML_LOCAL_NAMESPACE) {
4720 /* Within the context of an element attributes */
4721 if (cur->prefix != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004722 xmlBufferWriteChar(buf, " xmlns:");
4723 xmlBufferWriteCHAR(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004724 } else
Daniel Veillard5099ae81999-04-21 20:12:07 +00004725 xmlBufferWriteChar(buf, " xmlns");
Daniel Veillard011b63c1999-06-02 17:44:04 +00004726 xmlBufferWriteChar(buf, "=");
4727 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004728 }
4729}
4730
Daniel Veillard97b58771998-10-20 06:14:16 +00004731/**
4732 * xmlNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004733 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004734 * @cur: the first namespace
4735 *
4736 * Dump a list of local Namespace definitions.
4737 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004738 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004739static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004740xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004741 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004742 xmlNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004743 cur = cur->next;
4744 }
4745}
4746
Daniel Veillard97b58771998-10-20 06:14:16 +00004747/**
4748 * xmlDtdDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004749 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004750 * @doc: the document
4751 *
4752 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004753 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004754static void
Daniel Veillardcf461992000-03-14 18:30:20 +00004755xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
4756 if (dtd == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004757#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004758 xmlGenericError(xmlGenericErrorContext,
4759 "xmlDtdDump : no internal subset\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004760#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004761 return;
4762 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004763 xmlBufferWriteChar(buf, "<!DOCTYPE ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004764 xmlBufferWriteCHAR(buf, dtd->name);
4765 if (dtd->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004766 xmlBufferWriteChar(buf, " PUBLIC ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004767 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004768 xmlBufferWriteChar(buf, " ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004769 xmlBufferWriteQuotedString(buf, dtd->SystemID);
4770 } else if (dtd->SystemID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004771 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004772 xmlBufferWriteQuotedString(buf, dtd->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004773 }
Daniel Veillardcf461992000-03-14 18:30:20 +00004774 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
4775 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
4776 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004777 return;
4778 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004779 xmlBufferWriteChar(buf, " [\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00004780 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
4781#if 0
4782 if (dtd->entities != NULL)
4783 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
4784 if (dtd->notations != NULL)
4785 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
4786 if (dtd->elements != NULL)
4787 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
4788 if (dtd->attributes != NULL)
4789 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
4790#endif
4791 xmlBufferWriteChar(buf, "]>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004792}
4793
Daniel Veillard97b58771998-10-20 06:14:16 +00004794/**
4795 * xmlAttrDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004796 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004797 * @doc: the document
4798 * @cur: the attribute pointer
4799 *
4800 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00004801 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004802static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004803xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004804 xmlChar *value;
Daniel Veillardccb09631998-10-27 06:21:04 +00004805
Daniel Veillard260a68f1998-08-13 03:39:55 +00004806 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004807#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004808 xmlGenericError(xmlGenericErrorContext,
4809 "xmlAttrDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004810#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004811 return;
4812 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004813 xmlBufferWriteChar(buf, " ");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004814 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4815 xmlBufferWriteCHAR(buf, cur->ns->prefix);
4816 xmlBufferWriteChar(buf, ":");
4817 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004818 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00004819 value = xmlNodeListGetString(doc, cur->children, 0);
Daniel Veillardccb09631998-10-27 06:21:04 +00004820 if (value) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004821 xmlBufferWriteChar(buf, "=");
4822 xmlBufferWriteQuotedString(buf, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004823 xmlFree(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00004824 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004825 xmlBufferWriteChar(buf, "=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004826 }
4827}
4828
Daniel Veillard97b58771998-10-20 06:14:16 +00004829/**
4830 * xmlAttrListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004831 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004832 * @doc: the document
4833 * @cur: the first attribute pointer
4834 *
4835 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00004836 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004837static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004838xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004839 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004840#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004841 xmlGenericError(xmlGenericErrorContext,
4842 "xmlAttrListDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004843#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004844 return;
4845 }
4846 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004847 xmlAttrDump(buf, doc, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004848 cur = cur->next;
4849 }
4850}
4851
Daniel Veillard260a68f1998-08-13 03:39:55 +00004852
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004853
Daniel Veillard97b58771998-10-20 06:14:16 +00004854/**
4855 * xmlNodeListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004856 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004857 * @doc: the document
4858 * @cur: the first node
Daniel Veillardcf461992000-03-14 18:30:20 +00004859 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004860 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004861 *
4862 * Dump an XML node list, recursive behaviour,children are printed too.
4863 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004864static void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004865xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4866 int format) {
4867 int i;
Daniel Veillardccb09631998-10-27 06:21:04 +00004868
Daniel Veillard260a68f1998-08-13 03:39:55 +00004869 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004870#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004871 xmlGenericError(xmlGenericErrorContext,
4872 "xmlNodeListDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004873#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004874 return;
4875 }
4876 while (cur != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004877 if ((format) && (xmlIndentTreeOutput) &&
4878 (cur->type == XML_ELEMENT_NODE))
4879 for (i = 0;i < level;i++)
4880 xmlBufferWriteChar(buf, " ");
4881 xmlNodeDump(buf, doc, cur, level, format);
4882 if (format) {
4883 xmlBufferWriteChar(buf, "\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00004884 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004885 cur = cur->next;
4886 }
4887}
4888
Daniel Veillard97b58771998-10-20 06:14:16 +00004889/**
Daniel Veillardccb09631998-10-27 06:21:04 +00004890 * xmlNodeDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004891 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004892 * @doc: the document
4893 * @cur: the current node
Daniel Veillardcf461992000-03-14 18:30:20 +00004894 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004895 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004896 *
4897 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004898 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00004899void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004900xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4901 int format) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004902 int i;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004903 xmlNodePtr tmp;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004904
4905 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004906#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004907 xmlGenericError(xmlGenericErrorContext,
4908 "xmlNodeDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004909#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004910 return;
4911 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004912 if (cur->type == XML_XINCLUDE_START)
4913 return;
4914 if (cur->type == XML_XINCLUDE_END)
4915 return;
Daniel Veillardcf461992000-03-14 18:30:20 +00004916 if (cur->type == XML_DTD_NODE) {
4917 xmlDtdDump(buf, (xmlDtdPtr) cur);
4918 return;
4919 }
4920 if (cur->type == XML_ELEMENT_DECL) {
4921 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
4922 return;
4923 }
4924 if (cur->type == XML_ATTRIBUTE_DECL) {
4925 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
4926 return;
4927 }
4928 if (cur->type == XML_ENTITY_DECL) {
4929 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
4930 return;
4931 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00004932 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard14fff061999-06-22 21:49:07 +00004933 if (cur->content != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004934 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00004935
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004936#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +00004937 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004938#else
4939 buffer = xmlEncodeEntitiesReentrant(doc,
4940 xmlBufferContent(cur->content));
4941#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00004942 if (buffer != NULL) {
4943 xmlBufferWriteCHAR(buf, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004944 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +00004945 }
4946 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004947 return;
4948 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004949 if (cur->type == XML_PI_NODE) {
4950 if (cur->content != NULL) {
4951 xmlBufferWriteChar(buf, "<?");
4952 xmlBufferWriteCHAR(buf, cur->name);
4953 if (cur->content != NULL) {
4954 xmlBufferWriteChar(buf, " ");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004955#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00004956 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004957#else
4958 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4959#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00004960 }
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004961 xmlBufferWriteChar(buf, "?>");
Daniel Veillardcf461992000-03-14 18:30:20 +00004962 } else {
4963 xmlBufferWriteChar(buf, "<?");
4964 xmlBufferWriteCHAR(buf, cur->name);
4965 xmlBufferWriteChar(buf, "?>");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004966 }
4967 return;
4968 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00004969 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004970 if (cur->content != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004971 xmlBufferWriteChar(buf, "<!--");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004972#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00004973 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004974#else
4975 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4976#endif
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004977 xmlBufferWriteChar(buf, "-->");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004978 }
4979 return;
4980 }
Daniel Veillardccb09631998-10-27 06:21:04 +00004981 if (cur->type == XML_ENTITY_REF_NODE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004982 xmlBufferWriteChar(buf, "&");
4983 xmlBufferWriteCHAR(buf, cur->name);
4984 xmlBufferWriteChar(buf, ";");
Daniel Veillardccb09631998-10-27 06:21:04 +00004985 return;
4986 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00004987 if (cur->type == XML_CDATA_SECTION_NODE) {
4988 xmlBufferWriteChar(buf, "<![CDATA[");
4989 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004990#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00004991 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004992#else
4993 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4994#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00004995 xmlBufferWriteChar(buf, "]]>");
4996 return;
4997 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004998
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004999 if (format == 1) {
Daniel Veillardcf461992000-03-14 18:30:20 +00005000 tmp = cur->children;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005001 while (tmp != NULL) {
5002 if ((tmp->type == XML_TEXT_NODE) ||
5003 (tmp->type == XML_ENTITY_REF_NODE)) {
5004 format = 0;
5005 break;
5006 }
5007 tmp = tmp->next;
5008 }
5009 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005010 xmlBufferWriteChar(buf, "<");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005011 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005012 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5013 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005014 }
5015
Daniel Veillard5099ae81999-04-21 20:12:07 +00005016 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005017 if (cur->nsDef)
Daniel Veillard5099ae81999-04-21 20:12:07 +00005018 xmlNsListDump(buf, cur->nsDef);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005019 if (cur->properties != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00005020 xmlAttrListDump(buf, doc, cur->properties);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005021
Daniel Veillardcf461992000-03-14 18:30:20 +00005022 if ((cur->content == NULL) && (cur->children == NULL) &&
Daniel Veillarde41f2b72000-01-30 20:00:07 +00005023 (!xmlSaveNoEmptyTags)) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005024 xmlBufferWriteChar(buf, "/>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005025 return;
5026 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005027 xmlBufferWriteChar(buf, ">");
Daniel Veillard14fff061999-06-22 21:49:07 +00005028 if (cur->content != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005029 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00005030
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005031#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +00005032 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005033#else
5034 buffer = xmlEncodeEntitiesReentrant(doc,
5035 xmlBufferContent(cur->content));
5036#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00005037 if (buffer != NULL) {
5038 xmlBufferWriteCHAR(buf, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005039 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +00005040 }
5041 }
Daniel Veillardcf461992000-03-14 18:30:20 +00005042 if (cur->children != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005043 if (format) xmlBufferWriteChar(buf, "\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00005044 xmlNodeListDump(buf, doc, cur->children,
Daniel Veillard3e6d2372000-03-04 11:39:43 +00005045 (level >= 0?level+1:-1), format);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005046 if ((xmlIndentTreeOutput) && (format))
5047 for (i = 0;i < level;i++)
5048 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005049 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005050 xmlBufferWriteChar(buf, "</");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005051 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005052 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5053 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005054 }
5055
Daniel Veillard5099ae81999-04-21 20:12:07 +00005056 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005057 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005058}
5059
Daniel Veillard97b58771998-10-20 06:14:16 +00005060/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005061 * xmlElemDump:
Daniel Veillard06047432000-04-24 11:33:38 +00005062 * @f: the FILE * for the output
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005063 * @doc: the document
5064 * @cur: the current node
5065 *
5066 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5067 */
5068void
5069xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5070 xmlBufferPtr buf;
5071
5072 if (cur == NULL) {
5073#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005074 xmlGenericError(xmlGenericErrorContext,
5075 "xmlElemDump : cur == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005076#endif
5077 return;
5078 }
5079 if (doc == NULL) {
5080#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005081 xmlGenericError(xmlGenericErrorContext,
5082 "xmlElemDump : doc == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005083#endif
5084 }
5085 buf = xmlBufferCreate();
5086 if (buf == NULL) return;
5087 if ((doc != NULL) &&
5088 (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard361d8452000-04-03 19:48:13 +00005089#ifdef LIBXML_HTML_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005090 htmlNodeDump(buf, doc, cur);
Daniel Veillard361d8452000-04-03 19:48:13 +00005091#else
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005092 xmlGenericError(xmlGenericErrorContext,
5093 "HTML support not compiled in\n");
Daniel Veillard361d8452000-04-03 19:48:13 +00005094#endif /* LIBXML_HTML_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005095 } else
5096 xmlNodeDump(buf, doc, cur, 0, 1);
5097 xmlBufferDump(f, buf);
5098 xmlBufferFree(buf);
5099}
5100
Daniel Veillardbe803962000-06-28 23:40:59 +00005101/************************************************************************
5102 * *
5103 * Dumping XML tree content to an I/O output buffer *
5104 * *
5105 ************************************************************************/
5106
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005107void
Daniel Veillardbe803962000-06-28 23:40:59 +00005108xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5109 int level, int format, const char *encoding);
5110static void
5111xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5112 int level, int format, const char *encoding);
5113/**
Daniel Veillardbe803962000-06-28 23:40:59 +00005114 * xmlNsDumpOutput:
5115 * @buf: the XML buffer output
5116 * @cur: a namespace
5117 *
5118 * Dump a local Namespace definition.
5119 * Should be called in the context of attributes dumps.
5120 */
5121static void
5122xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5123 if (cur == NULL) {
5124#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005125 xmlGenericError(xmlGenericErrorContext,
5126 "xmlNsDump : Ns == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005127#endif
5128 return;
5129 }
Daniel Veillarde0854c32000-08-27 21:12:29 +00005130 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005131 /* Within the context of an element attributes */
5132 if (cur->prefix != NULL) {
5133 xmlOutputBufferWriteString(buf, " xmlns:");
5134 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5135 } else
5136 xmlOutputBufferWriteString(buf, " xmlns");
5137 xmlOutputBufferWriteString(buf, "=");
5138 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5139 }
5140}
5141
5142/**
5143 * xmlNsListDumpOutput:
5144 * @buf: the XML buffer output
5145 * @cur: the first namespace
5146 *
5147 * Dump a list of local Namespace definitions.
5148 * Should be called in the context of attributes dumps.
5149 */
5150static void
5151xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5152 while (cur != NULL) {
5153 xmlNsDumpOutput(buf, cur);
5154 cur = cur->next;
5155 }
5156}
5157
5158/**
5159 * xmlDtdDumpOutput:
5160 * @buf: the XML buffer output
5161 * @doc: the document
5162 * @encoding: an optional encoding string
5163 *
5164 * Dump the XML document DTD, if any.
5165 */
5166static void
5167xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5168 if (dtd == NULL) {
5169#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005170 xmlGenericError(xmlGenericErrorContext,
5171 "xmlDtdDump : no internal subset\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005172#endif
5173 return;
5174 }
5175 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5176 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5177 if (dtd->ExternalID != NULL) {
5178 xmlOutputBufferWriteString(buf, " PUBLIC ");
5179 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5180 xmlOutputBufferWriteString(buf, " ");
5181 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5182 } else if (dtd->SystemID != NULL) {
5183 xmlOutputBufferWriteString(buf, " SYSTEM ");
5184 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5185 }
5186 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5187 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5188 xmlOutputBufferWriteString(buf, ">");
5189 return;
5190 }
5191 xmlOutputBufferWriteString(buf, " [\n");
5192 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
Daniel Veillardbe803962000-06-28 23:40:59 +00005193 xmlOutputBufferWriteString(buf, "]>");
5194}
5195
5196/**
5197 * xmlAttrDumpOutput:
5198 * @buf: the XML buffer output
5199 * @doc: the document
5200 * @cur: the attribute pointer
5201 * @encoding: an optional encoding string
5202 *
5203 * Dump an XML attribute
5204 */
5205static void
5206xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
5207 const char *encoding) {
5208 xmlChar *value;
5209
5210 if (cur == NULL) {
5211#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005212 xmlGenericError(xmlGenericErrorContext,
5213 "xmlAttrDump : property == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005214#endif
5215 return;
5216 }
5217 xmlOutputBufferWriteString(buf, " ");
5218 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5219 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5220 xmlOutputBufferWriteString(buf, ":");
5221 }
5222 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5223 value = xmlNodeListGetString(doc, cur->children, 0);
5224 if (value) {
5225 xmlOutputBufferWriteString(buf, "=");
5226 xmlBufferWriteQuotedString(buf->buffer, value);
5227 xmlFree(value);
5228 } else {
5229 xmlOutputBufferWriteString(buf, "=\"\"");
5230 }
5231}
5232
5233/**
5234 * xmlAttrListDumpOutput:
5235 * @buf: the XML buffer output
5236 * @doc: the document
5237 * @cur: the first attribute pointer
5238 * @encoding: an optional encoding string
5239 *
5240 * Dump a list of XML attributes
5241 */
5242static void
5243xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5244 xmlAttrPtr cur, const char *encoding) {
5245 if (cur == NULL) {
5246#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005247 xmlGenericError(xmlGenericErrorContext,
5248 "xmlAttrListDump : property == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005249#endif
5250 return;
5251 }
5252 while (cur != NULL) {
5253 xmlAttrDumpOutput(buf, doc, cur, encoding);
5254 cur = cur->next;
5255 }
5256}
5257
5258
5259
5260/**
5261 * xmlNodeListDumpOutput:
5262 * @buf: the XML buffer output
5263 * @doc: the document
5264 * @cur: the first node
5265 * @level: the imbrication level for indenting
5266 * @format: is formatting allowed
5267 * @encoding: an optional encoding string
5268 *
5269 * Dump an XML node list, recursive behaviour,children are printed too.
5270 */
5271static void
5272xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5273 xmlNodePtr cur, int level, int format, const char *encoding) {
5274 int i;
5275
5276 if (cur == NULL) {
5277#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005278 xmlGenericError(xmlGenericErrorContext,
5279 "xmlNodeListDump : node == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005280#endif
5281 return;
5282 }
5283 while (cur != NULL) {
5284 if ((format) && (xmlIndentTreeOutput) &&
5285 (cur->type == XML_ELEMENT_NODE))
5286 for (i = 0;i < level;i++)
5287 xmlOutputBufferWriteString(buf, " ");
5288 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5289 if (format) {
5290 xmlOutputBufferWriteString(buf, "\n");
5291 }
5292 cur = cur->next;
5293 }
5294}
5295
5296/**
5297 * xmlNodeDumpOutput:
5298 * @buf: the XML buffer output
5299 * @doc: the document
5300 * @cur: the current node
5301 * @level: the imbrication level for indenting
5302 * @format: is formatting allowed
5303 * @encoding: an optional encoding string
5304 *
5305 * Dump an XML node, recursive behaviour,children are printed too.
5306 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005307void
Daniel Veillardbe803962000-06-28 23:40:59 +00005308xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5309 int level, int format, const char *encoding) {
5310 int i;
5311 xmlNodePtr tmp;
5312
5313 if (cur == NULL) {
5314#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005315 xmlGenericError(xmlGenericErrorContext,
5316 "xmlNodeDump : node == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005317#endif
5318 return;
5319 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00005320 if (cur->type == XML_XINCLUDE_START)
5321 return;
5322 if (cur->type == XML_XINCLUDE_END)
5323 return;
Daniel Veillardbe803962000-06-28 23:40:59 +00005324 if (cur->type == XML_DTD_NODE) {
5325 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5326 return;
5327 }
5328 if (cur->type == XML_ELEMENT_DECL) {
5329 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5330 return;
5331 }
5332 if (cur->type == XML_ATTRIBUTE_DECL) {
5333 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5334 return;
5335 }
5336 if (cur->type == XML_ENTITY_DECL) {
5337 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5338 return;
5339 }
5340 if (cur->type == XML_TEXT_NODE) {
5341 if (cur->content != NULL) {
5342 xmlChar *buffer;
5343
5344#ifndef XML_USE_BUFFER_CONTENT
5345 if (encoding == NULL)
5346 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5347 else
5348 buffer = xmlEncodeSpecialChars(doc, cur->content);
5349#else
5350 if (encoding == NULL)
5351 buffer = xmlEncodeEntitiesReentrant(doc,
5352 xmlBufferContent(cur->content));
5353 else
5354 buffer = xmlEncodeSpecialChars(doc,
5355 xmlBufferContent(cur->content));
5356#endif
5357 if (buffer != NULL) {
5358 xmlOutputBufferWriteString(buf, (const char *)buffer);
5359 xmlFree(buffer);
5360 }
5361 }
5362 return;
5363 }
5364 if (cur->type == XML_PI_NODE) {
5365 if (cur->content != NULL) {
5366 xmlOutputBufferWriteString(buf, "<?");
5367 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5368 if (cur->content != NULL) {
5369 xmlOutputBufferWriteString(buf, " ");
5370#ifndef XML_USE_BUFFER_CONTENT
5371 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5372#else
5373 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5374#endif
5375 }
5376 xmlOutputBufferWriteString(buf, "?>");
5377 } else {
5378 xmlOutputBufferWriteString(buf, "<?");
5379 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5380 xmlOutputBufferWriteString(buf, "?>");
5381 }
5382 return;
5383 }
5384 if (cur->type == XML_COMMENT_NODE) {
5385 if (cur->content != NULL) {
5386 xmlOutputBufferWriteString(buf, "<!--");
5387#ifndef XML_USE_BUFFER_CONTENT
5388 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5389#else
5390 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5391#endif
5392 xmlOutputBufferWriteString(buf, "-->");
5393 }
5394 return;
5395 }
5396 if (cur->type == XML_ENTITY_REF_NODE) {
5397 xmlOutputBufferWriteString(buf, "&");
5398 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5399 xmlOutputBufferWriteString(buf, ";");
5400 return;
5401 }
5402 if (cur->type == XML_CDATA_SECTION_NODE) {
5403 xmlOutputBufferWriteString(buf, "<![CDATA[");
5404 if (cur->content != NULL)
5405#ifndef XML_USE_BUFFER_CONTENT
5406 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5407#else
5408 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5409#endif
5410 xmlOutputBufferWriteString(buf, "]]>");
5411 return;
5412 }
5413
5414 if (format == 1) {
5415 tmp = cur->children;
5416 while (tmp != NULL) {
5417 if ((tmp->type == XML_TEXT_NODE) ||
5418 (tmp->type == XML_ENTITY_REF_NODE)) {
5419 format = 0;
5420 break;
5421 }
5422 tmp = tmp->next;
5423 }
5424 }
5425 xmlOutputBufferWriteString(buf, "<");
5426 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5427 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5428 xmlOutputBufferWriteString(buf, ":");
5429 }
5430
5431 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5432 if (cur->nsDef)
5433 xmlNsListDumpOutput(buf, cur->nsDef);
5434 if (cur->properties != NULL)
5435 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
5436
5437 if ((cur->content == NULL) && (cur->children == NULL) &&
5438 (!xmlSaveNoEmptyTags)) {
5439 xmlOutputBufferWriteString(buf, "/>");
5440 return;
5441 }
5442 xmlOutputBufferWriteString(buf, ">");
5443 if (cur->content != NULL) {
5444 xmlChar *buffer;
5445
5446#ifndef XML_USE_BUFFER_CONTENT
5447 if (encoding == NULL)
5448 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5449 else
5450 buffer = xmlEncodeSpecialChars(doc, cur->content);
5451#else
5452 if (encoding == NULL)
5453 buffer = xmlEncodeEntitiesReentrant(doc,
5454 xmlBufferContent(cur->content));
5455 else
5456 buffer = xmlEncodeSpecialChars(doc,
5457 xmlBufferContent(cur->content));
5458#endif
5459 if (buffer != NULL) {
5460 xmlOutputBufferWriteString(buf, (const char *)buffer);
5461 xmlFree(buffer);
5462 }
5463 }
5464 if (cur->children != NULL) {
5465 if (format) xmlOutputBufferWriteString(buf, "\n");
5466 xmlNodeListDumpOutput(buf, doc, cur->children,
5467 (level >= 0?level+1:-1), format, encoding);
5468 if ((xmlIndentTreeOutput) && (format))
5469 for (i = 0;i < level;i++)
5470 xmlOutputBufferWriteString(buf, " ");
5471 }
5472 xmlOutputBufferWriteString(buf, "</");
5473 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5474 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5475 xmlOutputBufferWriteString(buf, ":");
5476 }
5477
5478 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5479 xmlOutputBufferWriteString(buf, ">");
5480}
5481
5482/**
5483 * xmlDocContentDumpOutput:
5484 * @buf: the XML buffer output
5485 * @cur: the document
5486 * @encoding: an optional encoding string
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005487 * @format: should formatting spaces been added
Daniel Veillardbe803962000-06-28 23:40:59 +00005488 *
5489 * Dump an XML document.
5490 */
5491static void
5492xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005493 const char *encoding, int format) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005494 xmlOutputBufferWriteString(buf, "<?xml version=");
5495 if (cur->version != NULL)
5496 xmlBufferWriteQuotedString(buf->buffer, cur->version);
5497 else
5498 xmlOutputBufferWriteString(buf, "\"1.0\"");
5499 if (encoding == NULL) {
5500 if (cur->encoding != NULL)
5501 encoding = (const char *) cur->encoding;
5502 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005503 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
Daniel Veillardbe803962000-06-28 23:40:59 +00005504 }
5505 if (encoding != NULL) {
5506 xmlOutputBufferWriteString(buf, " encoding=");
5507 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
5508 }
5509 switch (cur->standalone) {
5510 case 0:
5511 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
5512 break;
5513 case 1:
5514 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
5515 break;
5516 }
5517 xmlOutputBufferWriteString(buf, "?>\n");
5518 if (cur->children != NULL) {
5519 xmlNodePtr child = cur->children;
5520
Daniel Veillardbe803962000-06-28 23:40:59 +00005521 while (child != NULL) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005522 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
Daniel Veillardbe803962000-06-28 23:40:59 +00005523 xmlOutputBufferWriteString(buf, "\n");
5524 child = child->next;
5525 }
5526 }
5527}
5528
5529/************************************************************************
5530 * *
5531 * Saving functions front-ends *
5532 * *
5533 ************************************************************************/
5534
Daniel Veillard97b58771998-10-20 06:14:16 +00005535/**
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005536 * xmlDocDumpMemoryEnc:
5537 * @out_doc: Document to generate XML text from
5538 * @doc_txt_ptr: Memory pointer for allocated XML text
5539 * @doc_txt_len: Length of the generated XML text
5540 * @txt_encoding: Character encoding to use when generating XML text
5541 * @format: should formatting spaces been added
5542 *
5543 * Dump the current DOM tree into memory using the character encoding specified
5544 * by the caller. Note it is up to the caller of this function to free the
5545 * allocated memory.
5546 */
5547
5548void
5549xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5550 int * doc_txt_len, const char * txt_encoding, int format) {
5551 int dummy = 0;
5552
5553 xmlCharEncoding doc_charset;
5554 xmlOutputBufferPtr out_buff = NULL;
5555 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
5556
5557 if (doc_txt_len == NULL) {
5558 doc_txt_len = &dummy; /* Continue, caller just won't get length */
5559 }
5560
5561 if (doc_txt_ptr == NULL) {
5562 *doc_txt_len = 0;
5563 xmlGenericError(xmlGenericErrorContext,
5564 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
5565 return;
5566 }
5567
5568 *doc_txt_ptr = NULL;
5569 *doc_txt_len = 0;
5570
5571 if (out_doc == NULL) {
5572 /* No document, no output */
5573 xmlGenericError(xmlGenericErrorContext,
5574 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
5575 return;
5576 }
5577
5578 /*
5579 * Validate the encoding value, if provided.
5580 * This logic is copied from xmlSaveFileEnc.
5581 */
5582
5583 if (txt_encoding == NULL)
5584 txt_encoding = (const char *) out_doc->encoding;
5585 if (txt_encoding != NULL) {
5586 doc_charset = xmlParseCharEncoding(txt_encoding);
5587
5588 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
5589 xmlGenericError(xmlGenericErrorContext,
5590 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
5591 return;
5592
5593 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
5594 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
5595 if ( conv_hdlr == NULL ) {
5596 xmlGenericError(xmlGenericErrorContext,
5597 "%s: %s %s '%s'\n",
5598 "xmlDocDumpFormatMemoryEnc",
5599 "Failed to identify encoding handler for",
5600 "character set",
5601 txt_encoding);
5602 return;
5603 }
5604 }
5605 }
5606
5607 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
5608 xmlGenericError(xmlGenericErrorContext,
5609 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
5610 return;
5611 }
5612
5613 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, 1);
5614 xmlOutputBufferFlush(out_buff);
5615 if (out_buff->conv != NULL) {
5616 *doc_txt_len = out_buff->conv->use;
5617 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
5618 } else {
5619 *doc_txt_len = out_buff->buffer->use;
5620 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
5621 }
5622 (void)xmlOutputBufferClose(out_buff);
5623
5624 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
5625 *doc_txt_len = 0;
5626 xmlGenericError(xmlGenericErrorContext,
5627 "xmlDocDumpFormatMemoryEnc: %s\n",
5628 "Failed to allocate memory for document text representation.");
5629 }
5630
5631 return;
5632}
5633
5634/**
Daniel Veillard97b58771998-10-20 06:14:16 +00005635 * xmlDocDumpMemory:
5636 * @cur: the document
5637 * @mem: OUT: the memory pointer
5638 * @size: OUT: the memory lenght
5639 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005640 * Dump an XML document in memory and return the xmlChar * and it's size.
Daniel Veillard97b58771998-10-20 06:14:16 +00005641 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005642 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005643void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005644xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005645 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
5646}
Daniel Veillard5099ae81999-04-21 20:12:07 +00005647
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005648/**
5649 * xmlDocDumpFormatMemory:
5650 * @cur: the document
5651 * @mem: OUT: the memory pointer
5652 * @size: OUT: the memory lenght
5653 * @format: should formatting spaces been added
5654 *
5655 *
5656 * Dump an XML document in memory and return the xmlChar * and it's size.
5657 * It's up to the caller to free the memory.
5658 */
5659void
5660xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
5661 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005662}
5663
Daniel Veillard97b58771998-10-20 06:14:16 +00005664/**
Daniel Veillard58770e72000-11-25 00:48:47 +00005665 * xmlDocDumpMemoryEnc:
5666 * @out_doc: Document to generate XML text from
5667 * @doc_txt_ptr: Memory pointer for allocated XML text
5668 * @doc_txt_len: Length of the generated XML text
5669 * @txt_encoding: Character encoding to use when generating XML text
5670 *
5671 * Dump the current DOM tree into memory using the character encoding specified
5672 * by the caller. Note it is up to the caller of this function to free the
5673 * allocated memory.
5674 */
5675
5676void
5677xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5678 int * doc_txt_len, const char * txt_encoding) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005679 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
5680 txt_encoding, 1);
Daniel Veillard58770e72000-11-25 00:48:47 +00005681}
5682
5683/**
Daniel Veillard97b58771998-10-20 06:14:16 +00005684 * xmlGetDocCompressMode:
5685 * @doc: the document
5686 *
5687 * get the compression ratio for a document, ZLIB based
Daniel Veillard1e346af1999-02-22 10:33:01 +00005688 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00005689 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005690int
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005691xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005692 if (doc == NULL) return(-1);
5693 return(doc->compression);
5694}
5695
Daniel Veillard97b58771998-10-20 06:14:16 +00005696/**
5697 * xmlSetDocCompressMode:
5698 * @doc: the document
5699 * @mode: the compression ratio
5700 *
5701 * set the compression ratio for a document, ZLIB based
5702 * Correct values: 0 (uncompressed) to 9 (max compression)
5703 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005704void
5705xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005706 if (doc == NULL) return;
5707 if (mode < 0) doc->compression = 0;
5708 else if (mode > 9) doc->compression = 9;
5709 else doc->compression = mode;
5710}
5711
Daniel Veillard97b58771998-10-20 06:14:16 +00005712/**
5713 * xmlGetCompressMode:
5714 *
5715 * get the default compression mode used, ZLIB based.
Daniel Veillard1e346af1999-02-22 10:33:01 +00005716 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00005717 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005718int
5719 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005720 return(xmlCompressMode);
5721}
Daniel Veillard97b58771998-10-20 06:14:16 +00005722
5723/**
5724 * xmlSetCompressMode:
5725 * @mode: the compression ratio
5726 *
5727 * set the default compression mode used, ZLIB based
5728 * Correct values: 0 (uncompressed) to 9 (max compression)
5729 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005730void
5731xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005732 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00005733 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005734 else xmlCompressMode = mode;
5735}
5736
Daniel Veillardbe803962000-06-28 23:40:59 +00005737/**
5738 * xmlDocDump:
5739 * @f: the FILE*
5740 * @cur: the document
5741 *
5742 * Dump an XML document to an open FILE.
5743 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005744 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005745 */
5746int
5747xmlDocDump(FILE *f, xmlDocPtr cur) {
5748 xmlOutputBufferPtr buf;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005749 const char * encoding;
5750 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillardbe803962000-06-28 23:40:59 +00005751 int ret;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005752
Daniel Veillardbe803962000-06-28 23:40:59 +00005753 if (cur == NULL) {
5754#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005755 xmlGenericError(xmlGenericErrorContext,
5756 "xmlDocDump : document == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005757#endif
5758 return(-1);
5759 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005760 encoding = (const char *) cur->encoding;
5761
5762 if (encoding != NULL) {
5763 xmlCharEncoding enc;
5764
5765 enc = xmlParseCharEncoding(encoding);
5766
5767 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005768 xmlGenericError(xmlGenericErrorContext,
5769 "xmlDocDump: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005770 return(-1);
5771 }
5772 if (enc != XML_CHAR_ENCODING_UTF8) {
5773 handler = xmlFindCharEncodingHandler(encoding);
5774 if (handler == NULL) {
5775 xmlFree((char *) cur->encoding);
5776 cur->encoding = NULL;
5777 }
5778 }
5779 }
5780 buf = xmlOutputBufferCreateFile(f, handler);
Daniel Veillardbe803962000-06-28 23:40:59 +00005781 if (buf == NULL) return(-1);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005782 xmlDocContentDumpOutput(buf, cur, NULL, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005783
5784 ret = xmlOutputBufferClose(buf);
5785 return(ret);
5786}
5787
5788/**
Daniel Veillardbe803962000-06-28 23:40:59 +00005789 * xmlSaveFileTo:
5790 * @buf: an output I/O buffer
5791 * @cur: the document
5792 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
5793 *
5794 * Dump an XML document to an I/O buffer.
5795 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005796 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005797 */
5798int
5799xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
5800 int ret;
5801
5802 if (buf == NULL) return(0);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005803 xmlDocContentDumpOutput(buf, cur, encoding, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005804 ret = xmlOutputBufferClose(buf);
5805 return(ret);
5806}
5807
5808/**
5809 * xmlSaveFileEnc:
5810 * @filename: the filename (or URL)
5811 * @cur: the document
5812 * @encoding: the name of an encoding (or NULL)
5813 *
5814 * Dump an XML document, converting it to the given encoding
5815 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005816 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005817 */
5818int
5819xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
5820 xmlOutputBufferPtr buf;
5821 xmlCharEncodingHandlerPtr handler = NULL;
5822 int ret;
5823
5824 if (encoding != NULL) {
5825 xmlCharEncoding enc;
5826
5827 enc = xmlParseCharEncoding(encoding);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005828 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005829 xmlGenericError(xmlGenericErrorContext,
5830 "xmlSaveFileEnc: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005831 return(-1);
5832 }
5833 if (enc != XML_CHAR_ENCODING_UTF8) {
5834 handler = xmlFindCharEncodingHandler(encoding);
5835 if (handler == NULL) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005836 return(-1);
5837 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005838 }
5839 }
5840
5841 /*
5842 * save the content to a temp buffer.
5843 */
5844 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
5845 if (buf == NULL) return(0);
5846
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005847 xmlDocContentDumpOutput(buf, cur, encoding, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005848
5849 ret = xmlOutputBufferClose(buf);
5850 return(ret);
5851}
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005852
5853/**
5854 * xmlSaveFile:
5855 * @filename: the filename (or URL)
5856 * @cur: the document
5857 *
5858 * Dump an XML document to a file. Will use compression if
5859 * compiled in and enabled. If @filename is "-" the stdout file is
5860 * used.
5861 * returns: the number of byte written or -1 in case of failure.
5862 */
5863int
5864xmlSaveFile(const char *filename, xmlDocPtr cur) {
5865 xmlOutputBufferPtr buf;
5866 const char *encoding;
5867 xmlCharEncodingHandlerPtr handler = NULL;
5868 int ret;
5869
5870 if (cur == NULL)
5871 return(-1);
5872 encoding = (const char *) cur->encoding;
5873
5874 /*
5875 * save the content to a temp buffer.
5876 */
5877#ifdef HAVE_ZLIB_H
5878 if (cur->compression < 0) cur->compression = xmlCompressMode;
Daniel Veillardbe803962000-06-28 23:40:59 +00005879#endif
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005880 if (encoding != NULL) {
5881 xmlCharEncoding enc;
5882
5883 enc = xmlParseCharEncoding(encoding);
5884
5885 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005886 xmlGenericError(xmlGenericErrorContext,
5887 "xmlSaveFile: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005888 return(-1);
5889 }
5890 if (enc != XML_CHAR_ENCODING_UTF8) {
5891 handler = xmlFindCharEncodingHandler(encoding);
5892 if (handler == NULL) {
5893 xmlFree((char *) cur->encoding);
5894 cur->encoding = NULL;
5895 }
5896 }
5897 }
5898
5899 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
5900 if (buf == NULL) return(0);
5901
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005902 xmlDocContentDumpOutput(buf, cur, NULL, 1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005903
5904 ret = xmlOutputBufferClose(buf);
5905 return(ret);
5906}
5907