blob: 5fd26b5b67c21fbe14c75d9cb8b9a448c6885e7b [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 Veillard260a68f1998-08-13 03:39:55 +00007 */
8
Daniel Veillard7f7d1111999-09-22 09:46:25 +00009#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000010#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000011#else
Daniel Veillard151b1b01998-09-23 00:49:46 +000012#include "config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000013#endif
14
Daniel Veillard260a68f1998-08-13 03:39:55 +000015#include <stdio.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000016#include <string.h> /* for memset() only ! */
17
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
Daniel Veillard151b1b01998-09-23 00:49:46 +000024#ifdef HAVE_ZLIB_H
25#include <zlib.h>
26#endif
27
Daniel Veillard361d8452000-04-03 19:48:13 +000028#include <libxml/xmlmemory.h>
29#include <libxml/tree.h>
30#include <libxml/parser.h>
31#include <libxml/entities.h>
32#include <libxml/valid.h>
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000033#include <libxml/xmlerror.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000034
Daniel Veillarddd6b3671999-09-23 22:19:22 +000035static xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
Daniel Veillardcf461992000-03-14 18:30:20 +000036static xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
Daniel Veillard260a68f1998-08-13 03:39:55 +000037int oldXMLWDcompatibility = 0;
Daniel Veillardcf461992000-03-14 18:30:20 +000038int xmlIndentTreeOutput = 0;
Daniel Veillardf5c2c871999-12-01 09:51:45 +000039xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT;
Daniel Veillard260a68f1998-08-13 03:39:55 +000040
Daniel Veillard15a8df41998-09-24 19:15:06 +000041static int xmlCompressMode = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +000042static int xmlCheckDTD = 1;
Daniel Veillarde41f2b72000-01-30 20:00:07 +000043int xmlSaveNoEmptyTags = 0;
Daniel Veillard3e6d2372000-03-04 11:39:43 +000044
45#define IS_BLANK(c) \
46 (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
Daniel Veillard15a8df41998-09-24 19:15:06 +000047
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000048#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
Daniel Veillardcf461992000-03-14 18:30:20 +000049 xmlNodePtr ulccur = (n)->children; \
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000050 if (ulccur == NULL) { \
51 (n)->last = NULL; \
52 } else { \
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000053 while (ulccur->next != NULL) { \
54 ulccur->parent = (n); \
55 ulccur = ulccur->next; \
56 } \
57 ulccur->parent = (n); \
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000058 (n)->last = ulccur; \
Daniel Veillard1e346af1999-02-22 10:33:01 +000059}}
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000060
Daniel Veillardad8f99d2000-01-15 14:20:03 +000061/* #define DEBUG_BUFFER */
62/* #define DEBUG_TREE */
63
Daniel Veillard260a68f1998-08-13 03:39:55 +000064/************************************************************************
65 * *
66 * Allocation and deallocation of basic structures *
67 * *
68 ************************************************************************/
69
Daniel Veillard97b58771998-10-20 06:14:16 +000070/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +000071 * xmlSetBufferAllocationScheme:
72 * @scheme: allocation method to use
73 *
74 * Set the buffer allocation method. Types are
75 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
76 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
77 * improves performance
78 */
79void
80xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
81 xmlBufferAllocScheme = scheme;
82}
83
84/**
85 * xmlGetBufferAllocationScheme:
86 *
87 * Types are
88 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
89 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
90 * improves performance
91 *
92 * Returns the current allocation scheme
93 */
94xmlBufferAllocationScheme
95xmlGetBufferAllocationScheme() {
96 return xmlBufferAllocScheme;
97}
98
99/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000100 * xmlNewNs:
101 * @node: the element carrying the namespace
102 * @href: the URI associated
103 * @prefix: the prefix for the namespace
104 *
Daniel Veillard686d6b62000-01-03 11:08:02 +0000105 * Creation of a new Namespace. This function will refuse to create
106 * a namespace with a similar prefix than an existing one present on this
107 * node.
Daniel Veillarde0854c32000-08-27 21:12:29 +0000108 * We use href==NULL in the case of an element creation where the namespace
109 * was not defined.
Daniel Veillard686d6b62000-01-03 11:08:02 +0000110 * Returns returns a new namespace pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000111 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000112xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000113xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000114 xmlNsPtr cur;
115
Daniel Veillard260a68f1998-08-13 03:39:55 +0000116 /*
Daniel Veillardcf461992000-03-14 18:30:20 +0000117 * Allocate a new Namespace and fill the fields.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000118 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000119 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000120 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000121 xmlGenericError(xmlGenericErrorContext,
122 "xmlNewNs : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000123 return(NULL);
124 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000125 memset(cur, 0, sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000126 cur->type = XML_LOCAL_NAMESPACE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000127
Daniel Veillard260a68f1998-08-13 03:39:55 +0000128 if (href != NULL)
129 cur->href = xmlStrdup(href);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000130 if (prefix != NULL)
131 cur->prefix = xmlStrdup(prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000132
133 /*
134 * Add it at the end to preserve parsing order ...
Daniel Veillard686d6b62000-01-03 11:08:02 +0000135 * and checks for existing use of the prefix
Daniel Veillard260a68f1998-08-13 03:39:55 +0000136 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000137 if (node != NULL) {
138 if (node->nsDef == NULL) {
139 node->nsDef = cur;
140 } else {
141 xmlNsPtr prev = node->nsDef;
142
Daniel Veillard0142b842000-01-14 14:45:24 +0000143 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000144 (xmlStrEqual(prev->prefix, cur->prefix))) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000145 xmlFreeNs(cur);
146 return(NULL);
147 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000148 while (prev->next != NULL) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000149 prev = prev->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +0000150 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000151 (xmlStrEqual(prev->prefix, cur->prefix))) {
Daniel Veillard686d6b62000-01-03 11:08:02 +0000152 xmlFreeNs(cur);
153 return(NULL);
154 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000155 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000156 prev->next = cur;
157 }
158 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000159 return(cur);
160}
161
Daniel Veillard97b58771998-10-20 06:14:16 +0000162/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000163 * xmlSetNs:
164 * @node: a node in the document
165 * @ns: a namespace pointer
166 *
167 * Associate a namespace to a node, a posteriori.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000168 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000169void
170xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000171 if (node == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000172#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000173 xmlGenericError(xmlGenericErrorContext,
174 "xmlSetNs: node == NULL\n");
Daniel Veillardcf461992000-03-14 18:30:20 +0000175#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000176 return;
177 }
178 node->ns = ns;
179}
180
Daniel Veillard97b58771998-10-20 06:14:16 +0000181/**
182 * xmlFreeNs:
183 * @cur: the namespace pointer
184 *
185 * Free up the structures associated to a namespace
Daniel Veillard260a68f1998-08-13 03:39:55 +0000186 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000187void
188xmlFreeNs(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000189 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000190#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000191 xmlGenericError(xmlGenericErrorContext,
192 "xmlFreeNs : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000193#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000194 return;
195 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000196 if (cur->href != NULL) xmlFree((char *) cur->href);
197 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000198 memset(cur, -1, sizeof(xmlNs));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000199 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000200}
201
Daniel Veillard97b58771998-10-20 06:14:16 +0000202/**
203 * xmlFreeNsList:
204 * @cur: the first namespace pointer
205 *
206 * Free up all the structures associated to the chained namespaces.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000207 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000208void
209xmlFreeNsList(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000210 xmlNsPtr next;
211 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000212#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000213 xmlGenericError(xmlGenericErrorContext,
214 "xmlFreeNsList : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000215#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000216 return;
217 }
218 while (cur != NULL) {
219 next = cur->next;
220 xmlFreeNs(cur);
221 cur = next;
222 }
223}
224
Daniel Veillard97b58771998-10-20 06:14:16 +0000225/**
226 * xmlNewDtd:
227 * @doc: the document pointer
228 * @name: the DTD name
229 * @ExternalID: the external ID
230 * @SystemID: the system ID
231 *
Daniel Veillardcf461992000-03-14 18:30:20 +0000232 * Creation of a new DTD for the external subset. To create an
233 * internal subset, use xmlCreateIntSubset().
234 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000235 * Returns a pointer to the new DTD structure
Daniel Veillard260a68f1998-08-13 03:39:55 +0000236 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000237xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000238xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
239 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000240 xmlDtdPtr cur;
241
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000242 if ((doc != NULL) && (doc->extSubset != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000243#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000244 xmlGenericError(xmlGenericErrorContext,
245 "xmlNewDtd(%s): document %s already have a DTD %s\n",
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000246 /* !!! */ (char *) name, doc->name,
247 /* !!! */ (char *)doc->extSubset->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000248#endif
249 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000250 }
251
252 /*
253 * Allocate a new DTD and fill the fields.
254 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000255 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000256 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000257 xmlGenericError(xmlGenericErrorContext,
258 "xmlNewDtd : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000259 return(NULL);
260 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000261 memset(cur, 0 , sizeof(xmlDtd));
262 cur->type = XML_DTD_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000263
264 if (name != NULL)
265 cur->name = xmlStrdup(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000266 if (ExternalID != NULL)
267 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000268 if (SystemID != NULL)
269 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000270 if (doc != NULL)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000271 doc->extSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000272 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000273
274 return(cur);
275}
276
277/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000278 * xmlGetIntSubset:
279 * @doc: the document pointer
280 *
281 * Get the internal subset of a document
282 * Returns a pointer to the DTD structure or NULL if not found
283 */
284
285xmlDtdPtr
286xmlGetIntSubset(xmlDocPtr doc) {
287 xmlNodePtr cur;
288
289 if (doc == NULL)
290 return(NULL);
291 cur = doc->children;
292 while (cur != NULL) {
293 if (cur->type == XML_DTD_NODE)
294 return((xmlDtdPtr) cur);
295 cur = cur->next;
296 }
297 return((xmlDtdPtr) doc->intSubset);
298}
299
300/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000301 * xmlCreateIntSubset:
302 * @doc: the document pointer
303 * @name: the DTD name
304 * @ExternalID: the external ID
305 * @SystemID: the system ID
306 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000307 * Create the internal subset of a document
308 * Returns a pointer to the new DTD structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000309 */
310xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000311xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
312 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000313 xmlDtdPtr cur;
314
Daniel Veillardcf461992000-03-14 18:30:20 +0000315 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000316#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000317 xmlGenericError(xmlGenericErrorContext,
318
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000319 "xmlCreateIntSubset(): document %s already have an internal subset\n",
320 doc->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000321#endif
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000322 return(NULL);
323 }
324
325 /*
326 * Allocate a new DTD and fill the fields.
327 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000328 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000329 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000330 xmlGenericError(xmlGenericErrorContext,
331 "xmlNewDtd : malloc failed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000332 return(NULL);
333 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000334 memset(cur, 0, sizeof(xmlDtd));
335 cur->type = XML_DTD_NODE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000336
337 if (name != NULL)
338 cur->name = xmlStrdup(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000339 if (ExternalID != NULL)
340 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000341 if (SystemID != NULL)
342 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000343 if (doc != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000344 doc->intSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000345 cur->parent = doc;
346 cur->doc = doc;
347 if (doc->children == NULL) {
348 doc->children = (xmlNodePtr) cur;
349 doc->last = (xmlNodePtr) cur;
350 } else {
351 xmlNodePtr prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000352
Daniel Veillardb8f25c92000-08-19 19:52:36 +0000353 if (doc->type == XML_HTML_DOCUMENT_NODE) {
354 prev = doc->children;
355 prev->prev = (xmlNodePtr) cur;
356 cur->next = prev;
357 doc->children = (xmlNodePtr) cur;
358 } else {
359 prev = doc->last;
360 prev->next = (xmlNodePtr) cur;
361 cur->prev = prev;
362 doc->last = (xmlNodePtr) cur;
363 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000364 }
365 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000366 return(cur);
367}
368
Daniel Veillard97b58771998-10-20 06:14:16 +0000369/**
370 * xmlFreeDtd:
371 * @cur: the DTD structure to free up
372 *
373 * Free a DTD structure.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000374 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000375void
376xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000377 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000378#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000379 xmlGenericError(xmlGenericErrorContext,
380 "xmlFreeDtd : DTD == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000381#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000382 return;
383 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000384 if (cur->children != NULL) {
385 xmlNodePtr next, c = cur->children;
386
387 /*
388 * Cleanup all the DTD comments they are not in the Dtd
389 * indexes.
390 */
391 while (c != NULL) {
392 next = c->next;
393 if (c->type == XML_COMMENT_NODE) {
394 xmlUnlinkNode(c);
395 xmlFreeNode(c);
396 }
397 c = next;
398 }
399 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000400 if (cur->name != NULL) xmlFree((char *) cur->name);
401 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
402 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000403 /* TODO !!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000404 if (cur->notations != NULL)
405 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
Daniel Veillardcf461992000-03-14 18:30:20 +0000406
Daniel Veillard260a68f1998-08-13 03:39:55 +0000407 if (cur->elements != NULL)
Daniel Veillard3b9def11999-01-31 22:15:06 +0000408 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000409 if (cur->attributes != NULL)
410 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000411 if (cur->entities != NULL)
412 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
Daniel Veillard126f2792000-10-24 17:10:12 +0000413 if (cur->pentities != NULL)
414 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
Daniel Veillardcf461992000-03-14 18:30:20 +0000415
Daniel Veillard260a68f1998-08-13 03:39:55 +0000416 memset(cur, -1, sizeof(xmlDtd));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000417 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000418}
419
Daniel Veillard97b58771998-10-20 06:14:16 +0000420/**
421 * xmlNewDoc:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000422 * @version: xmlChar string giving the version of XML "1.0"
Daniel Veillard97b58771998-10-20 06:14:16 +0000423 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000424 * Returns a new document
Daniel Veillard260a68f1998-08-13 03:39:55 +0000425 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000426xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000427xmlNewDoc(const xmlChar *version) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000428 xmlDocPtr cur;
429
Daniel Veillard7eda8452000-10-14 23:38:43 +0000430 if (version == NULL)
431 version = (const xmlChar *) "1.0";
Daniel Veillard260a68f1998-08-13 03:39:55 +0000432
433 /*
434 * Allocate a new document and fill the fields.
435 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000436 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000437 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000438 xmlGenericError(xmlGenericErrorContext,
439 "xmlNewDoc : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000440 return(NULL);
441 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000442 memset(cur, 0, sizeof(xmlDoc));
Daniel Veillard33942841998-10-18 19:12:41 +0000443 cur->type = XML_DOCUMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000444
Daniel Veillard260a68f1998-08-13 03:39:55 +0000445 cur->version = xmlStrdup(version);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000446 cur->standalone = -1;
Daniel Veillard11a48ec1999-11-23 10:40:46 +0000447 cur->compression = -1; /* not initialized */
Daniel Veillardcf461992000-03-14 18:30:20 +0000448 cur->doc = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000449 return(cur);
450}
451
Daniel Veillard97b58771998-10-20 06:14:16 +0000452/**
453 * xmlFreeDoc:
454 * @cur: pointer to the document
455 * @:
456 *
457 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000458 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000459void
460xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000461 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000462#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000463 xmlGenericError(xmlGenericErrorContext,
464 "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000465#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000466 return;
467 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000468 if (cur->version != NULL) xmlFree((char *) cur->version);
469 if (cur->name != NULL) xmlFree((char *) cur->name);
470 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Daniel Veillardcf461992000-03-14 18:30:20 +0000471 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000472 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
473 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000474 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000475 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000476 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
Daniel Veillardcf461992000-03-14 18:30:20 +0000477 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000478 memset(cur, -1, sizeof(xmlDoc));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000479 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000480}
481
Daniel Veillard97b58771998-10-20 06:14:16 +0000482/**
Daniel Veillard16253641998-10-28 22:58:05 +0000483 * xmlStringLenGetNodeList:
484 * @doc: the document
485 * @value: the value of the text
Daniel Veillard1e346af1999-02-22 10:33:01 +0000486 * @len: the length of the string value
Daniel Veillard16253641998-10-28 22:58:05 +0000487 *
488 * Parse the value string and build the node list associated. Should
489 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000490 * Returns a pointer to the first child
Daniel Veillard16253641998-10-28 22:58:05 +0000491 */
492xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000493xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
Daniel Veillard16253641998-10-28 22:58:05 +0000494 xmlNodePtr ret = NULL, last = NULL;
495 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000496 xmlChar *val;
497 const xmlChar *cur = value;
498 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000499 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000500
501 if (value == NULL) return(NULL);
502
503 q = cur;
504 while ((*cur != 0) && (cur - value < len)) {
505 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000506 /*
507 * Save the current text.
508 */
Daniel Veillard16253641998-10-28 22:58:05 +0000509 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000510 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
511 xmlNodeAddContentLen(last, q, cur - q);
512 } else {
513 node = xmlNewDocTextLen(doc, q, cur - q);
514 if (node == NULL) return(ret);
515 if (last == NULL)
516 last = ret = node;
517 else {
518 last->next = node;
519 node->prev = last;
520 last = node;
521 }
Daniel Veillard16253641998-10-28 22:58:05 +0000522 }
523 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000524 /*
525 * Read the entity string
526 */
Daniel Veillard16253641998-10-28 22:58:05 +0000527 cur++;
528 q = cur;
529 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
530 if ((*cur == 0) || (cur - value >= len)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000531#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000532 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard011b63c1999-06-02 17:44:04 +0000533 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000534#endif
Daniel Veillard16253641998-10-28 22:58:05 +0000535 return(ret);
536 }
537 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000538 /*
539 * Predefined entities don't generate nodes
540 */
Daniel Veillard16253641998-10-28 22:58:05 +0000541 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000542 ent = xmlGetDocEntity(doc, val);
543 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000544 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000545 if (last == NULL) {
546 node = xmlNewDocText(doc, ent->content);
547 last = ret = node;
548 } else
549 xmlNodeAddContent(last, ent->content);
550
551 } else {
552 /*
553 * Create a new REFERENCE_REF node
554 */
555 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000556 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000557 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000558 return(ret);
559 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000560 if (last == NULL)
561 last = ret = node;
562 else {
563 last->next = node;
564 node->prev = last;
565 last = node;
566 }
Daniel Veillard16253641998-10-28 22:58:05 +0000567 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000568 xmlFree(val);
Daniel Veillard16253641998-10-28 22:58:05 +0000569 }
570 cur++;
571 q = cur;
572 } else
573 cur++;
574 }
575 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000576 /*
577 * Handle the last piece of text.
578 */
579 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
580 xmlNodeAddContentLen(last, q, cur - q);
581 } else {
582 node = xmlNewDocTextLen(doc, q, cur - q);
583 if (node == NULL) return(ret);
584 if (last == NULL)
585 last = ret = node;
586 else {
587 last->next = node;
588 node->prev = last;
589 last = node;
590 }
Daniel Veillard16253641998-10-28 22:58:05 +0000591 }
592 }
593 return(ret);
594}
595
596/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000597 * xmlStringGetNodeList:
598 * @doc: the document
599 * @value: the value of the attribute
600 *
601 * Parse the value string and build the node list associated. Should
602 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000603 * Returns a pointer to the first child
Daniel Veillardccb09631998-10-27 06:21:04 +0000604 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000605xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000606xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000607 xmlNodePtr ret = NULL, last = NULL;
608 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000609 xmlChar *val;
610 const xmlChar *cur = value;
611 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000612 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000613
614 if (value == NULL) return(NULL);
615
616 q = cur;
617 while (*cur != 0) {
618 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000619 /*
620 * Save the current text.
621 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000622 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000623 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
624 xmlNodeAddContentLen(last, q, cur - q);
625 } else {
626 node = xmlNewDocTextLen(doc, q, cur - q);
627 if (node == NULL) return(ret);
628 if (last == NULL)
629 last = ret = node;
630 else {
631 last->next = node;
632 node->prev = last;
633 last = node;
634 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000635 }
636 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000637 /*
638 * Read the entity string
639 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000640 cur++;
641 q = cur;
642 while ((*cur != 0) && (*cur != ';')) cur++;
643 if (*cur == 0) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000644#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000645 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardccb09631998-10-27 06:21:04 +0000646 "xmlStringGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000647#endif
Daniel Veillardccb09631998-10-27 06:21:04 +0000648 return(ret);
649 }
650 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000651 /*
652 * Predefined entities don't generate nodes
653 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000654 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000655 ent = xmlGetDocEntity(doc, val);
656 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000657 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000658 if (last == NULL) {
659 node = xmlNewDocText(doc, ent->content);
660 last = ret = node;
661 } else
662 xmlNodeAddContent(last, ent->content);
663
664 } else {
665 /*
666 * Create a new REFERENCE_REF node
667 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000668 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000669 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000670 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000671 return(ret);
672 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000673 if (last == NULL)
674 last = ret = node;
675 else {
676 last->next = node;
677 node->prev = last;
678 last = node;
679 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000680 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000681 xmlFree(val);
Daniel Veillardccb09631998-10-27 06:21:04 +0000682 }
683 cur++;
684 q = cur;
685 } else
686 cur++;
687 }
688 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000689 /*
690 * Handle the last piece of text.
691 */
692 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
693 xmlNodeAddContentLen(last, q, cur - q);
694 } else {
695 node = xmlNewDocTextLen(doc, q, cur - q);
696 if (node == NULL) return(ret);
697 if (last == NULL)
698 last = ret = node;
699 else {
700 last->next = node;
701 node->prev = last;
702 last = node;
703 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000704 }
705 }
706 return(ret);
707}
708
709/**
710 * xmlNodeListGetString:
711 * @doc: the document
712 * @list: a Node list
713 * @inLine: should we replace entity contents or show their external form
714 *
715 * Returns the string equivalent to the text contained in the Node list
716 * made of TEXTs and ENTITY_REFs
Daniel Veillard1e346af1999-02-22 10:33:01 +0000717 * Returns a pointer to the string copy, the calller must free it.
Daniel Veillardccb09631998-10-27 06:21:04 +0000718 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000719xmlChar *
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000720xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000721 xmlNodePtr node = list;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000722 xmlChar *ret = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000723 xmlEntityPtr ent;
724
725 if (list == NULL) return(NULL);
726
727 while (node != NULL) {
Daniel Veillard87b95392000-08-12 21:12:04 +0000728 if ((node->type == XML_TEXT_NODE) ||
729 (node->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard71b656e2000-01-05 14:46:17 +0000730 if (inLine) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000731#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000732 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000733#else
734 ret = xmlStrcat(ret, xmlBufferContent(node->content));
735#endif
736 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000737 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +0000738
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000739#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +0000740 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000741#else
742 buffer = xmlEncodeEntitiesReentrant(doc,
743 xmlBufferContent(node->content));
744#endif
Daniel Veillard14fff061999-06-22 21:49:07 +0000745 if (buffer != NULL) {
746 ret = xmlStrcat(ret, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000747 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +0000748 }
749 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000750 } else if (node->type == XML_ENTITY_REF_NODE) {
751 if (inLine) {
752 ent = xmlGetDocEntity(doc, node->name);
753 if (ent != NULL)
754 ret = xmlStrcat(ret, ent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000755 else {
756#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000757 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000758#else
759 ret = xmlStrcat(ret, xmlBufferContent(node->content));
760#endif
761 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000762 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000763 xmlChar buf[2];
Daniel Veillardccb09631998-10-27 06:21:04 +0000764 buf[0] = '&'; buf[1] = 0;
765 ret = xmlStrncat(ret, buf, 1);
766 ret = xmlStrcat(ret, node->name);
767 buf[0] = ';'; buf[1] = 0;
768 ret = xmlStrncat(ret, buf, 1);
769 }
770 }
771#if 0
772 else {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000773 xmlGenericError(xmlGenericErrorContext,
774 "xmlGetNodeListString : invalide node type %d\n",
Daniel Veillardccb09631998-10-27 06:21:04 +0000775 node->type);
776 }
777#endif
778 node = node->next;
779 }
780 return(ret);
781}
782
783/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000784 * xmlNodeListGetRawString:
785 * @doc: the document
786 * @list: a Node list
787 * @inLine: should we replace entity contents or show their external form
788 *
789 * Returns the string equivalent to the text contained in the Node list
790 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
791 * this function doesn't do any character encoding handling.
792 *
793 * Returns a pointer to the string copy, the calller must free it.
794 */
795xmlChar *
796xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
797 xmlNodePtr node = list;
798 xmlChar *ret = NULL;
799 xmlEntityPtr ent;
800
801 if (list == NULL) return(NULL);
802
803 while (node != NULL) {
804 if (node->type == XML_TEXT_NODE) {
805 if (inLine) {
806#ifndef XML_USE_BUFFER_CONTENT
807 ret = xmlStrcat(ret, node->content);
808#else
809 ret = xmlStrcat(ret, xmlBufferContent(node->content));
810#endif
811 } else {
812 xmlChar *buffer;
813
814#ifndef XML_USE_BUFFER_CONTENT
815 buffer = xmlEncodeSpecialChars(doc, node->content);
816#else
817 buffer = xmlEncodeSpecialChars(doc,
818 xmlBufferContent(node->content));
819#endif
820 if (buffer != NULL) {
821 ret = xmlStrcat(ret, buffer);
822 xmlFree(buffer);
823 }
824 }
825 } else if (node->type == XML_ENTITY_REF_NODE) {
826 if (inLine) {
827 ent = xmlGetDocEntity(doc, node->name);
828 if (ent != NULL)
829 ret = xmlStrcat(ret, ent->content);
830 else {
831#ifndef XML_USE_BUFFER_CONTENT
832 ret = xmlStrcat(ret, node->content);
833#else
834 ret = xmlStrcat(ret, xmlBufferContent(node->content));
835#endif
836 }
837 } else {
838 xmlChar buf[2];
839 buf[0] = '&'; buf[1] = 0;
840 ret = xmlStrncat(ret, buf, 1);
841 ret = xmlStrcat(ret, node->name);
842 buf[0] = ';'; buf[1] = 0;
843 ret = xmlStrncat(ret, buf, 1);
844 }
845 }
846#if 0
847 else {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000848 xmlGenericError(xmlGenericErrorContext,
849 "xmlGetNodeListString : invalide node type %d\n",
Daniel Veillardbe803962000-06-28 23:40:59 +0000850 node->type);
851 }
852#endif
853 node = node->next;
854 }
855 return(ret);
856}
857
858/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000859 * xmlNewProp:
860 * @node: the holding node
861 * @name: the name of the attribute
862 * @value: the value of the attribute
863 *
864 * Create a new property carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000865 * Returns a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000866 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000867xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000868xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000869 xmlAttrPtr cur;
870
871 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000872#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000873 xmlGenericError(xmlGenericErrorContext,
874 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000875#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000876 return(NULL);
877 }
878
879 /*
880 * Allocate a new property and fill the fields.
881 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000882 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000883 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000884 xmlGenericError(xmlGenericErrorContext,
885 "xmlNewProp : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000886 return(NULL);
887 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000888 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillard33942841998-10-18 19:12:41 +0000889 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000890
891 cur->parent = node;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000892 cur->name = xmlStrdup(name);
Daniel Veillard51e3b151999-11-12 17:02:31 +0000893 if (value != NULL) {
894 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +0000895 xmlNodePtr tmp;
896
Daniel Veillard51e3b151999-11-12 17:02:31 +0000897 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +0000898 cur->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000899 cur->last = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +0000900 tmp = cur->children;
901 while (tmp != NULL) {
902 tmp->parent = (xmlNodePtr) cur;
903 if (tmp->next == NULL)
904 cur->last = tmp;
905 tmp = tmp->next;
906 }
Daniel Veillard51e3b151999-11-12 17:02:31 +0000907 xmlFree(buffer);
908 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000909
910 /*
911 * Add it at the end to preserve parsing order ...
912 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000913 if (node != NULL) {
914 if (node->properties == NULL) {
915 node->properties = cur;
916 } else {
917 xmlAttrPtr prev = node->properties;
918
919 while (prev->next != NULL) prev = prev->next;
920 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000921 cur->prev = prev;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000922 }
923 }
924 return(cur);
925}
926
927/**
928 * xmlNewNsProp:
929 * @node: the holding node
930 * @ns: the namespace
931 * @name: the name of the attribute
932 * @value: the value of the attribute
933 *
934 * Create a new property tagged with a namespace and carried by a node.
935 * Returns a pointer to the attribute
936 */
937xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000938xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
939 const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000940 xmlAttrPtr cur;
941
942 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000943#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000944 xmlGenericError(xmlGenericErrorContext,
945 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000946#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +0000947 return(NULL);
948 }
949
950 /*
951 * Allocate a new property and fill the fields.
952 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000953 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000954 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000955 xmlGenericError(xmlGenericErrorContext,
956 "xmlNewProp : malloc failed\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +0000957 return(NULL);
958 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000959 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000960 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000961
962 cur->parent = node;
963 if (node != NULL)
964 cur->doc = node->doc;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000965 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000966 cur->name = xmlStrdup(name);
Daniel Veillardcf461992000-03-14 18:30:20 +0000967 if (value != NULL) {
968 xmlChar *buffer;
969 xmlNodePtr tmp;
970
971 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
972 cur->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000973 cur->last = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +0000974 tmp = cur->children;
975 while (tmp != NULL) {
976 tmp->parent = (xmlNodePtr) cur;
977 if (tmp->next == NULL)
978 cur->last = tmp;
979 tmp = tmp->next;
980 }
981 xmlFree(buffer);
982 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000983
984 /*
985 * Add it at the end to preserve parsing order ...
986 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000987 if (node != NULL) {
988 if (node->properties == NULL) {
989 node->properties = cur;
990 } else {
991 xmlAttrPtr prev = node->properties;
992
993 while (prev->next != NULL) prev = prev->next;
994 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000995 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000996 }
997 }
998 return(cur);
999}
1000
Daniel Veillard97b58771998-10-20 06:14:16 +00001001/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001002 * xmlNewDocProp:
1003 * @doc: the document
1004 * @name: the name of the attribute
1005 * @value: the value of the attribute
1006 *
1007 * Create a new property carried by a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001008 * Returns a pointer to the attribute
Daniel Veillardccb09631998-10-27 06:21:04 +00001009 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001010xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001011xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001012 xmlAttrPtr cur;
1013
1014 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001015#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001016 xmlGenericError(xmlGenericErrorContext,
1017 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001018#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00001019 return(NULL);
1020 }
1021
1022 /*
1023 * Allocate a new property and fill the fields.
1024 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001025 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001026 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001027 xmlGenericError(xmlGenericErrorContext,
1028 "xmlNewProp : malloc failed\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00001029 return(NULL);
1030 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001031 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001032 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardccb09631998-10-27 06:21:04 +00001033
Daniel Veillardcf461992000-03-14 18:30:20 +00001034 cur->name = xmlStrdup(name);
1035 cur->doc = doc;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001036 if (value != NULL) {
1037 xmlNodePtr tmp;
1038
Daniel Veillardcf461992000-03-14 18:30:20 +00001039 cur->children = xmlStringGetNodeList(doc, value);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001040 cur->last = NULL;
1041
1042 tmp = cur->children;
1043 while (tmp != NULL) {
1044 tmp->parent = (xmlNodePtr) cur;
1045 if (tmp->next == NULL)
1046 cur->last = tmp;
1047 tmp = tmp->next;
1048 }
1049 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001050 return(cur);
1051}
1052
1053/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001054 * xmlFreePropList:
1055 * @cur: the first property in the list
1056 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001057 * Free a property and all its siblings, all the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001058 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001059void
1060xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001061 xmlAttrPtr next;
1062 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001063#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001064 xmlGenericError(xmlGenericErrorContext,
1065 "xmlFreePropList : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001066#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001067 return;
1068 }
1069 while (cur != NULL) {
1070 next = cur->next;
1071 xmlFreeProp(cur);
1072 cur = next;
1073 }
1074}
1075
Daniel Veillard97b58771998-10-20 06:14:16 +00001076/**
1077 * xmlFreeProp:
Daniel Veillard686d6b62000-01-03 11:08:02 +00001078 * @cur: an attribute
Daniel Veillard97b58771998-10-20 06:14:16 +00001079 *
Daniel Veillard686d6b62000-01-03 11:08:02 +00001080 * Free one attribute, all the content is freed too
Daniel Veillard260a68f1998-08-13 03:39:55 +00001081 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001082void
1083xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001084 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001085#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001086 xmlGenericError(xmlGenericErrorContext,
1087 "xmlFreeProp : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001088#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001089 return;
1090 }
Daniel Veillard71b656e2000-01-05 14:46:17 +00001091 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardcf461992000-03-14 18:30:20 +00001092 if ((cur->parent != NULL) &&
1093 (xmlIsID(cur->parent->doc, cur->parent, cur)))
1094 xmlRemoveID(cur->parent->doc, cur);
Daniel Veillard6454aec1999-09-02 22:04:43 +00001095 if (cur->name != NULL) xmlFree((char *) cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001096 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001097 memset(cur, -1, sizeof(xmlAttr));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001098 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001099}
1100
Daniel Veillard97b58771998-10-20 06:14:16 +00001101/**
Daniel Veillard686d6b62000-01-03 11:08:02 +00001102 * xmlRemoveProp:
1103 * @cur: an attribute
1104 *
1105 * Unlink and free one attribute, all the content is freed too
1106 * Note this doesn't work for namespace definition attributes
1107 *
1108 * Returns 0 if success and -1 in case of error.
1109 */
1110int
1111xmlRemoveProp(xmlAttrPtr cur) {
1112 xmlAttrPtr tmp;
1113 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001114#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001115 xmlGenericError(xmlGenericErrorContext,
1116 "xmlRemoveProp : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001117#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001118 return(-1);
1119 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001120 if (cur->parent == NULL) {
1121#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001122 xmlGenericError(xmlGenericErrorContext,
1123 "xmlRemoveProp : cur->parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001124#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001125 return(-1);
1126 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001127 tmp = cur->parent->properties;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001128 if (tmp == cur) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001129 cur->parent->properties = cur->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001130 xmlFreeProp(cur);
1131 return(0);
1132 }
1133 while (tmp != NULL) {
1134 if (tmp->next == cur) {
1135 tmp->next = cur->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00001136 if (tmp->next != NULL)
1137 tmp->next->prev = tmp;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001138 xmlFreeProp(cur);
1139 return(0);
1140 }
1141 tmp = tmp->next;
1142 }
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001143#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001144 xmlGenericError(xmlGenericErrorContext,
1145 "xmlRemoveProp : attribute not owned by its node\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001146#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001147 return(-1);
1148}
1149
1150/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001151 * xmlNewPI:
1152 * @name: the processing instruction name
1153 * @content: the PI content
1154 *
1155 * Creation of a processing instruction element.
1156 * Returns a pointer to the new node object.
1157 */
1158xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001159xmlNewPI(const xmlChar *name, const xmlChar *content) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001160 xmlNodePtr cur;
1161
1162 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001163#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001164 xmlGenericError(xmlGenericErrorContext,
1165 "xmlNewPI : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001166#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001167 return(NULL);
1168 }
1169
1170 /*
1171 * Allocate a new node and fill the fields.
1172 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001173 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001174 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001175 xmlGenericError(xmlGenericErrorContext,
1176 "xmlNewPI : malloc failed\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00001177 return(NULL);
1178 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001179 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001180 cur->type = XML_PI_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001181
Daniel Veillardb96e6431999-08-29 21:02:19 +00001182 cur->name = xmlStrdup(name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001183 if (content != NULL) {
1184#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00001185 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001186#else
1187 cur->content = xmlBufferCreateSize(0);
1188 xmlBufferSetAllocationScheme(cur->content,
1189 xmlGetBufferAllocationScheme());
1190 xmlBufferAdd(cur->content, content, -1);
1191#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001192 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001193 return(cur);
1194}
1195
1196/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001197 * xmlNewNode:
1198 * @ns: namespace if any
1199 * @name: the node name
Daniel Veillard97b58771998-10-20 06:14:16 +00001200 *
Daniel Veillarde0854c32000-08-27 21:12:29 +00001201 * Creation of a new node element. @ns is optionnal (NULL).
1202 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001203 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001204 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001205xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001206xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001207 xmlNodePtr cur;
1208
1209 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001210#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001211 xmlGenericError(xmlGenericErrorContext,
1212 "xmlNewNode : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001213#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001214 return(NULL);
1215 }
1216
1217 /*
1218 * Allocate a new node and fill the fields.
1219 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001220 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001221 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001222 xmlGenericError(xmlGenericErrorContext,
1223 "xmlNewNode : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001224 return(NULL);
1225 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001226 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard33942841998-10-18 19:12:41 +00001227 cur->type = XML_ELEMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001228
Daniel Veillard260a68f1998-08-13 03:39:55 +00001229 cur->name = xmlStrdup(name);
1230 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001231 return(cur);
1232}
1233
Daniel Veillard97b58771998-10-20 06:14:16 +00001234/**
1235 * xmlNewDocNode:
1236 * @doc: the document
1237 * @ns: namespace if any
1238 * @name: the node name
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001239 * @content: the XML text content if any
Daniel Veillard97b58771998-10-20 06:14:16 +00001240 *
1241 * Creation of a new node element within a document. @ns and @content
1242 * are optionnal (NULL).
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001243 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1244 * references, but XML special chars need to be escaped first by using
1245 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1246 * need entities support.
1247 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001248 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001249 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001250xmlNodePtr
1251xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001252 const xmlChar *name, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001253 xmlNodePtr cur;
1254
Daniel Veillardccb09631998-10-27 06:21:04 +00001255 cur = xmlNewNode(ns, name);
1256 if (cur != NULL) {
1257 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001258 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001259 cur->children = xmlStringGetNodeList(doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001260 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001261 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001262 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001263 return(cur);
1264}
1265
1266
Daniel Veillard97b58771998-10-20 06:14:16 +00001267/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001268 * xmlNewDocRawNode:
1269 * @doc: the document
1270 * @ns: namespace if any
1271 * @name: the node name
1272 * @content: the text content if any
1273 *
1274 * Creation of a new node element within a document. @ns and @content
1275 * are optionnal (NULL).
1276 *
1277 * Returns a pointer to the new node object.
1278 */
1279xmlNodePtr
1280xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1281 const xmlChar *name, const xmlChar *content) {
1282 xmlNodePtr cur;
1283
1284 cur = xmlNewNode(ns, name);
1285 if (cur != NULL) {
1286 cur->doc = doc;
1287 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001288 cur->children = xmlNewDocText(doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001289 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001290 }
1291 }
1292 return(cur);
1293}
1294
Daniel Veillard2eac5032000-01-09 21:08:56 +00001295/**
1296 * xmlNewDocFragment:
1297 * @doc: the document owning the fragment
1298 *
1299 * Creation of a new Fragment node.
1300 * Returns a pointer to the new node object.
1301 */
1302xmlNodePtr
1303xmlNewDocFragment(xmlDocPtr doc) {
1304 xmlNodePtr cur;
1305
1306 /*
1307 * Allocate a new DocumentFragment node and fill the fields.
1308 */
1309 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1310 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001311 xmlGenericError(xmlGenericErrorContext,
1312 "xmlNewDocFragment : malloc failed\n");
Daniel Veillard2eac5032000-01-09 21:08:56 +00001313 return(NULL);
1314 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001315 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard2eac5032000-01-09 21:08:56 +00001316 cur->type = XML_DOCUMENT_FRAG_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001317
Daniel Veillard2eac5032000-01-09 21:08:56 +00001318 cur->doc = doc;
Daniel Veillard2eac5032000-01-09 21:08:56 +00001319 return(cur);
1320}
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001321
1322/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001323 * xmlNewText:
1324 * @content: the text content
1325 *
1326 * Creation of a new text node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001327 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001328 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001329xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001330xmlNewText(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001331 xmlNodePtr cur;
1332
1333 /*
1334 * Allocate a new node and fill the fields.
1335 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001336 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001337 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001338 xmlGenericError(xmlGenericErrorContext,
1339 "xmlNewText : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001340 return(NULL);
1341 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001342 memset(cur, 0, sizeof(xmlNode));
1343 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001344
Daniel Veillard260a68f1998-08-13 03:39:55 +00001345 cur->name = xmlStrdup(xmlStringText);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001346 if (content != NULL) {
1347#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001348 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001349#else
1350 cur->content = xmlBufferCreateSize(0);
1351 xmlBufferSetAllocationScheme(cur->content,
1352 xmlGetBufferAllocationScheme());
1353 xmlBufferAdd(cur->content, content, -1);
1354#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001355 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001356 return(cur);
1357}
1358
Daniel Veillard97b58771998-10-20 06:14:16 +00001359/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001360 * xmlNewTextChild:
1361 * @parent: the parent node
1362 * @ns: a namespace if any
1363 * @name: the name of the child
1364 * @content: the text content of the child if any.
1365 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001366 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001367 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1368 * a child TEXT node will be created containing the string content.
1369 *
1370 * Returns a pointer to the new node object.
1371 */
1372xmlNodePtr
1373xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1374 const xmlChar *name, const xmlChar *content) {
1375 xmlNodePtr cur, prev;
1376
1377 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001378#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001379 xmlGenericError(xmlGenericErrorContext,
1380 "xmlNewTextChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001381#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001382 return(NULL);
1383 }
1384
1385 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001386#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001387 xmlGenericError(xmlGenericErrorContext,
1388 "xmlNewTextChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001389#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001390 return(NULL);
1391 }
1392
1393 /*
1394 * Allocate a new node
1395 */
1396 if (ns == NULL)
1397 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1398 else
1399 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1400 if (cur == NULL) return(NULL);
1401
1402 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001403 * add the new element at the end of the children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001404 */
1405 cur->type = XML_ELEMENT_NODE;
1406 cur->parent = parent;
1407 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001408 if (parent->children == NULL) {
1409 parent->children = cur;
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001410 parent->last = cur;
1411 } else {
1412 prev = parent->last;
1413 prev->next = cur;
1414 cur->prev = prev;
1415 parent->last = cur;
1416 }
1417
1418 return(cur);
1419}
1420
1421/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001422 * xmlNewCharRef:
1423 * @doc: the document
1424 * @name: the char ref string, starting with # or "&# ... ;"
1425 *
1426 * Creation of a new character reference node.
1427 * Returns a pointer to the new node object.
1428 */
1429xmlNodePtr
1430xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1431 xmlNodePtr cur;
1432
1433 /*
1434 * Allocate a new node and fill the fields.
1435 */
1436 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1437 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001438 xmlGenericError(xmlGenericErrorContext,
1439 "xmlNewText : malloc failed\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00001440 return(NULL);
1441 }
1442 memset(cur, 0, sizeof(xmlNode));
1443 cur->type = XML_ENTITY_REF_NODE;
1444
1445 cur->doc = doc;
1446 if (name[0] == '&') {
1447 int len;
1448 name++;
1449 len = xmlStrlen(name);
1450 if (name[len - 1] == ';')
1451 cur->name = xmlStrndup(name, len - 1);
1452 else
1453 cur->name = xmlStrndup(name, len);
1454 } else
1455 cur->name = xmlStrdup(name);
1456 return(cur);
1457}
1458
1459/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001460 * xmlNewReference:
1461 * @doc: the document
1462 * @name: the reference name, or the reference string with & and ;
1463 *
1464 * Creation of a new reference node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001465 * Returns a pointer to the new node object.
Daniel Veillardccb09631998-10-27 06:21:04 +00001466 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001467xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001468xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001469 xmlNodePtr cur;
1470 xmlEntityPtr ent;
1471
1472 /*
1473 * Allocate a new node and fill the fields.
1474 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001475 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001476 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001477 xmlGenericError(xmlGenericErrorContext,
1478 "xmlNewText : malloc failed\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00001479 return(NULL);
1480 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001481 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001482 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001483
Daniel Veillard10c6a8f1998-10-28 01:00:12 +00001484 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +00001485 if (name[0] == '&') {
1486 int len;
1487 name++;
1488 len = xmlStrlen(name);
1489 if (name[len - 1] == ';')
1490 cur->name = xmlStrndup(name, len - 1);
1491 else
1492 cur->name = xmlStrndup(name, len);
1493 } else
1494 cur->name = xmlStrdup(name);
Daniel Veillardccb09631998-10-27 06:21:04 +00001495
1496 ent = xmlGetDocEntity(doc, cur->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001497 if (ent != NULL) {
1498#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00001499 cur->content = ent->content;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001500#else
1501 /*
1502 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1503 * a copy of this pointer. Let's hope we don't manipulate it
1504 * later
1505 */
1506 cur->content = xmlBufferCreateSize(0);
1507 xmlBufferSetAllocationScheme(cur->content,
1508 xmlGetBufferAllocationScheme());
1509 if (ent->content != NULL)
1510 xmlBufferAdd(cur->content, ent->content, -1);
1511#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001512 /*
1513 * The parent pointer in entity is a Dtd pointer and thus is NOT
1514 * updated. Not sure if this is 100% correct.
1515 * -George
1516 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001517 cur->children = (xmlNodePtr) ent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001518 cur->last = (xmlNodePtr) ent;
Daniel Veillardcf461992000-03-14 18:30:20 +00001519 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001520 return(cur);
1521}
1522
1523/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001524 * xmlNewDocText:
1525 * @doc: the document
1526 * @content: the text content
1527 *
1528 * Creation of a new text node within a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001529 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001530 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001531xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001532xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001533 xmlNodePtr cur;
1534
1535 cur = xmlNewText(content);
1536 if (cur != NULL) cur->doc = doc;
1537 return(cur);
1538}
1539
Daniel Veillard97b58771998-10-20 06:14:16 +00001540/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001541 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001542 * @content: the text content
1543 * @len: the text len.
1544 *
1545 * Creation of a new text node with an extra parameter for the content's lenght
Daniel Veillard1e346af1999-02-22 10:33:01 +00001546 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001547 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001548xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001549xmlNewTextLen(const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001550 xmlNodePtr cur;
1551
1552 /*
1553 * Allocate a new node and fill the fields.
1554 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001555 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001556 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001557 xmlGenericError(xmlGenericErrorContext,
1558 "xmlNewText : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001559 return(NULL);
1560 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001561 memset(cur, 0, sizeof(xmlNode));
1562 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001563
Daniel Veillard260a68f1998-08-13 03:39:55 +00001564 cur->name = xmlStrdup(xmlStringText);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001565 if (content != NULL) {
1566#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001567 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001568#else
1569 cur->content = xmlBufferCreateSize(len);
1570 xmlBufferSetAllocationScheme(cur->content,
1571 xmlGetBufferAllocationScheme());
1572 xmlBufferAdd(cur->content, content, len);
1573#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001574 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001575 return(cur);
1576}
1577
Daniel Veillard97b58771998-10-20 06:14:16 +00001578/**
1579 * xmlNewDocTextLen:
1580 * @doc: the document
1581 * @content: the text content
1582 * @len: the text len.
1583 *
1584 * Creation of a new text node with an extra content lenght parameter. The
1585 * text node pertain to a given document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001586 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001587 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001588xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001589xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001590 xmlNodePtr cur;
1591
1592 cur = xmlNewTextLen(content, len);
1593 if (cur != NULL) cur->doc = doc;
1594 return(cur);
1595}
1596
Daniel Veillard97b58771998-10-20 06:14:16 +00001597/**
1598 * xmlNewComment:
1599 * @content: the comment content
1600 *
1601 * Creation of a new node containing a comment.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001602 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001603 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001604xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001605xmlNewComment(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001606 xmlNodePtr cur;
1607
1608 /*
1609 * Allocate a new node and fill the fields.
1610 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001611 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001612 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001613 xmlGenericError(xmlGenericErrorContext,
1614 "xmlNewComment : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001615 return(NULL);
1616 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001617 memset(cur, 0, sizeof(xmlNode));
1618 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001619
Daniel Veillardcf461992000-03-14 18:30:20 +00001620 cur->name = xmlStrdup(xmlStringComment);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001621 if (content != NULL) {
1622#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001623 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001624#else
1625 cur->content = xmlBufferCreateSize(0);
1626 xmlBufferSetAllocationScheme(cur->content,
1627 xmlGetBufferAllocationScheme());
1628 xmlBufferAdd(cur->content, content, -1);
1629#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001630 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001631 return(cur);
1632}
1633
Daniel Veillard97b58771998-10-20 06:14:16 +00001634/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001635 * xmlNewCDataBlock:
1636 * @doc: the document
1637 * @content: the CData block content content
1638 * @len: the length of the block
1639 *
1640 * Creation of a new node containing a CData block.
1641 * Returns a pointer to the new node object.
1642 */
1643xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001644xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001645 xmlNodePtr cur;
1646
1647 /*
1648 * Allocate a new node and fill the fields.
1649 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001650 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001651 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001652 xmlGenericError(xmlGenericErrorContext,
1653 "xmlNewCDataBlock : malloc failed\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +00001654 return(NULL);
1655 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001656 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001657 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001658
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001659 if (content != NULL) {
1660#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00001661 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001662#else
1663 cur->content = xmlBufferCreateSize(len);
1664 xmlBufferSetAllocationScheme(cur->content,
1665 xmlGetBufferAllocationScheme());
1666 xmlBufferAdd(cur->content, content, len);
1667#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001668 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001669 return(cur);
1670}
1671
1672/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001673 * xmlNewDocComment:
Daniel Veillard97b58771998-10-20 06:14:16 +00001674 * @doc: the document
1675 * @content: the comment content
1676 *
1677 * Creation of a new node containing a commentwithin a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001678 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001679 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001680xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001681xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001682 xmlNodePtr cur;
1683
1684 cur = xmlNewComment(content);
1685 if (cur != NULL) cur->doc = doc;
1686 return(cur);
1687}
1688
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001689/**
1690 * xmlSetTreeDoc:
1691 * @tree: the top element
1692 * @doc: the document
1693 *
1694 * update all nodes under the tree to point to the right document
1695 */
1696void
1697xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
1698 if (tree == NULL)
1699 return;
1700 if (tree->type == XML_ENTITY_DECL)
1701 return;
1702 if (tree->doc != doc) {
1703 if (tree->children != NULL)
1704 xmlSetListDoc(tree->children, doc);
1705 tree->doc = doc;
1706 }
1707}
1708
1709/**
1710 * xmlSetListDoc:
1711 * @tree: the first element
1712 * @doc: the document
1713 *
1714 * update all nodes in the list to point to the right document
1715 */
1716void
1717xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1718 xmlNodePtr cur;
1719
1720 if (list == NULL)
1721 return;
1722 cur = list;
1723 while (cur != NULL) {
1724 if (cur->doc != doc)
1725 xmlSetTreeDoc(cur, doc);
1726 cur = cur->next;
1727 }
1728}
1729
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001730
Daniel Veillard97b58771998-10-20 06:14:16 +00001731/**
1732 * xmlNewChild:
1733 * @parent: the parent node
1734 * @ns: a namespace if any
1735 * @name: the name of the child
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001736 * @content: the XML content of the child if any.
Daniel Veillard97b58771998-10-20 06:14:16 +00001737 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001738 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001739 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1740 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001741 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1742 * references, but XML special chars need to be escaped first by using
1743 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1744 * support is not needed.
1745 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001746 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001747 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001748xmlNodePtr
1749xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001750 const xmlChar *name, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001751 xmlNodePtr cur, prev;
1752
1753 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001754#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001755 xmlGenericError(xmlGenericErrorContext,
1756 "xmlNewChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001757#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001758 return(NULL);
1759 }
1760
1761 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001762#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001763 xmlGenericError(xmlGenericErrorContext,
1764 "xmlNewChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001765#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001766 return(NULL);
1767 }
1768
1769 /*
1770 * Allocate a new node
1771 */
1772 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001773 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001774 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001775 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001776 if (cur == NULL) return(NULL);
1777
1778 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001779 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001780 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001781 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001782 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001783 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001784 if (parent->children == NULL) {
1785 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001786 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001787 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001788 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001789 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001790 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001791 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001792 }
1793
1794 return(cur);
1795}
1796
Daniel Veillard97b58771998-10-20 06:14:16 +00001797/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001798 * xmlAddNextSibling:
1799 * @cur: the child node
1800 * @elem: the new node
1801 *
1802 * Add a new element @elem as the next siblings of @cur
1803 * If the new element was already inserted in a document it is
1804 * first unlinked from its existing context.
Daniel Veillard683cb022000-10-22 12:04:13 +00001805 * As a result of text merging @elem may be freed.
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001806 *
1807 * Returns the new element or NULL in case of error.
1808 */
1809xmlNodePtr
1810xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1811 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001812#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001813 xmlGenericError(xmlGenericErrorContext,
1814 "xmlAddNextSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001815#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001816 return(NULL);
1817 }
1818 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001819#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001820 xmlGenericError(xmlGenericErrorContext,
1821 "xmlAddNextSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001822#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001823 return(NULL);
1824 }
1825
1826 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00001827
1828 if (elem->type == XML_TEXT_NODE) {
1829 if (cur->type == XML_TEXT_NODE) {
1830#ifndef XML_USE_BUFFER_CONTENT
1831 xmlNodeAddContent(cur, elem->content);
1832#else
1833 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1834#endif
1835 xmlFreeNode(elem);
1836 return(cur);
1837 }
1838 if ((cur->next != NULL) && (cur->type == XML_TEXT_NODE)) {
1839#ifndef XML_USE_BUFFER_CONTENT
1840 xmlChar *tmp;
1841
1842 tmp = xmlStrdup(elem->content);
1843 tmp = xmlStrcat(tmp, cur->next->content);
1844 xmlNodeSetContent(cur->next, tmp);
1845 xmlFree(tmp);
1846#else
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001847 xmlBufferAddHead(cur->next->content,
1848 xmlBufferContent(elem->content),
Daniel Veillard683cb022000-10-22 12:04:13 +00001849 xmlBufferLength(elem->content));
1850#endif
1851 xmlFreeNode(elem);
1852 return(cur->next);
1853 }
1854 }
1855
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001856 if (elem->doc != cur->doc) {
1857 xmlSetTreeDoc(elem, cur->doc);
1858 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001859 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001860 elem->prev = cur;
1861 elem->next = cur->next;
1862 cur->next = elem;
1863 if (elem->next != NULL)
1864 elem->next->prev = elem;
1865 if ((elem->parent != NULL) && (elem->parent->last == cur))
1866 elem->parent->last = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001867 return(elem);
1868}
1869
1870/**
1871 * xmlAddPrevSibling:
1872 * @cur: the child node
1873 * @elem: the new node
1874 *
1875 * Add a new element @elem as the previous siblings of @cur
Daniel Veillard683cb022000-10-22 12:04:13 +00001876 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001877 * If the new element was already inserted in a document it is
1878 * first unlinked from its existing context.
1879 *
1880 * Returns the new element or NULL in case of error.
1881 */
1882xmlNodePtr
1883xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
1884 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001885#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001886 xmlGenericError(xmlGenericErrorContext,
1887 "xmlAddPrevSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001888#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001889 return(NULL);
1890 }
1891 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001892#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001893 xmlGenericError(xmlGenericErrorContext,
1894 "xmlAddPrevSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001895#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001896 return(NULL);
1897 }
1898
1899 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00001900
1901 if (elem->type == XML_TEXT_NODE) {
1902 if (cur->type == XML_TEXT_NODE) {
1903#ifndef XML_USE_BUFFER_CONTENT
1904 xmlChar *tmp;
1905
1906 tmp = xmlStrdup(elem->content);
1907 tmp = xmlStrcat(tmp, cur->content);
1908 xmlNodeSetContent(cur, tmp);
1909 xmlFree(tmp);
1910#else
1911 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
1912 xmlBufferLength(elem->content));
1913#endif
1914 xmlFreeNode(elem);
1915 return(cur);
1916 }
1917 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE)) {
1918#ifndef XML_USE_BUFFER_CONTENT
1919 xmlNodeAddContent(cur->prev, elem->content);
1920#else
1921 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
1922#endif
1923 xmlFreeNode(elem);
1924 return(cur->prev);
1925 }
1926 }
1927
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001928 if (elem->doc != cur->doc) {
1929 xmlSetTreeDoc(elem, cur->doc);
1930 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001931 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001932 elem->next = cur;
1933 elem->prev = cur->prev;
1934 cur->prev = elem;
1935 if (elem->prev != NULL)
1936 elem->prev->next = elem;
1937 if ((elem->parent != NULL) && (elem->parent->children == cur))
1938 elem->parent->children = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001939 return(elem);
1940}
1941
1942/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001943 * xmlAddSibling:
1944 * @cur: the child node
1945 * @elem: the new node
1946 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001947 * Add a new element @elem to the list of siblings of @cur
Daniel Veillard683cb022000-10-22 12:04:13 +00001948 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001949 * If the new element was already inserted in a document it is
1950 * first unlinked from its existing context.
1951 *
1952 * Returns the new element or NULL in case of error.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001953 */
1954xmlNodePtr
1955xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
1956 xmlNodePtr parent;
1957
1958 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001959#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001960 xmlGenericError(xmlGenericErrorContext,
1961 "xmlAddSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001962#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001963 return(NULL);
1964 }
1965
1966 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001967#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001968 xmlGenericError(xmlGenericErrorContext,
1969 "xmlAddSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001970#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001971 return(NULL);
1972 }
1973
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001974 /*
1975 * Constant time is we can rely on the ->parent->last to find
1976 * the last sibling.
1977 */
1978 if ((cur->parent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +00001979 (cur->parent->children != NULL) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001980 (cur->parent->last != NULL) &&
1981 (cur->parent->last->next == NULL)) {
1982 cur = cur->parent->last;
1983 } else {
1984 while (cur->next != NULL) cur = cur->next;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001985 }
1986
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001987 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00001988
1989 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
1990#ifndef XML_USE_BUFFER_CONTENT
1991 xmlNodeAddContent(cur, elem->content);
1992#else
1993 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1994#endif
1995 xmlFreeNode(elem);
1996 return(cur);
1997 }
1998
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001999 if (elem->doc != cur->doc) {
2000 xmlSetTreeDoc(elem, cur->doc);
2001 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002002 parent = cur->parent;
2003 elem->prev = cur;
2004 elem->next = NULL;
2005 elem->parent = parent;
2006 cur->next = elem;
2007 if (parent != NULL)
2008 parent->last = elem;
2009
2010 return(elem);
2011}
2012
2013/**
Daniel Veillard87b95392000-08-12 21:12:04 +00002014 * xmlAddChildList:
2015 * @parent: the parent node
2016 * @cur: the first node in the list
2017 *
2018 * Add a list of node at the end of the child list of the parent
Daniel Veillard683cb022000-10-22 12:04:13 +00002019 * merging adjacent TEXT nodes (@cur may be freed)
Daniel Veillard87b95392000-08-12 21:12:04 +00002020 *
2021 * Returns the last child or NULL in case of error.
2022 */
2023xmlNodePtr
2024xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2025 xmlNodePtr prev;
2026
2027 if (parent == NULL) {
2028#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002029 xmlGenericError(xmlGenericErrorContext,
2030 "xmlAddChild : parent == NULL\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002031#endif
2032 return(NULL);
2033 }
2034
2035 if (cur == NULL) {
2036#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002037 xmlGenericError(xmlGenericErrorContext,
2038 "xmlAddChild : child == NULL\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002039#endif
2040 return(NULL);
2041 }
2042
2043 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2044 (cur->doc != parent->doc)) {
2045#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002046 xmlGenericError(xmlGenericErrorContext,
2047 "Elements moved to a different document\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002048#endif
2049 }
2050
2051 /*
2052 * add the first element at the end of the children list.
2053 */
2054 if (parent->children == NULL) {
2055 parent->children = cur;
2056 } else {
Daniel Veillard683cb022000-10-22 12:04:13 +00002057 /*
2058 * If cur and parent->last both are TEXT nodes, then merge them.
2059 */
2060 if ((cur->type == XML_TEXT_NODE) &&
2061 (parent->last->type == XML_TEXT_NODE)) {
2062#ifndef XML_USE_BUFFER_CONTENT
2063 xmlNodeAddContent(parent->last, cur->content);
2064#else
2065 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2066#endif
2067 /*
2068 * if it's the only child, nothing more to be done.
2069 */
2070 if (cur->next == NULL) {
2071 xmlFreeNode(cur);
2072 return(parent->last);
2073 }
2074 prev = cur;
2075 cur = cur->next;
2076 xmlFreeNode(prev);
2077 }
Daniel Veillard87b95392000-08-12 21:12:04 +00002078 prev = parent->last;
2079 prev->next = cur;
2080 cur->prev = prev;
2081 }
2082 while (cur->next != NULL) {
2083 cur->parent = parent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002084 if (cur->doc != parent->doc) {
2085 xmlSetTreeDoc(cur, parent->doc);
2086 }
Daniel Veillard87b95392000-08-12 21:12:04 +00002087 cur = cur->next;
2088 }
2089 cur->parent = parent;
2090 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2091 parent->last = cur;
2092
2093 return(cur);
2094}
2095
2096/**
Daniel Veillard97b58771998-10-20 06:14:16 +00002097 * xmlAddChild:
2098 * @parent: the parent node
2099 * @cur: the child node
2100 *
Daniel Veillard683cb022000-10-22 12:04:13 +00002101 * Add a new child element, to @parent, at the end of the child list
2102 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillard1e346af1999-02-22 10:33:01 +00002103 * Returns the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002104 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002105xmlNodePtr
2106xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002107 xmlNodePtr prev;
2108
2109 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002110#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002111 xmlGenericError(xmlGenericErrorContext,
2112 "xmlAddChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002113#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002114 return(NULL);
2115 }
2116
2117 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002118#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002119 xmlGenericError(xmlGenericErrorContext,
2120 "xmlAddChild : child == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002121#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002122 return(NULL);
2123 }
2124
Daniel Veillard0bef1311998-10-14 02:36:47 +00002125 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2126 (cur->doc != parent->doc)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002127#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002128 xmlGenericError(xmlGenericErrorContext,
2129 "Elements moved to a different document\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002130#endif
Daniel Veillard0bef1311998-10-14 02:36:47 +00002131 }
2132
Daniel Veillard260a68f1998-08-13 03:39:55 +00002133 /*
Daniel Veillard683cb022000-10-22 12:04:13 +00002134 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
2135 * or with parent->content if parent->content != NULL.
2136 * cur is then freed.
2137 */
2138 if (cur->type == XML_TEXT_NODE) {
2139 if (((parent->type == XML_ELEMENT_NODE) ||
2140 (parent->type == XML_TEXT_NODE)) &&
2141 (parent->content != NULL)) {
2142#ifndef XML_USE_BUFFER_CONTENT
2143 xmlNodeAddContent(parent, cur->content);
2144#else
2145 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2146#endif
2147 xmlFreeNode(cur);
2148 return(parent);
2149 }
2150 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE)) {
2151#ifndef XML_USE_BUFFER_CONTENT
2152 xmlNodeAddContent(parent->last, cur->content);
2153#else
2154 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2155#endif
2156 xmlFreeNode(cur);
2157 return(parent->last);
2158 }
2159 }
2160
2161 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00002162 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002163 */
2164 cur->parent = parent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002165 if (cur->doc != parent->doc) {
2166 xmlSetTreeDoc(cur, parent->doc);
2167 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002168
Daniel Veillardccb09631998-10-27 06:21:04 +00002169 /*
2170 * Handle the case where parent->content != NULL, in that case it will
2171 * create a intermediate TEXT node.
2172 */
Daniel Veillardcf461992000-03-14 18:30:20 +00002173 if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
2174 (parent->content != NULL)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002175 xmlNodePtr text;
2176
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002177#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00002178 text = xmlNewDocText(parent->doc, parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002179#else
2180 text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
2181#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002182 if (text != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002183 text->next = parent->children;
Daniel Veillardccb09631998-10-27 06:21:04 +00002184 if (text->next != NULL)
2185 text->next->prev = text;
Daniel Veillardcf461992000-03-14 18:30:20 +00002186 parent->children = text;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002187 UPDATE_LAST_CHILD_AND_PARENT(parent)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002188#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002189 xmlFree(parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002190#else
2191 xmlBufferFree(parent->content);
2192#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002193 parent->content = NULL;
2194 }
2195 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002196 if (parent->children == NULL) {
2197 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002198 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002199 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002200 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002201 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00002202 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002203 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002204 }
2205
2206 return(cur);
2207}
2208
Daniel Veillard97b58771998-10-20 06:14:16 +00002209/**
2210 * xmlGetLastChild:
2211 * @parent: the parent node
2212 *
2213 * Search the last child of a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002214 * Returns the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002215 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002216xmlNodePtr
2217xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002218 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002219#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002220 xmlGenericError(xmlGenericErrorContext,
2221 "xmlGetLastChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002222#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002223 return(NULL);
2224 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002225 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002226}
2227
Daniel Veillard97b58771998-10-20 06:14:16 +00002228/**
2229 * xmlFreeNodeList:
2230 * @cur: the first node in the list
2231 *
2232 * Free a node and all its siblings, this is a recursive behaviour, all
Daniel Veillardcf461992000-03-14 18:30:20 +00002233 * the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002234 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002235void
2236xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002237 xmlNodePtr next;
2238 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002239#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002240 xmlGenericError(xmlGenericErrorContext,
2241 "xmlFreeNodeList : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002242#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002243 return;
2244 }
2245 while (cur != NULL) {
2246 next = cur->next;
2247 xmlFreeNode(cur);
2248 cur = next;
2249 }
2250}
2251
Daniel Veillard97b58771998-10-20 06:14:16 +00002252/**
2253 * xmlFreeNode:
2254 * @cur: the node
2255 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002256 * Free a node, this is a recursive behaviour, all the children are freed too.
2257 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002258 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002259void
2260xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002261 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002262#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002263 xmlGenericError(xmlGenericErrorContext,
2264 "xmlFreeNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002265#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002266 return;
2267 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002268 if (cur->type == XML_DTD_NODE)
2269 return;
Daniel Veillardccb09631998-10-27 06:21:04 +00002270 cur->doc = NULL;
2271 cur->parent = NULL;
2272 cur->next = NULL;
2273 cur->prev = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002274 if ((cur->children != NULL) &&
2275 (cur->type != XML_ENTITY_REF_NODE))
2276 xmlFreeNodeList(cur->children);
Daniel Veillardccb09631998-10-27 06:21:04 +00002277 if (cur->properties != NULL) xmlFreePropList(cur->properties);
2278 if (cur->type != XML_ENTITY_REF_NODE)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002279#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002280 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002281#else
2282 if (cur->content != NULL) xmlBufferFree(cur->content);
2283#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00002284 if (cur->name != NULL) xmlFree((char *) cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002285 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
2286 memset(cur, -1, sizeof(xmlNode));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002287 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002288}
2289
Daniel Veillard16253641998-10-28 22:58:05 +00002290/**
2291 * xmlUnlinkNode:
2292 * @cur: the node
2293 *
2294 * Unlink a node from it's current context, the node is not freed
2295 */
2296void
2297xmlUnlinkNode(xmlNodePtr cur) {
2298 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002299#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002300 xmlGenericError(xmlGenericErrorContext,
2301 "xmlUnlinkNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002302#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002303 return;
2304 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002305 if ((cur->parent != NULL) && (cur->parent->children == cur))
2306 cur->parent->children = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002307 if ((cur->parent != NULL) && (cur->parent->last == cur))
2308 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00002309 if (cur->next != NULL)
2310 cur->next->prev = cur->prev;
2311 if (cur->prev != NULL)
2312 cur->prev->next = cur->next;
2313 cur->next = cur->prev = NULL;
2314 cur->parent = NULL;
2315}
2316
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002317/**
2318 * xmlReplaceNode:
2319 * @old: the old node
2320 * @cur: the node
2321 *
2322 * Unlink the old node from it's current context, prune the new one
2323 * at the same place. If cur was already inserted in a document it is
2324 * first unlinked from its existing context.
2325 *
2326 * Returns the old node
2327 */
2328xmlNodePtr
2329xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2330 if (old == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002331#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002332 xmlGenericError(xmlGenericErrorContext,
2333 "xmlReplaceNode : old == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002334#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002335 return(NULL);
2336 }
2337 if (cur == NULL) {
2338 xmlUnlinkNode(old);
2339 return(old);
2340 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002341 if (cur == old) {
2342 return(old);
2343 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002344 xmlUnlinkNode(cur);
2345 cur->doc = old->doc;
2346 cur->parent = old->parent;
2347 cur->next = old->next;
2348 if (cur->next != NULL)
2349 cur->next->prev = cur;
2350 cur->prev = old->prev;
2351 if (cur->prev != NULL)
2352 cur->prev->next = cur;
2353 if (cur->parent != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002354 if (cur->parent->children == old)
2355 cur->parent->children = cur;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002356 if (cur->parent->last == old)
2357 cur->parent->last = cur;
2358 }
2359 old->next = old->prev = NULL;
2360 old->parent = NULL;
2361 return(old);
2362}
2363
Daniel Veillard260a68f1998-08-13 03:39:55 +00002364/************************************************************************
2365 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002366 * Copy operations *
2367 * *
2368 ************************************************************************/
2369
2370/**
2371 * xmlCopyNamespace:
2372 * @cur: the namespace
2373 *
2374 * Do a copy of the namespace.
2375 *
2376 * Returns: a new xmlNsPtr, or NULL in case of error.
2377 */
2378xmlNsPtr
2379xmlCopyNamespace(xmlNsPtr cur) {
2380 xmlNsPtr ret;
2381
2382 if (cur == NULL) return(NULL);
2383 switch (cur->type) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002384 case XML_LOCAL_NAMESPACE:
2385 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2386 break;
2387 default:
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002388#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002389 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda4964b72000-10-31 18:23:44 +00002390 "xmlCopyNamespace: invalid type %d\n", cur->type);
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002391#endif
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002392 return(NULL);
2393 }
2394 return(ret);
2395}
2396
2397/**
2398 * xmlCopyNamespaceList:
2399 * @cur: the first namespace
2400 *
2401 * Do a copy of an namespace list.
2402 *
2403 * Returns: a new xmlNsPtr, or NULL in case of error.
2404 */
2405xmlNsPtr
2406xmlCopyNamespaceList(xmlNsPtr cur) {
2407 xmlNsPtr ret = NULL;
2408 xmlNsPtr p = NULL,q;
2409
2410 while (cur != NULL) {
2411 q = xmlCopyNamespace(cur);
2412 if (p == NULL) {
2413 ret = p = q;
2414 } else {
2415 p->next = q;
2416 p = q;
2417 }
2418 cur = cur->next;
2419 }
2420 return(ret);
2421}
2422
2423/**
2424 * xmlCopyProp:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002425 * @target: the element where the attribute will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002426 * @cur: the attribute
2427 *
2428 * Do a copy of the attribute.
2429 *
2430 * Returns: a new xmlAttrPtr, or NULL in case of error.
2431 */
2432xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002433xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002434 xmlAttrPtr ret;
2435
2436 if (cur == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002437 if (cur->parent != NULL)
2438 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2439 else if (cur->children != NULL)
2440 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002441 else
2442 ret = xmlNewDocProp(NULL, cur->name, NULL);
2443 if (ret == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002444 ret->parent = target;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002445
2446 if ((cur->ns != NULL) && (target != NULL)) {
2447 xmlNsPtr ns;
2448
2449 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2450 ret->ns = ns;
2451 } else
2452 ret->ns = NULL;
2453
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002454 if (cur->children != NULL) {
2455 xmlNodePtr tmp;
2456
Daniel Veillardcf461992000-03-14 18:30:20 +00002457 ret->children = xmlCopyNodeList(cur->children);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002458 ret->last = NULL;
2459 tmp = ret->children;
2460 while (tmp != NULL) {
2461 tmp->parent = (xmlNodePtr)ret;
2462 if (tmp->next == NULL)
2463 ret->last = tmp;
2464 tmp = tmp->next;
2465 }
2466 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002467 return(ret);
2468}
2469
2470/**
2471 * xmlCopyPropList:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002472 * @target: the element where the attributes will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002473 * @cur: the first attribute
2474 *
2475 * Do a copy of an attribute list.
2476 *
2477 * Returns: a new xmlAttrPtr, or NULL in case of error.
2478 */
2479xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002480xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002481 xmlAttrPtr ret = NULL;
2482 xmlAttrPtr p = NULL,q;
2483
2484 while (cur != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002485 q = xmlCopyProp(target, cur);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002486 if (p == NULL) {
2487 ret = p = q;
2488 } else {
2489 p->next = q;
Daniel Veillardcf461992000-03-14 18:30:20 +00002490 q->prev = p;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002491 p = q;
2492 }
2493 cur = cur->next;
2494 }
2495 return(ret);
2496}
2497
2498/*
Daniel Veillard11a48ec1999-11-23 10:40:46 +00002499 * NOTE abeut the CopyNode operations !
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002500 *
2501 * They are splitted into external and internal parts for one
2502 * tricky reason: namespaces. Doing a direct copy of a node
2503 * say RPM:Copyright without changing the namespace pointer to
2504 * something else can produce stale links. One way to do it is
2505 * to keep a reference counter but this doesn't work as soon
2506 * as one move the element or the subtree out of the scope of
2507 * the existing namespace. The actual solution seems to add
2508 * a copy of the namespace at the top of the copied tree if
2509 * not available in the subtree.
2510 * Hence two functions, the public front-end call the inner ones
2511 */
2512
2513static xmlNodePtr
2514xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2515
2516static xmlNodePtr
2517xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
2518 int recursive) {
2519 xmlNodePtr ret;
2520
2521 if (node == NULL) return(NULL);
2522 /*
2523 * Allocate a new node and fill the fields.
2524 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00002525 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002526 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002527 xmlGenericError(xmlGenericErrorContext,
2528 "xmlStaticCopyNode : malloc failed\n");
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002529 return(NULL);
2530 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002531 memset(ret, 0, sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002532 ret->type = node->type;
Daniel Veillardcf461992000-03-14 18:30:20 +00002533
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002534 ret->doc = doc;
2535 ret->parent = parent;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002536 if (node->name != NULL)
2537 ret->name = xmlStrdup(node->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002538 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
2539#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002540 ret->content = xmlStrdup(node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002541#else
2542 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2543 xmlBufferSetAllocationScheme(ret->content,
2544 xmlGetBufferAllocationScheme());
2545 xmlBufferAdd(ret->content,
2546 xmlBufferContent(node->content),
2547 xmlBufferLength(node->content));
2548#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002549 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002550 if (parent != NULL)
2551 xmlAddChild(parent, ret);
2552
2553 if (!recursive) return(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002554 if (node->nsDef != NULL)
2555 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2556
2557 if (node->ns != NULL) {
2558 xmlNsPtr ns;
2559
2560 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2561 if (ns == NULL) {
2562 /*
2563 * Humm, we are copying an element whose namespace is defined
2564 * out of the new tree scope. Search it in the original tree
2565 * and add it at the top of the new tree
2566 */
2567 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2568 if (ns != NULL) {
2569 xmlNodePtr root = ret;
2570
2571 while (root->parent != NULL) root = root->parent;
2572 xmlNewNs(root, ns->href, ns->prefix);
2573 }
2574 } else {
2575 /*
2576 * reference the existing namespace definition in our own tree.
2577 */
2578 ret->ns = ns;
2579 }
2580 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002581 if (node->properties != NULL)
2582 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardcf461992000-03-14 18:30:20 +00002583 if (node->children != NULL)
2584 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002585 UPDATE_LAST_CHILD_AND_PARENT(ret)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002586 return(ret);
2587}
2588
2589static xmlNodePtr
2590xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2591 xmlNodePtr ret = NULL;
2592 xmlNodePtr p = NULL,q;
2593
2594 while (node != NULL) {
2595 q = xmlStaticCopyNode(node, doc, parent, 1);
Daniel Veillard06047432000-04-24 11:33:38 +00002596 if (ret == NULL) {
2597 q->prev = NULL;
2598 ret = p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002599 } else {
Daniel Veillard06047432000-04-24 11:33:38 +00002600 p->next = q;
2601 q->prev = p;
2602 p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002603 }
2604 node = node->next;
2605 }
2606 return(ret);
2607}
2608
2609/**
2610 * xmlCopyNode:
2611 * @node: the node
2612 * @recursive: if 1 do a recursive copy.
2613 *
2614 * Do a copy of the node.
2615 *
2616 * Returns: a new xmlNodePtr, or NULL in case of error.
2617 */
2618xmlNodePtr
2619xmlCopyNode(xmlNodePtr node, int recursive) {
2620 xmlNodePtr ret;
2621
2622 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2623 return(ret);
2624}
2625
2626/**
2627 * xmlCopyNodeList:
2628 * @node: the first node in the list.
2629 *
2630 * Do a recursive copy of the node list.
2631 *
2632 * Returns: a new xmlNodePtr, or NULL in case of error.
2633 */
2634xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2635 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2636 return(ret);
2637}
2638
2639/**
2640 * xmlCopyElement:
2641 * @elem: the element
2642 *
2643 * Do a copy of the element definition.
2644 *
2645 * Returns: a new xmlElementPtr, or NULL in case of error.
2646xmlElementPtr
2647xmlCopyElement(xmlElementPtr elem) {
2648 xmlElementPtr ret;
2649
2650 if (elem == NULL) return(NULL);
2651 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
2652 if (ret == NULL) return(NULL);
2653 if (!recursive) return(ret);
2654 if (elem->properties != NULL)
2655 ret->properties = xmlCopyPropList(elem->properties);
2656
2657 if (elem->nsDef != NULL)
2658 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
Daniel Veillardcf461992000-03-14 18:30:20 +00002659 if (elem->children != NULL)
2660 ret->children = xmlCopyElementList(elem->children);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002661 return(ret);
2662}
2663 */
2664
2665/**
2666 * xmlCopyDtd:
2667 * @dtd: the dtd
2668 *
2669 * Do a copy of the dtd.
2670 *
2671 * Returns: a new xmlDtdPtr, or NULL in case of error.
2672 */
2673xmlDtdPtr
2674xmlCopyDtd(xmlDtdPtr dtd) {
2675 xmlDtdPtr ret;
2676
2677 if (dtd == NULL) return(NULL);
2678 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2679 if (ret == NULL) return(NULL);
2680 if (dtd->entities != NULL)
2681 ret->entities = (void *) xmlCopyEntitiesTable(
2682 (xmlEntitiesTablePtr) dtd->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002683 if (dtd->notations != NULL)
2684 ret->notations = (void *) xmlCopyNotationTable(
2685 (xmlNotationTablePtr) dtd->notations);
2686 if (dtd->elements != NULL)
2687 ret->elements = (void *) xmlCopyElementTable(
2688 (xmlElementTablePtr) dtd->elements);
2689 if (dtd->attributes != NULL)
2690 ret->attributes = (void *) xmlCopyAttributeTable(
2691 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002692 return(ret);
2693}
2694
2695/**
2696 * xmlCopyDoc:
2697 * @doc: the document
2698 * @recursive: if 1 do a recursive copy.
2699 *
2700 * Do a copy of the document info. If recursive, the content tree will
2701 * be copied too as well as Dtd, namespaces and entities.
2702 *
2703 * Returns: a new xmlDocPtr, or NULL in case of error.
2704 */
2705xmlDocPtr
2706xmlCopyDoc(xmlDocPtr doc, int recursive) {
2707 xmlDocPtr ret;
2708
2709 if (doc == NULL) return(NULL);
2710 ret = xmlNewDoc(doc->version);
2711 if (ret == NULL) return(NULL);
2712 if (doc->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002713 ret->name = xmlMemStrdup(doc->name);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002714 if (doc->encoding != NULL)
2715 ret->encoding = xmlStrdup(doc->encoding);
2716 ret->compression = doc->compression;
2717 ret->standalone = doc->standalone;
2718 if (!recursive) return(ret);
2719
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002720 if (doc->intSubset != NULL)
2721 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002722 if (doc->oldNs != NULL)
2723 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002724 if (doc->children != NULL) {
2725 xmlNodePtr tmp;
Daniel Veillard06047432000-04-24 11:33:38 +00002726 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2727 (xmlNodePtr)ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002728 ret->last = NULL;
2729 tmp = ret->children;
2730 while (tmp != NULL) {
2731 if (tmp->next == NULL)
2732 ret->last = tmp;
2733 tmp = tmp->next;
2734 }
2735 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002736 return(ret);
2737}
2738
2739/************************************************************************
2740 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002741 * Content access functions *
2742 * *
2743 ************************************************************************/
2744
Daniel Veillard97b58771998-10-20 06:14:16 +00002745/**
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002746 * xmlDocGetRootElement:
2747 * @doc: the document
2748 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002749 * Get the root element of the document (doc->children is a list
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002750 * containing possibly comments, PIs, etc ...).
2751 *
2752 * Returns the xmlNodePtr for the root or NULL
2753 */
2754xmlNodePtr
2755xmlDocGetRootElement(xmlDocPtr doc) {
2756 xmlNodePtr ret;
2757
2758 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002759 ret = doc->children;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002760 while (ret != NULL) {
2761 if (ret->type == XML_ELEMENT_NODE)
2762 return(ret);
2763 ret = ret->next;
2764 }
2765 return(ret);
2766}
2767
2768/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002769 * xmlDocSetRootElement:
2770 * @doc: the document
2771 * @root: the new document root element
2772 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002773 * Set the root element of the document (doc->children is a list
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002774 * containing possibly comments, PIs, etc ...).
2775 *
2776 * Returns the old root element if any was found
2777 */
2778xmlNodePtr
2779xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
2780 xmlNodePtr old = NULL;
2781
2782 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002783 old = doc->children;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002784 while (old != NULL) {
2785 if (old->type == XML_ELEMENT_NODE)
2786 break;
2787 old = old->next;
2788 }
2789 if (old == NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002790 if (doc->children == NULL) {
2791 doc->children = root;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002792 doc->last = root;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002793 } else {
Daniel Veillardcf461992000-03-14 18:30:20 +00002794 xmlAddSibling(doc->children, root);
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002795 }
2796 } else {
2797 xmlReplaceNode(old, root);
2798 }
2799 return(old);
2800}
2801
2802/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002803 * xmlNodeSetLang:
2804 * @cur: the node being changed
2805 * @lang: the langage description
2806 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002807 * Set the language of a node, i.e. the values of the xml:lang
2808 * attribute.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002809 */
2810void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002811xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002812 if (cur == NULL) return;
2813 switch(cur->type) {
2814 case XML_TEXT_NODE:
2815 case XML_CDATA_SECTION_NODE:
2816 case XML_COMMENT_NODE:
2817 case XML_DOCUMENT_NODE:
2818 case XML_DOCUMENT_TYPE_NODE:
2819 case XML_DOCUMENT_FRAG_NODE:
2820 case XML_NOTATION_NODE:
2821 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002822 case XML_DTD_NODE:
2823 case XML_ELEMENT_DECL:
2824 case XML_ATTRIBUTE_DECL:
2825 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002826 case XML_PI_NODE:
2827 case XML_ENTITY_REF_NODE:
2828 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002829 case XML_NAMESPACE_DECL:
Daniel Veillard04698d92000-09-17 16:00:22 +00002830#ifdef LIBXML_SGML_ENABLED
2831 case XML_SGML_DOCUMENT_NODE:
2832#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002833 case XML_XINCLUDE_START:
2834 case XML_XINCLUDE_END:
Daniel Veillard39c7d712000-09-10 16:14:55 +00002835 return;
2836 case XML_ELEMENT_NODE:
2837 case XML_ATTRIBUTE_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002838 break;
2839 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002840 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
2841}
2842
2843/**
2844 * xmlNodeGetLang:
2845 * @cur: the node being checked
2846 *
2847 * Searches the language of a node, i.e. the values of the xml:lang
2848 * attribute or the one carried by the nearest ancestor.
2849 *
2850 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillarda819dac1999-11-24 18:04:22 +00002851 * It's up to the caller to free the memory.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002852 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00002853xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00002854xmlNodeGetLang(xmlNodePtr cur) {
Daniel Veillarda819dac1999-11-24 18:04:22 +00002855 xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002856
2857 while (cur != NULL) {
2858 lang = xmlGetProp(cur, BAD_CAST "xml:lang");
2859 if (lang != NULL)
2860 return(lang);
2861 cur = cur->parent;
2862 }
2863 return(NULL);
2864}
2865
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002866
2867/**
2868 * xmlNodeSetSpacePreserve:
2869 * @cur: the node being changed
2870 * @val: the xml:space value ("0": default, 1: "preserve")
2871 *
2872 * Set (or reset) the space preserving behaviour of a node, i.e. the
2873 * value of the xml:space attribute.
2874 */
2875void
2876xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
2877 if (cur == NULL) return;
2878 switch(cur->type) {
2879 case XML_TEXT_NODE:
2880 case XML_CDATA_SECTION_NODE:
2881 case XML_COMMENT_NODE:
2882 case XML_DOCUMENT_NODE:
2883 case XML_DOCUMENT_TYPE_NODE:
2884 case XML_DOCUMENT_FRAG_NODE:
2885 case XML_NOTATION_NODE:
2886 case XML_HTML_DOCUMENT_NODE:
2887 case XML_DTD_NODE:
2888 case XML_ELEMENT_DECL:
2889 case XML_ATTRIBUTE_DECL:
2890 case XML_ENTITY_DECL:
2891 case XML_PI_NODE:
2892 case XML_ENTITY_REF_NODE:
2893 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002894 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002895 case XML_XINCLUDE_START:
2896 case XML_XINCLUDE_END:
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002897#ifdef LIBXML_SGML_ENABLED
2898 case XML_SGML_DOCUMENT_NODE:
2899#endif
2900 return;
2901 case XML_ELEMENT_NODE:
2902 case XML_ATTRIBUTE_NODE:
2903 break;
2904 }
2905 switch (val) {
2906 case 0:
2907 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
2908 break;
2909 case 1:
2910 xmlSetProp(cur, BAD_CAST "xml:space",
2911 BAD_CAST "preserve");
2912 break;
2913 }
2914}
2915
Daniel Veillardb96e6431999-08-29 21:02:19 +00002916/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002917 * xmlNodeGetSpacePreserve:
2918 * @cur: the node being checked
2919 *
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002920 * Searches the space preserving behaviour of a node, i.e. the values
2921 * of the xml:space attribute or the one carried by the nearest
2922 * ancestor.
Daniel Veillardcf461992000-03-14 18:30:20 +00002923 *
2924 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
2925 */
2926int
2927xmlNodeGetSpacePreserve(xmlNodePtr cur) {
2928 xmlChar *space;
2929
2930 while (cur != NULL) {
2931 space = xmlGetProp(cur, BAD_CAST "xml:space");
2932 if (space != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002933 if (xmlStrEqual(space, BAD_CAST "preserve")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002934 xmlFree(space);
2935 return(1);
2936 }
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002937 if (xmlStrEqual(space, BAD_CAST "default")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002938 xmlFree(space);
2939 return(0);
2940 }
2941 xmlFree(space);
2942 }
2943 cur = cur->parent;
2944 }
2945 return(-1);
2946}
2947
2948/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002949 * xmlNodeSetName:
2950 * @cur: the node being changed
2951 * @name: the new tag name
2952 *
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002953 * Set (or reset) the name of a node.
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002954 */
2955void
2956xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
2957 if (cur == NULL) return;
2958 if (name == NULL) return;
2959 switch(cur->type) {
2960 case XML_TEXT_NODE:
2961 case XML_CDATA_SECTION_NODE:
2962 case XML_COMMENT_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002963 case XML_DOCUMENT_TYPE_NODE:
2964 case XML_DOCUMENT_FRAG_NODE:
2965 case XML_NOTATION_NODE:
2966 case XML_HTML_DOCUMENT_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002967 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002968 case XML_XINCLUDE_START:
2969 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00002970#ifdef LIBXML_SGML_ENABLED
2971 case XML_SGML_DOCUMENT_NODE:
2972#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002973 return;
2974 case XML_ELEMENT_NODE:
2975 case XML_ATTRIBUTE_NODE:
2976 case XML_PI_NODE:
2977 case XML_ENTITY_REF_NODE:
2978 case XML_ENTITY_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002979 case XML_DTD_NODE:
2980 case XML_DOCUMENT_NODE:
2981 case XML_ELEMENT_DECL:
2982 case XML_ATTRIBUTE_DECL:
2983 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002984 break;
2985 }
2986 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
2987 cur->name = xmlStrdup(name);
2988}
2989
2990/**
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002991 * xmlNodeSetBase:
2992 * @cur: the node being changed
2993 * @uri: the new base URI
2994 *
2995 * Set (or reset) the base URI of a node, i.e. the value of the
2996 * xml:base attribute.
2997 */
2998void
2999xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3000 if (cur == NULL) return;
3001 switch(cur->type) {
3002 case XML_TEXT_NODE:
3003 case XML_CDATA_SECTION_NODE:
3004 case XML_COMMENT_NODE:
3005 case XML_DOCUMENT_NODE:
3006 case XML_DOCUMENT_TYPE_NODE:
3007 case XML_DOCUMENT_FRAG_NODE:
3008 case XML_NOTATION_NODE:
3009 case XML_HTML_DOCUMENT_NODE:
3010 case XML_DTD_NODE:
3011 case XML_ELEMENT_DECL:
3012 case XML_ATTRIBUTE_DECL:
3013 case XML_ENTITY_DECL:
3014 case XML_PI_NODE:
3015 case XML_ENTITY_REF_NODE:
3016 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003017 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003018 case XML_XINCLUDE_START:
3019 case XML_XINCLUDE_END:
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00003020#ifdef LIBXML_SGML_ENABLED
3021 case XML_SGML_DOCUMENT_NODE:
3022#endif
3023 return;
3024 case XML_ELEMENT_NODE:
3025 case XML_ATTRIBUTE_NODE:
3026 break;
3027 }
3028 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3029}
3030
3031/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003032 * xmlDocumentGetBase:
3033 * @doc: the document
3034 *
3035 * Searches for the Document BASE URL. The code should work on both XML
3036 * and HTML document.
3037 * It returns the base as defined in RFC 2396 section
3038 * 5.1.3. Base URI from the Retrieval URI
3039 * However it does not return the computed base (5.1.1 and 5.1.2), use
3040 * xmlNodeGetBase() for this
3041 *
3042 * Returns a pointer to the base URL, or NULL if not found
3043 * It's up to the caller to free the memory.
3044 */
3045xmlChar *
3046xmlDocumentGetBase(xmlDocPtr doc) {
3047 if (doc == NULL)
3048 return(NULL);
3049 if (doc->type == XML_HTML_DOCUMENT_NODE) {
3050 if (doc->URL != NULL)
3051 return(xmlStrdup(doc->URL));
3052 return(NULL);
3053 }
3054 if (doc->URL != NULL)
3055 return(xmlStrdup(doc->URL));
3056 return(NULL);
3057}
3058
3059/**
Daniel Veillard10a2c651999-12-12 13:03:50 +00003060 * xmlNodeGetBase:
3061 * @doc: the document the node pertains to
3062 * @cur: the node being checked
3063 *
3064 * Searches for the BASE URL. The code should work on both XML
3065 * and HTML document even if base mechanisms are completely different.
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003066 * It returns the base as defined in RFC 2396 sections
3067 * 5.1.1. Base URI within Document Content
3068 * and
3069 * 5.1.2. Base URI from the Encapsulating Entity
3070 * However it does not return the document base (5.1.3), use
3071 * xmlDocumentGetBase() for this
Daniel Veillard10a2c651999-12-12 13:03:50 +00003072 *
3073 * Returns a pointer to the base URL, or NULL if not found
3074 * It's up to the caller to free the memory.
3075 */
3076xmlChar *
3077xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
3078 xmlChar *base;
3079
3080 if ((cur == NULL) && (doc == NULL))
3081 return(NULL);
3082 if (doc == NULL) doc = cur->doc;
3083 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003084 cur = doc->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003085 while ((cur != NULL) && (cur->name != NULL)) {
3086 if (cur->type != XML_ELEMENT_NODE) {
3087 cur = cur->next;
3088 continue;
3089 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003090 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003091 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003092 continue;
3093 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003094 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003095 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003096 continue;
3097 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003098 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3099 return(xmlGetProp(cur, BAD_CAST "href"));
Daniel Veillard10a2c651999-12-12 13:03:50 +00003100 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003101 cur = cur->next;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003102 }
3103 return(NULL);
3104 }
3105 while (cur != NULL) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003106 if (cur->type == XML_ENTITY_DECL) {
3107 xmlEntityPtr ent = (xmlEntityPtr) cur;
3108 return(xmlStrdup(ent->URI));
3109 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003110 base = xmlGetProp(cur, BAD_CAST "xml:base");
3111 if (base != NULL)
3112 return(base);
3113 cur = cur->parent;
3114 }
3115 return(NULL);
3116}
3117
3118/**
Daniel Veillard16253641998-10-28 22:58:05 +00003119 * xmlNodeGetContent:
3120 * @cur: the node being read
3121 *
3122 * Read the value of a node, this can be either the text carried
3123 * directly by this node if it's a TEXT node or the aggregate string
3124 * of the values carried by this node child's (TEXT and ENTITY_REF).
3125 * Entity references are substitued.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003126 * Returns a new xmlChar * or NULL if no content is available.
Daniel Veillard5099ae81999-04-21 20:12:07 +00003127 * It's up to the caller to free the memory.
Daniel Veillard16253641998-10-28 22:58:05 +00003128 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003129xmlChar *
Daniel Veillard16253641998-10-28 22:58:05 +00003130xmlNodeGetContent(xmlNodePtr cur) {
3131 if (cur == NULL) return(NULL);
3132 switch (cur->type) {
3133 case XML_DOCUMENT_FRAG_NODE:
3134 case XML_ELEMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003135 return(xmlNodeListGetString(cur->doc, cur->children, 1));
Daniel Veillard16253641998-10-28 22:58:05 +00003136 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003137 case XML_ATTRIBUTE_NODE: {
3138 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00003139 if (attr->parent != NULL)
3140 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003141 else
Daniel Veillardcf461992000-03-14 18:30:20 +00003142 return(xmlNodeListGetString(NULL, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003143 break;
3144 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003145 case XML_COMMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003146 case XML_PI_NODE:
3147 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003148#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00003149 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003150#else
3151 return(xmlStrdup(xmlBufferContent(cur->content)));
3152#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00003153 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00003154 case XML_ENTITY_REF_NODE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003155 /*
3156 * Locate the entity, and get it's content
3157 * @@@
3158 */
3159 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00003160 case XML_ENTITY_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003161 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003162 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003163 case XML_DOCUMENT_TYPE_NODE:
3164 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003165 case XML_DTD_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003166 case XML_XINCLUDE_START:
3167 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003168#ifdef LIBXML_SGML_ENABLED
3169 case XML_SGML_DOCUMENT_NODE:
3170#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00003171 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00003172 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003173 return(xmlStrdup(((xmlNsPtr)cur)->href));
Daniel Veillardcf461992000-03-14 18:30:20 +00003174 case XML_ELEMENT_DECL:
3175 /* TODO !!! */
3176 return(NULL);
3177 case XML_ATTRIBUTE_DECL:
3178 /* TODO !!! */
3179 return(NULL);
3180 case XML_ENTITY_DECL:
3181 /* TODO !!! */
Daniel Veillard16253641998-10-28 22:58:05 +00003182 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003183 case XML_CDATA_SECTION_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003184 case XML_TEXT_NODE:
3185 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003186#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003187 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003188#else
3189 return(xmlStrdup(xmlBufferContent(cur->content)));
3190#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003191 return(NULL);
3192 }
3193 return(NULL);
3194}
3195
3196/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003197 * xmlNodeSetContent:
3198 * @cur: the node being modified
3199 * @content: the new value of the content
3200 *
3201 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003202 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003203void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003204xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003205 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003206#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003207 xmlGenericError(xmlGenericErrorContext,
3208 "xmlNodeSetContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003209#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003210 return;
3211 }
Daniel Veillard16253641998-10-28 22:58:05 +00003212 switch (cur->type) {
3213 case XML_DOCUMENT_FRAG_NODE:
3214 case XML_ELEMENT_NODE:
3215 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003216#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003217 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003218#else
3219 xmlBufferFree(cur->content);
3220#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003221 cur->content = NULL;
3222 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003223 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3224 cur->children = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003225 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00003226 break;
3227 case XML_ATTRIBUTE_NODE:
3228 break;
3229 case XML_TEXT_NODE:
3230 case XML_CDATA_SECTION_NODE:
3231 case XML_ENTITY_REF_NODE:
3232 case XML_ENTITY_NODE:
3233 case XML_PI_NODE:
3234 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003235 if (cur->content != NULL) {
3236#ifndef XML_USE_BUFFER_CONTENT
3237 xmlFree(cur->content);
3238#else
3239 xmlBufferFree(cur->content);
3240#endif
3241 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003242 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3243 cur->last = cur->children = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003244 if (content != NULL) {
3245#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003246 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003247#else
3248 cur->content = xmlBufferCreateSize(0);
3249 xmlBufferSetAllocationScheme(cur->content,
3250 xmlGetBufferAllocationScheme());
3251 xmlBufferAdd(cur->content, content, -1);
3252#endif
3253 } else
Daniel Veillard16253641998-10-28 22:58:05 +00003254 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003255 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003256 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003257 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003258 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003259 case XML_XINCLUDE_START:
3260 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003261#ifdef LIBXML_SGML_ENABLED
3262 case XML_SGML_DOCUMENT_NODE:
3263#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003264 break;
3265 case XML_NOTATION_NODE:
3266 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003267 case XML_DTD_NODE:
3268 break;
Daniel Veillarda4964b72000-10-31 18:23:44 +00003269 case XML_NAMESPACE_DECL:
3270 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003271 case XML_ELEMENT_DECL:
3272 /* TODO !!! */
3273 break;
3274 case XML_ATTRIBUTE_DECL:
3275 /* TODO !!! */
3276 break;
3277 case XML_ENTITY_DECL:
3278 /* TODO !!! */
3279 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003280 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003281}
3282
Daniel Veillard97b58771998-10-20 06:14:16 +00003283/**
3284 * xmlNodeSetContentLen:
3285 * @cur: the node being modified
3286 * @content: the new value of the content
3287 * @len: the size of @content
3288 *
3289 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003290 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003291void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003292xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003293 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003294#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003295 xmlGenericError(xmlGenericErrorContext,
3296 "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003297#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003298 return;
3299 }
Daniel Veillard16253641998-10-28 22:58:05 +00003300 switch (cur->type) {
3301 case XML_DOCUMENT_FRAG_NODE:
3302 case XML_ELEMENT_NODE:
3303 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003304#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003305 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003306#else
3307 xmlBufferFree(cur->content);
3308#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003309 cur->content = NULL;
3310 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003311 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3312 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003313 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00003314 break;
3315 case XML_ATTRIBUTE_NODE:
3316 break;
3317 case XML_TEXT_NODE:
3318 case XML_CDATA_SECTION_NODE:
3319 case XML_ENTITY_REF_NODE:
3320 case XML_ENTITY_NODE:
3321 case XML_PI_NODE:
3322 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003323 case XML_NOTATION_NODE:
3324 if (cur->content != NULL) {
3325#ifndef XML_USE_BUFFER_CONTENT
3326 xmlFree(cur->content);
3327#else
3328 xmlBufferFree(cur->content);
3329#endif
3330 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003331 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3332 cur->children = cur->last = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003333 if (content != NULL) {
3334#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003335 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003336#else
3337 cur->content = xmlBufferCreateSize(len);
3338 xmlBufferSetAllocationScheme(cur->content,
3339 xmlGetBufferAllocationScheme());
3340 xmlBufferAdd(cur->content, content, len);
3341#endif
3342 } else
Daniel Veillard16253641998-10-28 22:58:05 +00003343 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003344 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003345 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003346 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003347 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003348 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003349 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003350 case XML_XINCLUDE_START:
3351 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003352#ifdef LIBXML_SGML_ENABLED
3353 case XML_SGML_DOCUMENT_NODE:
3354#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003355 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003356 case XML_ELEMENT_DECL:
3357 /* TODO !!! */
3358 break;
3359 case XML_ATTRIBUTE_DECL:
3360 /* TODO !!! */
3361 break;
3362 case XML_ENTITY_DECL:
3363 /* TODO !!! */
3364 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003365 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003366}
3367
Daniel Veillard97b58771998-10-20 06:14:16 +00003368/**
3369 * xmlNodeAddContentLen:
3370 * @cur: the node being modified
3371 * @content: extra content
3372 * @len: the size of @content
3373 *
3374 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003375 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003376void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003377xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003378 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003379#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003380 xmlGenericError(xmlGenericErrorContext,
3381 "xmlNodeAddContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003382#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003383 return;
3384 }
3385 if (len <= 0) return;
3386 switch (cur->type) {
3387 case XML_DOCUMENT_FRAG_NODE:
3388 case XML_ELEMENT_NODE: {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003389 xmlNodePtr last = NULL, newNode;
Daniel Veillard16253641998-10-28 22:58:05 +00003390
Daniel Veillardcf461992000-03-14 18:30:20 +00003391 if (cur->children != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003392 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003393 } else {
3394 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003395#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardcf461992000-03-14 18:30:20 +00003396 cur->children = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003397#else
Daniel Veillardcf461992000-03-14 18:30:20 +00003398 cur->children = xmlStringGetNodeList(cur->doc,
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003399 xmlBufferContent(cur->content));
3400#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003401 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003402#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003403 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003404#else
3405 xmlBufferFree(cur->content);
3406#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003407 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003408 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003409 }
3410 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003411 newNode = xmlNewTextLen(content, len);
3412 if (newNode != NULL) {
3413 xmlAddChild(cur, newNode);
3414 if ((last != NULL) && (last->next == newNode)) {
3415 xmlTextMerge(last, newNode);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003416 }
Daniel Veillard16253641998-10-28 22:58:05 +00003417 }
3418 break;
3419 }
3420 case XML_ATTRIBUTE_NODE:
3421 break;
3422 case XML_TEXT_NODE:
3423 case XML_CDATA_SECTION_NODE:
3424 case XML_ENTITY_REF_NODE:
3425 case XML_ENTITY_NODE:
3426 case XML_PI_NODE:
3427 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003428 case XML_NOTATION_NODE:
3429 if (content != NULL) {
3430#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003431 cur->content = xmlStrncat(cur->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003432#else
3433 xmlBufferAdd(cur->content, content, len);
3434#endif
3435 }
Daniel Veillard16253641998-10-28 22:58:05 +00003436 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003437 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003438 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003439 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003440 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003441 case XML_XINCLUDE_START:
3442 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003443#ifdef LIBXML_SGML_ENABLED
3444 case XML_SGML_DOCUMENT_NODE:
3445#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003446 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003447 case XML_ELEMENT_DECL:
3448 case XML_ATTRIBUTE_DECL:
3449 case XML_ENTITY_DECL:
3450 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003451 }
3452}
3453
3454/**
3455 * xmlNodeAddContent:
3456 * @cur: the node being modified
3457 * @content: extra content
3458 *
3459 * Append the extra substring to the node content.
3460 */
3461void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003462xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard16253641998-10-28 22:58:05 +00003463 int len;
3464
3465 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003466#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003467 xmlGenericError(xmlGenericErrorContext,
3468 "xmlNodeAddContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003469#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003470 return;
3471 }
Daniel Veillard16253641998-10-28 22:58:05 +00003472 if (content == NULL) return;
3473 len = xmlStrlen(content);
3474 xmlNodeAddContentLen(cur, content, len);
3475}
3476
3477/**
3478 * xmlTextMerge:
3479 * @first: the first text node
3480 * @second: the second text node being merged
3481 *
3482 * Merge two text nodes into one
Daniel Veillard1e346af1999-02-22 10:33:01 +00003483 * Returns the first text node augmented
Daniel Veillard16253641998-10-28 22:58:05 +00003484 */
3485xmlNodePtr
3486xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3487 if (first == NULL) return(second);
3488 if (second == NULL) return(first);
3489 if (first->type != XML_TEXT_NODE) return(first);
3490 if (second->type != XML_TEXT_NODE) return(first);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003491#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003492 xmlNodeAddContent(first, second->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003493#else
3494 xmlNodeAddContent(first, xmlBufferContent(second->content));
3495#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003496 xmlUnlinkNode(second);
3497 xmlFreeNode(second);
3498 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003499}
3500
Daniel Veillard97b58771998-10-20 06:14:16 +00003501/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003502 * xmlGetNsList:
3503 * @doc: the document
3504 * @node: the current node
3505 *
3506 * Search all the namespace applying to a given element.
3507 * Returns an NULL terminated array of all the xmlNsPtr found
3508 * that need to be freed by the caller or NULL if no
3509 * namespace if defined
3510 */
3511xmlNsPtr *
3512xmlGetNsList(xmlDocPtr doc, xmlNodePtr node) {
3513 xmlNsPtr cur;
3514 xmlNsPtr *ret = NULL;
3515 int nbns = 0;
3516 int maxns = 10;
3517 int i;
3518
3519 while (node != NULL) {
3520 cur = node->nsDef;
3521 while (cur != NULL) {
3522 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003523 ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003524 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003525 xmlGenericError(xmlGenericErrorContext,
3526 "xmlGetNsList : out of memory!\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00003527 return(NULL);
3528 }
3529 ret[nbns] = NULL;
3530 }
3531 for (i = 0;i < nbns;i++) {
3532 if ((cur->prefix == ret[i]->prefix) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003533 (xmlStrEqual(cur->prefix, ret[i]->prefix))) break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003534 }
3535 if (i >= nbns) {
3536 if (nbns >= maxns) {
3537 maxns *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003538 ret = (xmlNsPtr *) xmlRealloc(ret,
Daniel Veillardb96e6431999-08-29 21:02:19 +00003539 (maxns + 1) * sizeof(xmlNsPtr));
3540 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003541 xmlGenericError(xmlGenericErrorContext,
3542 "xmlGetNsList : realloc failed!\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00003543 return(NULL);
3544 }
3545 }
3546 ret[nbns++] = cur;
3547 ret[nbns] = NULL;
3548 }
3549
3550 cur = cur->next;
3551 }
3552 node = node->parent;
3553 }
3554 return(ret);
3555}
3556
3557/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003558 * xmlSearchNs:
3559 * @doc: the document
3560 * @node: the current node
3561 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00003562 *
Daniel Veillard97b58771998-10-20 06:14:16 +00003563 * Search a Ns registered under a given name space for a document.
3564 * recurse on the parents until it finds the defined namespace
3565 * or return NULL otherwise.
3566 * @nameSpace can be NULL, this is a search for the default namespace.
Daniel Veillarde0854c32000-08-27 21:12:29 +00003567 * We don't allow to cross entities boundaries. If you don't declare
3568 * the namespace within those you will be in troubles !!! A warning
3569 * is generated to cover this case.
3570 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003571 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003572 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003573xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003574xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003575 xmlNsPtr cur;
3576
Daniel Veillard62ba71e1999-12-16 17:52:19 +00003577 if (node == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003578 while (node != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003579 if ((node->type == XML_ENTITY_REF_NODE) ||
3580 (node->type == XML_ENTITY_NODE) ||
3581 (node->type == XML_ENTITY_DECL))
3582 return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00003583 if (node->type == XML_ELEMENT_NODE) {
3584 cur = node->nsDef;
3585 while (cur != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003586 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3587 (cur->href != NULL))
Daniel Veillardcf461992000-03-14 18:30:20 +00003588 return(cur);
3589 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
Daniel Veillarde0854c32000-08-27 21:12:29 +00003590 (cur->href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003591 (xmlStrEqual(cur->prefix, nameSpace)))
Daniel Veillardcf461992000-03-14 18:30:20 +00003592 return(cur);
3593 cur = cur->next;
3594 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003595 }
3596 node = node->parent;
3597 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003598 return(NULL);
3599}
3600
Daniel Veillard97b58771998-10-20 06:14:16 +00003601/**
3602 * xmlSearchNsByHref:
3603 * @doc: the document
3604 * @node: the current node
3605 * @href: the namespace value
3606 *
3607 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3608 * the defined namespace or return NULL otherwise.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003609 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003610 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003611xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003612xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003613 xmlNsPtr cur;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003614 xmlNodePtr orig = node;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003615
Daniel Veillard10a2c651999-12-12 13:03:50 +00003616 if ((node == NULL) || (href == NULL)) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003617 while (node != NULL) {
3618 cur = node->nsDef;
3619 while (cur != NULL) {
3620 if ((cur->href != NULL) && (href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003621 (xmlStrEqual(cur->href, href))) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003622 /*
3623 * Check that the prefix is not shadowed between orig and node
3624 */
3625 xmlNodePtr check = orig;
3626 xmlNsPtr tst;
3627
3628 while (check != node) {
3629 tst = check->nsDef;
3630 while (tst != NULL) {
3631 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3632 goto shadowed;
3633 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003634 (xmlStrEqual(tst->prefix, cur->prefix)))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003635 goto shadowed;
3636 tst = tst->next;
3637 }
Daniel Veillardc4f4f0b2000-10-29 17:46:30 +00003638 check = check->parent;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003639 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003640 return(cur);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003641 }
3642shadowed:
Daniel Veillard260a68f1998-08-13 03:39:55 +00003643 cur = cur->next;
3644 }
3645 node = node->parent;
3646 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003647 return(NULL);
3648}
3649
3650/**
3651 * xmlNewReconciliedNs
3652 * @doc: the document
3653 * @tree: a node expected to hold the new namespace
3654 * @ns: the original namespace
3655 *
3656 * This function tries to locate a namespace definition in a tree
3657 * ancestors, or create a new namespace definition node similar to
3658 * @ns trying to reuse the same prefix. However if the given prefix is
3659 * null (default namespace) or reused within the subtree defined by
3660 * @tree or on one of its ancestors then a new prefix is generated.
3661 * Returns the (new) namespace definition or NULL in case of error
3662 */
3663xmlNsPtr
3664xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3665 xmlNsPtr def;
3666 xmlChar prefix[50];
3667 int counter = 1;
3668
3669 if (tree == NULL) {
3670#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003671 xmlGenericError(xmlGenericErrorContext,
3672 "xmlNewReconciliedNs : tree == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003673#endif
3674 return(NULL);
3675 }
3676 if (ns == NULL) {
3677#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003678 xmlGenericError(xmlGenericErrorContext,
3679 "xmlNewReconciliedNs : ns == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003680#endif
3681 return(NULL);
3682 }
3683 /*
3684 * Search an existing namespace definition inherited.
3685 */
3686 def = xmlSearchNsByHref(doc, tree, ns->href);
3687 if (def != NULL)
3688 return(def);
3689
3690 /*
3691 * Find a close prefix which is not already in use.
3692 * Let's strip namespace prefixes longer than 20 chars !
3693 */
3694 sprintf((char *) prefix, "%.20s", ns->prefix);
3695 def = xmlSearchNs(doc, tree, prefix);
3696 while (def != NULL) {
3697 if (counter > 1000) return(NULL);
3698 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
3699 def = xmlSearchNs(doc, tree, prefix);
3700 }
3701
3702 /*
3703 * Ok, now we are ready to create a new one.
3704 */
3705 def = xmlNewNs(tree, ns->href, prefix);
3706 return(def);
3707}
3708
3709/**
3710 * xmlReconciliateNs
3711 * @doc: the document
3712 * @tree: a node defining the subtree to reconciliate
3713 *
3714 * This function checks that all the namespaces declared within the given
3715 * tree are properly declared. This is needed for example after Copy or Cut
3716 * and then paste operations. The subtree may still hold pointers to
3717 * namespace declarations outside the subtree or invalid/masked. As much
3718 * as possible the function try tu reuse the existing namespaces found in
3719 * the new environment. If not possible the new namespaces are redeclared
3720 * on @tree at the top of the given subtree.
3721 * Returns the number of namespace declarations created or -1 in case of error.
3722 */
3723int
3724xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
3725 xmlNsPtr *oldNs = NULL;
3726 xmlNsPtr *newNs = NULL;
3727 int sizeCache = 0;
3728 int nbCache = 0;
3729
3730 xmlNsPtr n;
3731 xmlNodePtr node = tree;
3732 xmlAttrPtr attr;
3733 int ret = 0, i;
3734
3735 while (node != NULL) {
3736 /*
3737 * Reconciliate the node namespace
3738 */
3739 if (node->ns != NULL) {
3740 /*
3741 * initialize the cache if needed
3742 */
3743 if (sizeCache == 0) {
3744 sizeCache = 10;
3745 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3746 sizeof(xmlNsPtr));
3747 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003748 xmlGenericError(xmlGenericErrorContext,
3749 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003750 return(-1);
3751 }
3752 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3753 sizeof(xmlNsPtr));
3754 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003755 xmlGenericError(xmlGenericErrorContext,
3756 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003757 xmlFree(oldNs);
3758 return(-1);
3759 }
3760 }
3761 for (i = 0;i < nbCache;i++) {
3762 if (oldNs[i] == node->ns) {
3763 node->ns = newNs[i];
3764 break;
3765 }
3766 }
3767 if (i == nbCache) {
3768 /*
3769 * Ok we need to recreate a new namespace definition
3770 */
3771 n = xmlNewReconciliedNs(doc, tree, node->ns);
3772 if (n != NULL) { /* :-( what if else ??? */
3773 /*
3774 * check if we need to grow the cache buffers.
3775 */
3776 if (sizeCache <= nbCache) {
3777 sizeCache *= 2;
3778 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3779 sizeof(xmlNsPtr));
3780 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003781 xmlGenericError(xmlGenericErrorContext,
3782 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003783 xmlFree(newNs);
3784 return(-1);
3785 }
3786 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3787 sizeof(xmlNsPtr));
3788 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003789 xmlGenericError(xmlGenericErrorContext,
3790 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003791 xmlFree(oldNs);
3792 return(-1);
3793 }
3794 }
3795 newNs[nbCache] = n;
3796 oldNs[nbCache++] = node->ns;
3797 node->ns = n;
3798 }
3799 }
3800 }
3801 /*
3802 * now check for namespace hold by attributes on the node.
3803 */
3804 attr = node->properties;
3805 while (attr != NULL) {
3806 if (attr->ns != NULL) {
3807 /*
3808 * initialize the cache if needed
3809 */
3810 if (sizeCache == 0) {
3811 sizeCache = 10;
3812 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3813 sizeof(xmlNsPtr));
3814 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003815 xmlGenericError(xmlGenericErrorContext,
3816 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003817 return(-1);
3818 }
3819 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3820 sizeof(xmlNsPtr));
3821 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003822 xmlGenericError(xmlGenericErrorContext,
3823 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003824 xmlFree(oldNs);
3825 return(-1);
3826 }
3827 }
3828 for (i = 0;i < nbCache;i++) {
3829 if (oldNs[i] == attr->ns) {
3830 node->ns = newNs[i];
3831 break;
3832 }
3833 }
3834 if (i == nbCache) {
3835 /*
3836 * Ok we need to recreate a new namespace definition
3837 */
3838 n = xmlNewReconciliedNs(doc, tree, attr->ns);
3839 if (n != NULL) { /* :-( what if else ??? */
3840 /*
3841 * check if we need to grow the cache buffers.
3842 */
3843 if (sizeCache <= nbCache) {
3844 sizeCache *= 2;
3845 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3846 sizeof(xmlNsPtr));
3847 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003848 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003849 "xmlReconciliateNs : memory pbm\n");
3850 xmlFree(newNs);
3851 return(-1);
3852 }
3853 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3854 sizeof(xmlNsPtr));
3855 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003856 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003857 "xmlReconciliateNs : memory pbm\n");
3858 xmlFree(oldNs);
3859 return(-1);
3860 }
3861 }
3862 newNs[nbCache] = n;
3863 oldNs[nbCache++] = attr->ns;
3864 attr->ns = n;
3865 }
3866 }
3867 }
3868 attr = attr->next;
3869 }
3870
3871 /*
3872 * Browse the full subtree, deep first
3873 */
Daniel Veillardcf461992000-03-14 18:30:20 +00003874 if (node->children != NULL) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003875 /* deep first */
Daniel Veillardcf461992000-03-14 18:30:20 +00003876 node = node->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003877 } else if ((node != tree) && (node->next != NULL)) {
3878 /* then siblings */
3879 node = node->next;
3880 } else if (node != tree) {
3881 /* go up to parents->next if needed */
3882 while (node != tree) {
3883 if (node->parent != NULL)
3884 node = node->parent;
3885 if ((node != tree) && (node->next != NULL)) {
3886 node = node->next;
3887 break;
3888 }
3889 if (node->parent == NULL) {
3890 node = NULL;
3891 break;
3892 }
3893 }
3894 /* exit condition */
3895 if (node == tree)
3896 node = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003897 }
3898 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003899 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003900}
3901
Daniel Veillard97b58771998-10-20 06:14:16 +00003902/**
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003903 * xmlHasProp:
3904 * @node: the node
3905 * @name: the attribute name
3906 *
3907 * Search an attribute associated to a node
3908 * This function also looks in DTD attribute declaration for #FIXED or
3909 * default declaration values unless DTD use has been turned off.
3910 *
3911 * Returns the attribute or the attribute declaration or NULL if
3912 * neither was found.
3913 */
3914xmlAttrPtr
3915xmlHasProp(xmlNodePtr node, const xmlChar *name) {
3916 xmlAttrPtr prop;
3917 xmlDocPtr doc;
3918
3919 if ((node == NULL) || (name == NULL)) return(NULL);
3920 /*
3921 * Check on the properties attached to the node
3922 */
3923 prop = node->properties;
3924 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003925 if (xmlStrEqual(prop->name, name)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003926 return(prop);
3927 }
3928 prop = prop->next;
3929 }
3930 if (!xmlCheckDTD) return(NULL);
3931
3932 /*
3933 * Check if there is a default declaration in the internal
3934 * or external subsets
3935 */
3936 doc = node->doc;
3937 if (doc != NULL) {
3938 xmlAttributePtr attrDecl;
3939 if (doc->intSubset != NULL) {
3940 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3941 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3942 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
3943 if (attrDecl != NULL)
3944 return((xmlAttrPtr) attrDecl);
3945 }
3946 }
3947 return(NULL);
3948}
3949
3950/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003951 * xmlGetProp:
3952 * @node: the node
3953 * @name: the attribute name
3954 *
3955 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00003956 * This does the entity substitution.
Daniel Veillard10a2c651999-12-12 13:03:50 +00003957 * This function looks in DTD attribute declaration for #FIXED or
3958 * default declaration values unless DTD use has been turned off.
3959 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003960 * Returns the attribute value or NULL if not found.
Daniel Veillarda819dac1999-11-24 18:04:22 +00003961 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003962 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003963xmlChar *
3964xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003965 xmlAttrPtr prop;
3966 xmlDocPtr doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003967
Daniel Veillard10a2c651999-12-12 13:03:50 +00003968 if ((node == NULL) || (name == NULL)) return(NULL);
3969 /*
3970 * Check on the properties attached to the node
3971 */
3972 prop = node->properties;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003973 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003974 if (xmlStrEqual(prop->name, name)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003975 xmlChar *ret;
Daniel Veillard6800ef31999-02-08 18:33:22 +00003976
Daniel Veillardcf461992000-03-14 18:30:20 +00003977 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003978 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
Daniel Veillard6800ef31999-02-08 18:33:22 +00003979 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00003980 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003981 prop = prop->next;
3982 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003983 if (!xmlCheckDTD) return(NULL);
3984
3985 /*
3986 * Check if there is a default declaration in the internal
3987 * or external subsets
3988 */
3989 doc = node->doc;
3990 if (doc != NULL) {
3991 xmlAttributePtr attrDecl;
3992 if (doc->intSubset != NULL) {
3993 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3994 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3995 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillardf967b902000-01-17 16:06:10 +00003996 if (attrDecl != NULL)
3997 return(xmlStrdup(attrDecl->defaultValue));
Daniel Veillard10a2c651999-12-12 13:03:50 +00003998 }
3999 }
4000 return(NULL);
4001}
4002
4003/**
4004 * xmlGetNsProp:
4005 * @node: the node
4006 * @name: the attribute name
4007 * @namespace: the URI of the namespace
4008 *
4009 * Search and get the value of an attribute associated to a node
4010 * This attribute has to be anchored in the namespace specified.
4011 * This does the entity substitution.
4012 * This function looks in DTD attribute declaration for #FIXED or
4013 * default declaration values unless DTD use has been turned off.
4014 *
4015 * Returns the attribute value or NULL if not found.
4016 * It's up to the caller to free the memory.
4017 */
4018xmlChar *
4019xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
4020 xmlAttrPtr prop = node->properties;
4021 xmlDocPtr doc;
4022 xmlNsPtr ns;
4023
4024 if (namespace == NULL)
4025 return(xmlGetProp(node, name));
4026 while (prop != NULL) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00004027 /*
4028 * One need to have
4029 * - same attribute names
4030 * - and the attribute carrying that namespace
4031 * or
4032 * no namespace on the attribute and the element carrying it
4033 */
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004034 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00004035 (((prop->ns == NULL) && (node->ns != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004036 (xmlStrEqual(node->ns->href, namespace))) ||
4037 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, namespace))))) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00004038 xmlChar *ret;
4039
Daniel Veillardcf461992000-03-14 18:30:20 +00004040 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillard10a2c651999-12-12 13:03:50 +00004041 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4042 return(ret);
4043 }
4044 prop = prop->next;
4045 }
4046 if (!xmlCheckDTD) return(NULL);
4047
4048 /*
4049 * Check if there is a default declaration in the internal
4050 * or external subsets
4051 */
4052 doc = node->doc;
4053 if (doc != NULL) {
4054 xmlAttributePtr attrDecl;
4055 if (doc->intSubset != NULL) {
4056 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4057 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4058 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4059
4060 if (attrDecl->prefix != NULL) {
4061 /*
4062 * The DTD declaration only allows a prefix search
4063 */
4064 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004065 if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
Daniel Veillard10a2c651999-12-12 13:03:50 +00004066 return(xmlStrdup(attrDecl->defaultValue));
4067 }
4068 }
4069 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004070 return(NULL);
4071}
4072
Daniel Veillard97b58771998-10-20 06:14:16 +00004073/**
Daniel Veillardccb09631998-10-27 06:21:04 +00004074 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00004075 * @node: the node
4076 * @name: the attribute name
4077 * @value: the attribute value
4078 *
4079 * Set (or reset) an attribute carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00004080 * Returns the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004081 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004082xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004083xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004084 xmlAttrPtr prop = node->properties;
4085
4086 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004087 if (xmlStrEqual(prop->name, name)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00004088 if (prop->children != NULL)
4089 xmlFreeNodeList(prop->children);
4090 prop->children = NULL;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004091 prop->last = NULL;
Daniel Veillard51e3b151999-11-12 17:02:31 +00004092 if (value != NULL) {
4093 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +00004094 xmlNodePtr tmp;
4095
Daniel Veillard51e3b151999-11-12 17:02:31 +00004096 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +00004097 prop->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004098 prop->last = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00004099 tmp = prop->children;
4100 while (tmp != NULL) {
4101 tmp->parent = (xmlNodePtr) prop;
4102 if (tmp->next == NULL)
4103 prop->last = tmp;
4104 tmp = tmp->next;
4105 }
Daniel Veillard51e3b151999-11-12 17:02:31 +00004106 xmlFree(buffer);
4107 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004108 return(prop);
4109 }
4110 prop = prop->next;
4111 }
4112 prop = xmlNewProp(node, name, value);
4113 return(prop);
4114}
4115
Daniel Veillard97b58771998-10-20 06:14:16 +00004116/**
4117 * xmlNodeIsText:
4118 * @node: the node
4119 *
4120 * Is this node a Text node ?
Daniel Veillard1e346af1999-02-22 10:33:01 +00004121 * Returns 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00004122 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004123int
4124xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004125 if (node == NULL) return(0);
4126
Daniel Veillard0bef1311998-10-14 02:36:47 +00004127 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004128 return(0);
4129}
4130
Daniel Veillard97b58771998-10-20 06:14:16 +00004131/**
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004132 * xmlIsBlankNode:
4133 * @node: the node
4134 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004135 * Checks whether this node is an empty or whitespace only
4136 * (and possibly ignorable) text-node.
4137 *
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004138 * Returns 1 yes, 0 no
4139 */
4140int
4141xmlIsBlankNode(xmlNodePtr node) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004142 const xmlChar *cur;
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004143 if (node == NULL) return(0);
4144
4145 if (node->type != XML_TEXT_NODE) return(0);
Daniel Veillardcd429612000-10-11 15:57:05 +00004146 if (node->content == NULL) return(1);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004147#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004148 cur = node->content;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004149#else
4150 cur = xmlBufferContent(node->content);
4151#endif
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004152 while (*cur != 0) {
4153 if (!IS_BLANK(*cur)) return(0);
4154 cur++;
4155 }
4156
4157 return(1);
4158}
4159
4160/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00004161 * xmlTextConcat:
Daniel Veillard97b58771998-10-20 06:14:16 +00004162 * @node: the node
4163 * @content: the content
4164 * @len: @content lenght
4165 *
4166 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00004167 */
Daniel Veillard97b58771998-10-20 06:14:16 +00004168
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004169void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004170xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004171 if (node == NULL) return;
4172
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004173 if ((node->type != XML_TEXT_NODE) &&
4174 (node->type != XML_CDATA_SECTION_NODE)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004175#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004176 xmlGenericError(xmlGenericErrorContext,
4177 "xmlTextConcat: node is not text nor cdata\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004178#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004179 return;
4180 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004181#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00004182 node->content = xmlStrncat(node->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004183#else
4184 xmlBufferAdd(node->content, content, len);
4185#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004186}
4187
4188/************************************************************************
4189 * *
4190 * Output : to a FILE or in memory *
4191 * *
4192 ************************************************************************/
4193
Daniel Veillard5099ae81999-04-21 20:12:07 +00004194#define BASE_BUFFER_SIZE 4000
4195
4196/**
4197 * xmlBufferCreate:
4198 *
4199 * routine to create an XML buffer.
4200 * returns the new structure.
4201 */
4202xmlBufferPtr
4203xmlBufferCreate(void) {
4204 xmlBufferPtr ret;
4205
Daniel Veillard6454aec1999-09-02 22:04:43 +00004206 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
Daniel Veillard5099ae81999-04-21 20:12:07 +00004207 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004208 xmlGenericError(xmlGenericErrorContext,
4209 "xmlBufferCreate : out of memory!\n");
Daniel Veillard5099ae81999-04-21 20:12:07 +00004210 return(NULL);
4211 }
4212 ret->use = 0;
4213 ret->size = BASE_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004214 ret->alloc = xmlBufferAllocScheme;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004215 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
Daniel Veillard5099ae81999-04-21 20:12:07 +00004216 if (ret->content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004217 xmlGenericError(xmlGenericErrorContext,
4218 "xmlBufferCreate : out of memory!\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00004219 xmlFree(ret);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004220 return(NULL);
4221 }
4222 ret->content[0] = 0;
4223 return(ret);
4224}
4225
4226/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004227 * xmlBufferCreateSize:
4228 * @size: initial size of buffer
4229 *
4230 * routine to create an XML buffer.
4231 * returns the new structure.
4232 */
4233xmlBufferPtr
4234xmlBufferCreateSize(size_t size) {
4235 xmlBufferPtr ret;
4236
4237 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4238 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004239 xmlGenericError(xmlGenericErrorContext,
4240 "xmlBufferCreate : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004241 return(NULL);
4242 }
4243 ret->use = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004244 ret->alloc = xmlBufferAllocScheme;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004245 ret->size = (size ? size+2 : 0); /* +1 for ending null */
Daniel Veillard10a2c651999-12-12 13:03:50 +00004246 if (ret->size){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004247 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4248 if (ret->content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004249 xmlGenericError(xmlGenericErrorContext,
4250 "xmlBufferCreate : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004251 xmlFree(ret);
4252 return(NULL);
4253 }
4254 ret->content[0] = 0;
4255 } else
4256 ret->content = NULL;
4257 return(ret);
4258}
4259
4260/**
Daniel Veillard06047432000-04-24 11:33:38 +00004261 * xmlBufferSetAllocationScheme:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004262 * @buf: the buffer to free
4263 * @scheme: allocation scheme to use
4264 *
4265 * Sets the allocation scheme for this buffer
4266 */
4267void
4268xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4269 xmlBufferAllocationScheme scheme) {
4270 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004271#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004272 xmlGenericError(xmlGenericErrorContext,
4273 "xmlBufferSetAllocationScheme: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004274#endif
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004275 return;
4276 }
4277
4278 buf->alloc = scheme;
4279}
4280
4281/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004282 * xmlBufferFree:
4283 * @buf: the buffer to free
4284 *
4285 * Frees an XML buffer.
4286 */
4287void
4288xmlBufferFree(xmlBufferPtr buf) {
4289 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004290#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004291 xmlGenericError(xmlGenericErrorContext,
4292 "xmlBufferFree: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004293#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004294 return;
4295 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004296 if (buf->content != NULL) {
4297#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00004298 memset(buf->content, -1, BASE_BUFFER_SIZE);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004299#else
4300 memset(buf->content, -1, buf->size);
4301#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004302 xmlFree(buf->content);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004303 }
4304 memset(buf, -1, sizeof(xmlBuffer));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004305 xmlFree(buf);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004306}
4307
4308/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004309 * xmlBufferEmpty:
4310 * @buf: the buffer
4311 *
4312 * empty a buffer.
4313 */
4314void
4315xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +00004316 if (buf->content == NULL) return;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004317 buf->use = 0;
4318 memset(buf->content, -1, buf->size);/* just for debug */
4319}
4320
4321/**
4322 * xmlBufferShrink:
4323 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004324 * @len: the number of xmlChar to remove
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004325 *
4326 * Remove the beginning of an XML buffer.
4327 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004328 * Returns the number of xmlChar removed, or -1 in case of failure.
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004329 */
4330int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004331xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004332 if (len == 0) return(0);
4333 if (len > buf->use) return(-1);
4334
4335 buf->use -= len;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004336 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004337
4338 buf->content[buf->use] = 0;
4339 return(len);
4340}
4341
4342/**
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004343 * xmlBufferGrow:
4344 * @buf: the buffer
4345 * @len: the minimum free sie to allocate
4346 *
4347 * Grow the available space of an XML buffer.
4348 *
4349 * Returns the new available space or -1 in case of error
4350 */
4351int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004352xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004353 int size;
4354 xmlChar *newbuf;
4355
4356 if (len <= buf->use) return(0);
4357
Daniel Veillardbe803962000-06-28 23:40:59 +00004358 size = buf->use + len + 100;
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004359
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004360 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004361 if (newbuf == NULL) return(-1);
4362 buf->content = newbuf;
4363 buf->size = size;
4364 return(buf->size - buf->use);
4365}
4366
4367/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004368 * xmlBufferDump:
4369 * @file: the file output
4370 * @buf: the buffer to dump
4371 *
4372 * Dumps an XML buffer to a FILE *.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004373 * Returns the number of xmlChar written
Daniel Veillard5099ae81999-04-21 20:12:07 +00004374 */
4375int
4376xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4377 int ret;
4378
4379 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004380#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004381 xmlGenericError(xmlGenericErrorContext,
4382 "xmlBufferDump: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004383#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004384 return(0);
4385 }
4386 if (buf->content == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004387#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004388 xmlGenericError(xmlGenericErrorContext,
4389 "xmlBufferDump: buf->content == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004390#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004391 return(0);
4392 }
4393 if (file == NULL) file = stdout;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004394 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004395 return(ret);
4396}
4397
4398/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004399 * xmlBufferContent:
4400 * @buf: the buffer to resize
4401 *
4402 * Returns the internal content
4403 */
4404
4405const xmlChar*
4406xmlBufferContent(const xmlBufferPtr buf)
4407{
4408 if(!buf)
4409 return NULL;
4410
4411 return buf->content;
4412}
4413
4414/**
4415 * xmlBufferLength:
4416 * @buf: the buffer
4417 *
4418 * Returns the length of data in the internal content
4419 */
4420
4421int
4422xmlBufferLength(const xmlBufferPtr buf)
4423{
4424 if(!buf)
4425 return 0;
4426
4427 return buf->use;
4428}
4429
4430/**
4431 * xmlBufferResize:
4432 * @buf: the buffer to resize
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004433 * @size: the desired size
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004434 *
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004435 * Resize a buffer to accomodate minimum size of @size.
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004436 *
4437 * Returns 0 in case of problems, 1 otherwise
4438 */
4439int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004440xmlBufferResize(xmlBufferPtr buf, unsigned int size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004441{
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004442 unsigned int newSize;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004443 xmlChar* rebuf = NULL;
4444
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004445 /*take care of empty case*/
4446 newSize = (buf->size ? buf->size*2 : size);
4447
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004448 /* Don't resize if we don't have to */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004449 if (size < buf->size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004450 return 1;
4451
4452 /* figure out new size */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004453 switch (buf->alloc){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004454 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004455 while (size > newSize) newSize *= 2;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004456 break;
4457 case XML_BUFFER_ALLOC_EXACT:
4458 newSize = size+10;
4459 break;
4460 default:
4461 newSize = size+10;
4462 break;
4463 }
4464
4465 if (buf->content == NULL)
4466 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
4467 else
4468 rebuf = (xmlChar *) xmlRealloc(buf->content,
4469 newSize * sizeof(xmlChar));
4470 if (rebuf == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004471 xmlGenericError(xmlGenericErrorContext,
4472 "xmlBufferAdd : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004473 return 0;
4474 }
4475 buf->content = rebuf;
4476 buf->size = newSize;
4477
4478 return 1;
4479}
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004480
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004481/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004482 * xmlBufferAdd:
4483 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004484 * @str: the xmlChar string
4485 * @len: the number of xmlChar to add
Daniel Veillard5099ae81999-04-21 20:12:07 +00004486 *
Daniel Veillard10a2c651999-12-12 13:03:50 +00004487 * Add a string range to an XML buffer. if len == -1, the lenght of
4488 * str is recomputed.
Daniel Veillard5099ae81999-04-21 20:12:07 +00004489 */
4490void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004491xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004492 unsigned int needSize;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004493
4494 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004495#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004496 xmlGenericError(xmlGenericErrorContext,
4497 "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004498#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004499 return;
4500 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00004501 if (len < -1) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004502#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004503 xmlGenericError(xmlGenericErrorContext,
4504 "xmlBufferAdd: len < 0\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004505#endif
Daniel Veillard10a2c651999-12-12 13:03:50 +00004506 return;
4507 }
4508 if (len == 0) return;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004509
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004510 if (len < 0)
Daniel Veillardcf461992000-03-14 18:30:20 +00004511 len = xmlStrlen(str);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004512
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004513 if (len <= 0) return;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004514
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004515 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004516 if (needSize > buf->size){
4517 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004518 xmlGenericError(xmlGenericErrorContext,
4519 "xmlBufferAdd : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004520 return;
4521 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004522 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004523
4524 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004525 buf->use += len;
4526 buf->content[buf->use] = 0;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004527}
4528
4529/**
Daniel Veillardbe803962000-06-28 23:40:59 +00004530 * xmlBufferAddHead:
4531 * @buf: the buffer
4532 * @str: the xmlChar string
4533 * @len: the number of xmlChar to add
4534 *
4535 * Add a string range to the beginning of an XML buffer.
4536 * if len == -1, the lenght of @str is recomputed.
4537 */
4538void
4539xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004540 unsigned int needSize;
Daniel Veillardbe803962000-06-28 23:40:59 +00004541
4542 if (str == NULL) {
4543#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004544 xmlGenericError(xmlGenericErrorContext,
4545 "xmlBufferAdd: str == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004546#endif
4547 return;
4548 }
4549 if (len < -1) {
4550#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004551 xmlGenericError(xmlGenericErrorContext,
4552 "xmlBufferAdd: len < 0\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004553#endif
4554 return;
4555 }
4556 if (len == 0) return;
4557
4558 if (len < 0)
4559 len = xmlStrlen(str);
4560
4561 if (len <= 0) return;
4562
4563 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004564 if (needSize > buf->size){
4565 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004566 xmlGenericError(xmlGenericErrorContext,
4567 "xmlBufferAddHead : out of memory!\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004568 return;
4569 }
4570 }
4571
4572 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
4573 memmove(&buf->content[0], str, len * sizeof(xmlChar));
4574 buf->use += len;
4575 buf->content[buf->use] = 0;
4576}
4577
4578/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004579 * xmlBufferCat:
4580 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004581 * @str: the xmlChar string
Daniel Veillard5099ae81999-04-21 20:12:07 +00004582 *
4583 * Append a zero terminated string to an XML buffer.
4584 */
4585void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004586xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004587 if (str != NULL)
4588 xmlBufferAdd(buf, str, -1);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004589}
4590
4591/**
4592 * xmlBufferCCat:
4593 * @buf: the buffer to dump
4594 * @str: the C char string
4595 *
4596 * Append a zero terminated C string to an XML buffer.
4597 */
4598void
4599xmlBufferCCat(xmlBufferPtr buf, const char *str) {
4600 const char *cur;
4601
4602 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004603#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004604 xmlGenericError(xmlGenericErrorContext,
4605 "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004606#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004607 return;
4608 }
4609 for (cur = str;*cur != 0;cur++) {
4610 if (buf->use + 10 >= buf->size) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004611 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004612 xmlGenericError(xmlGenericErrorContext,
4613 "xmlBufferCCat : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004614 return;
4615 }
4616 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004617 buf->content[buf->use++] = *cur;
4618 }
4619}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004620
Daniel Veillard97b58771998-10-20 06:14:16 +00004621/**
4622 * xmlBufferWriteCHAR:
Daniel Veillard5099ae81999-04-21 20:12:07 +00004623 * @buf: the XML buffer
Daniel Veillard97b58771998-10-20 06:14:16 +00004624 * @string: the string to add
4625 *
4626 * routine which manage and grows an output buffer. This one add
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004627 * xmlChars at the end of the buffer.
Daniel Veillard97b58771998-10-20 06:14:16 +00004628 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004629void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004630xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004631 xmlBufferCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004632}
4633
Daniel Veillard97b58771998-10-20 06:14:16 +00004634/**
4635 * xmlBufferWriteChar:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004636 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004637 * @string: the string to add
4638 *
4639 * routine which manage and grows an output buffer. This one add
4640 * C chars at the end of the array.
4641 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004642void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004643xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
4644 xmlBufferCCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004645}
4646
Daniel Veillard5099ae81999-04-21 20:12:07 +00004647
Daniel Veillard97b58771998-10-20 06:14:16 +00004648/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004649 * xmlBufferWriteQuotedString:
4650 * @buf: the XML buffer output
4651 * @string: the string to add
4652 *
4653 * routine which manage and grows an output buffer. This one writes
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004654 * a quoted or double quoted xmlChar string, checking first if it holds
Daniel Veillard011b63c1999-06-02 17:44:04 +00004655 * quote or double-quotes internally
4656 */
4657void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004658xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004659 if (xmlStrchr(string, '"')) {
4660 if (xmlStrchr(string, '\'')) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004661#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004662 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard011b63c1999-06-02 17:44:04 +00004663 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004664#endif
Daniel Veillard011b63c1999-06-02 17:44:04 +00004665 }
4666 xmlBufferCCat(buf, "'");
4667 xmlBufferCat(buf, string);
4668 xmlBufferCCat(buf, "'");
4669 } else {
4670 xmlBufferCCat(buf, "\"");
4671 xmlBufferCat(buf, string);
4672 xmlBufferCCat(buf, "\"");
4673 }
4674}
4675
4676
Daniel Veillardbe803962000-06-28 23:40:59 +00004677/************************************************************************
4678 * *
4679 * Dumping XML tree content to a simple buffer *
4680 * *
4681 ************************************************************************/
4682
Daniel Veillardb656ebe2000-09-22 13:51:48 +00004683void
Daniel Veillardcf461992000-03-14 18:30:20 +00004684xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4685 int format);
4686static void
4687xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4688 int format);
4689void
4690htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
4691
Daniel Veillard011b63c1999-06-02 17:44:04 +00004692/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004693 * xmlNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004694 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004695 * @cur: a namespace
4696 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004697 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00004698 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004699 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004700static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004701xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004702 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004703#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004704 xmlGenericError(xmlGenericErrorContext,
4705 "xmlNsDump : Ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004706#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004707 return;
4708 }
4709 if (cur->type == XML_LOCAL_NAMESPACE) {
4710 /* Within the context of an element attributes */
4711 if (cur->prefix != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004712 xmlBufferWriteChar(buf, " xmlns:");
4713 xmlBufferWriteCHAR(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004714 } else
Daniel Veillard5099ae81999-04-21 20:12:07 +00004715 xmlBufferWriteChar(buf, " xmlns");
Daniel Veillard011b63c1999-06-02 17:44:04 +00004716 xmlBufferWriteChar(buf, "=");
4717 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004718 }
4719}
4720
Daniel Veillard97b58771998-10-20 06:14:16 +00004721/**
4722 * xmlNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004723 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004724 * @cur: the first namespace
4725 *
4726 * Dump a list of local Namespace definitions.
4727 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004728 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004729static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004730xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004731 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004732 xmlNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004733 cur = cur->next;
4734 }
4735}
4736
Daniel Veillard97b58771998-10-20 06:14:16 +00004737/**
4738 * xmlDtdDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004739 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004740 * @doc: the document
4741 *
4742 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004743 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004744static void
Daniel Veillardcf461992000-03-14 18:30:20 +00004745xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
4746 if (dtd == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004747#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004748 xmlGenericError(xmlGenericErrorContext,
4749 "xmlDtdDump : no internal subset\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004750#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004751 return;
4752 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004753 xmlBufferWriteChar(buf, "<!DOCTYPE ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004754 xmlBufferWriteCHAR(buf, dtd->name);
4755 if (dtd->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004756 xmlBufferWriteChar(buf, " PUBLIC ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004757 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004758 xmlBufferWriteChar(buf, " ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004759 xmlBufferWriteQuotedString(buf, dtd->SystemID);
4760 } else if (dtd->SystemID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004761 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004762 xmlBufferWriteQuotedString(buf, dtd->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004763 }
Daniel Veillardcf461992000-03-14 18:30:20 +00004764 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
4765 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
4766 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004767 return;
4768 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004769 xmlBufferWriteChar(buf, " [\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00004770 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
4771#if 0
4772 if (dtd->entities != NULL)
4773 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
4774 if (dtd->notations != NULL)
4775 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
4776 if (dtd->elements != NULL)
4777 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
4778 if (dtd->attributes != NULL)
4779 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
4780#endif
4781 xmlBufferWriteChar(buf, "]>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004782}
4783
Daniel Veillard97b58771998-10-20 06:14:16 +00004784/**
4785 * xmlAttrDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004786 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004787 * @doc: the document
4788 * @cur: the attribute pointer
4789 *
4790 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00004791 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004792static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004793xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004794 xmlChar *value;
Daniel Veillardccb09631998-10-27 06:21:04 +00004795
Daniel Veillard260a68f1998-08-13 03:39:55 +00004796 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004797#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004798 xmlGenericError(xmlGenericErrorContext,
4799 "xmlAttrDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004800#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004801 return;
4802 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004803 xmlBufferWriteChar(buf, " ");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004804 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4805 xmlBufferWriteCHAR(buf, cur->ns->prefix);
4806 xmlBufferWriteChar(buf, ":");
4807 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004808 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00004809 value = xmlNodeListGetString(doc, cur->children, 0);
Daniel Veillardccb09631998-10-27 06:21:04 +00004810 if (value) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004811 xmlBufferWriteChar(buf, "=");
4812 xmlBufferWriteQuotedString(buf, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004813 xmlFree(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00004814 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004815 xmlBufferWriteChar(buf, "=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004816 }
4817}
4818
Daniel Veillard97b58771998-10-20 06:14:16 +00004819/**
4820 * xmlAttrListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004821 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004822 * @doc: the document
4823 * @cur: the first attribute pointer
4824 *
4825 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00004826 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004827static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004828xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004829 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004830#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004831 xmlGenericError(xmlGenericErrorContext,
4832 "xmlAttrListDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004833#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004834 return;
4835 }
4836 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004837 xmlAttrDump(buf, doc, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004838 cur = cur->next;
4839 }
4840}
4841
Daniel Veillard260a68f1998-08-13 03:39:55 +00004842
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004843
Daniel Veillard97b58771998-10-20 06:14:16 +00004844/**
4845 * xmlNodeListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004846 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004847 * @doc: the document
4848 * @cur: the first node
Daniel Veillardcf461992000-03-14 18:30:20 +00004849 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004850 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004851 *
4852 * Dump an XML node list, recursive behaviour,children are printed too.
4853 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004854static void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004855xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4856 int format) {
4857 int i;
Daniel Veillardccb09631998-10-27 06:21:04 +00004858
Daniel Veillard260a68f1998-08-13 03:39:55 +00004859 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004860#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004861 xmlGenericError(xmlGenericErrorContext,
4862 "xmlNodeListDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004863#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004864 return;
4865 }
4866 while (cur != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004867 if ((format) && (xmlIndentTreeOutput) &&
4868 (cur->type == XML_ELEMENT_NODE))
4869 for (i = 0;i < level;i++)
4870 xmlBufferWriteChar(buf, " ");
4871 xmlNodeDump(buf, doc, cur, level, format);
4872 if (format) {
4873 xmlBufferWriteChar(buf, "\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00004874 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004875 cur = cur->next;
4876 }
4877}
4878
Daniel Veillard97b58771998-10-20 06:14:16 +00004879/**
Daniel Veillardccb09631998-10-27 06:21:04 +00004880 * xmlNodeDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004881 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004882 * @doc: the document
4883 * @cur: the current node
Daniel Veillardcf461992000-03-14 18:30:20 +00004884 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004885 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004886 *
4887 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004888 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00004889void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004890xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4891 int format) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004892 int i;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004893 xmlNodePtr tmp;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004894
4895 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004896#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004897 xmlGenericError(xmlGenericErrorContext,
4898 "xmlNodeDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004899#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004900 return;
4901 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004902 if (cur->type == XML_XINCLUDE_START)
4903 return;
4904 if (cur->type == XML_XINCLUDE_END)
4905 return;
Daniel Veillardcf461992000-03-14 18:30:20 +00004906 if (cur->type == XML_DTD_NODE) {
4907 xmlDtdDump(buf, (xmlDtdPtr) cur);
4908 return;
4909 }
4910 if (cur->type == XML_ELEMENT_DECL) {
4911 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
4912 return;
4913 }
4914 if (cur->type == XML_ATTRIBUTE_DECL) {
4915 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
4916 return;
4917 }
4918 if (cur->type == XML_ENTITY_DECL) {
4919 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
4920 return;
4921 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00004922 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard14fff061999-06-22 21:49:07 +00004923 if (cur->content != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004924 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00004925
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004926#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +00004927 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004928#else
4929 buffer = xmlEncodeEntitiesReentrant(doc,
4930 xmlBufferContent(cur->content));
4931#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00004932 if (buffer != NULL) {
4933 xmlBufferWriteCHAR(buf, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004934 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +00004935 }
4936 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004937 return;
4938 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004939 if (cur->type == XML_PI_NODE) {
4940 if (cur->content != NULL) {
4941 xmlBufferWriteChar(buf, "<?");
4942 xmlBufferWriteCHAR(buf, cur->name);
4943 if (cur->content != NULL) {
4944 xmlBufferWriteChar(buf, " ");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004945#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00004946 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004947#else
4948 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4949#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00004950 }
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004951 xmlBufferWriteChar(buf, "?>");
Daniel Veillardcf461992000-03-14 18:30:20 +00004952 } else {
4953 xmlBufferWriteChar(buf, "<?");
4954 xmlBufferWriteCHAR(buf, cur->name);
4955 xmlBufferWriteChar(buf, "?>");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004956 }
4957 return;
4958 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00004959 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004960 if (cur->content != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004961 xmlBufferWriteChar(buf, "<!--");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004962#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00004963 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004964#else
4965 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4966#endif
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004967 xmlBufferWriteChar(buf, "-->");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004968 }
4969 return;
4970 }
Daniel Veillardccb09631998-10-27 06:21:04 +00004971 if (cur->type == XML_ENTITY_REF_NODE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004972 xmlBufferWriteChar(buf, "&");
4973 xmlBufferWriteCHAR(buf, cur->name);
4974 xmlBufferWriteChar(buf, ";");
Daniel Veillardccb09631998-10-27 06:21:04 +00004975 return;
4976 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00004977 if (cur->type == XML_CDATA_SECTION_NODE) {
4978 xmlBufferWriteChar(buf, "<![CDATA[");
4979 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004980#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00004981 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004982#else
4983 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
4984#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00004985 xmlBufferWriteChar(buf, "]]>");
4986 return;
4987 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004988
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004989 if (format == 1) {
Daniel Veillardcf461992000-03-14 18:30:20 +00004990 tmp = cur->children;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004991 while (tmp != NULL) {
4992 if ((tmp->type == XML_TEXT_NODE) ||
4993 (tmp->type == XML_ENTITY_REF_NODE)) {
4994 format = 0;
4995 break;
4996 }
4997 tmp = tmp->next;
4998 }
4999 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005000 xmlBufferWriteChar(buf, "<");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005001 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005002 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5003 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005004 }
5005
Daniel Veillard5099ae81999-04-21 20:12:07 +00005006 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005007 if (cur->nsDef)
Daniel Veillard5099ae81999-04-21 20:12:07 +00005008 xmlNsListDump(buf, cur->nsDef);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005009 if (cur->properties != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00005010 xmlAttrListDump(buf, doc, cur->properties);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005011
Daniel Veillardcf461992000-03-14 18:30:20 +00005012 if ((cur->content == NULL) && (cur->children == NULL) &&
Daniel Veillarde41f2b72000-01-30 20:00:07 +00005013 (!xmlSaveNoEmptyTags)) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005014 xmlBufferWriteChar(buf, "/>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005015 return;
5016 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005017 xmlBufferWriteChar(buf, ">");
Daniel Veillard14fff061999-06-22 21:49:07 +00005018 if (cur->content != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005019 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00005020
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005021#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +00005022 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005023#else
5024 buffer = xmlEncodeEntitiesReentrant(doc,
5025 xmlBufferContent(cur->content));
5026#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00005027 if (buffer != NULL) {
5028 xmlBufferWriteCHAR(buf, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005029 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +00005030 }
5031 }
Daniel Veillardcf461992000-03-14 18:30:20 +00005032 if (cur->children != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005033 if (format) xmlBufferWriteChar(buf, "\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00005034 xmlNodeListDump(buf, doc, cur->children,
Daniel Veillard3e6d2372000-03-04 11:39:43 +00005035 (level >= 0?level+1:-1), format);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005036 if ((xmlIndentTreeOutput) && (format))
5037 for (i = 0;i < level;i++)
5038 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005039 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005040 xmlBufferWriteChar(buf, "</");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005041 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005042 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5043 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005044 }
5045
Daniel Veillard5099ae81999-04-21 20:12:07 +00005046 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005047 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005048}
5049
Daniel Veillard97b58771998-10-20 06:14:16 +00005050/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005051 * xmlElemDump:
Daniel Veillard06047432000-04-24 11:33:38 +00005052 * @f: the FILE * for the output
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005053 * @doc: the document
5054 * @cur: the current node
5055 *
5056 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5057 */
5058void
5059xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5060 xmlBufferPtr buf;
5061
5062 if (cur == NULL) {
5063#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005064 xmlGenericError(xmlGenericErrorContext,
5065 "xmlElemDump : cur == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005066#endif
5067 return;
5068 }
5069 if (doc == NULL) {
5070#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005071 xmlGenericError(xmlGenericErrorContext,
5072 "xmlElemDump : doc == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005073#endif
5074 }
5075 buf = xmlBufferCreate();
5076 if (buf == NULL) return;
5077 if ((doc != NULL) &&
5078 (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard361d8452000-04-03 19:48:13 +00005079#ifdef LIBXML_HTML_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005080 htmlNodeDump(buf, doc, cur);
Daniel Veillard361d8452000-04-03 19:48:13 +00005081#else
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005082 xmlGenericError(xmlGenericErrorContext,
5083 "HTML support not compiled in\n");
Daniel Veillard361d8452000-04-03 19:48:13 +00005084#endif /* LIBXML_HTML_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005085 } else
5086 xmlNodeDump(buf, doc, cur, 0, 1);
5087 xmlBufferDump(f, buf);
5088 xmlBufferFree(buf);
5089}
5090
5091/**
Daniel Veillard97b58771998-10-20 06:14:16 +00005092 * xmlDocContentDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00005093 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00005094 * @cur: the document
5095 *
5096 * Dump an XML document.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005097 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005098static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00005099xmlDocContentDump(xmlBufferPtr buf, xmlDocPtr cur) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00005100 xmlBufferWriteChar(buf, "<?xml version=");
5101 if (cur->version != NULL)
5102 xmlBufferWriteQuotedString(buf, cur->version);
5103 else
5104 xmlBufferWriteChar(buf, "\"1.0\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005105 if (cur->encoding != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00005106 xmlBufferWriteChar(buf, " encoding=");
5107 xmlBufferWriteQuotedString(buf, cur->encoding);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005108 }
5109 switch (cur->standalone) {
5110 case 0:
Daniel Veillard5099ae81999-04-21 20:12:07 +00005111 xmlBufferWriteChar(buf, " standalone=\"no\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005112 break;
5113 case 1:
Daniel Veillard5099ae81999-04-21 20:12:07 +00005114 xmlBufferWriteChar(buf, " standalone=\"yes\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005115 break;
5116 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005117 xmlBufferWriteChar(buf, "?>\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00005118 if (cur->children != NULL) {
5119 xmlNodePtr child = cur->children;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005120
Daniel Veillardb96e6431999-08-29 21:02:19 +00005121 while (child != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005122 xmlNodeDump(buf, cur, child, 0, 1);
5123 xmlBufferWriteChar(buf, "\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00005124 child = child->next;
5125 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005126 }
5127}
5128
Daniel Veillardbe803962000-06-28 23:40:59 +00005129/************************************************************************
5130 * *
5131 * Dumping XML tree content to an I/O output buffer *
5132 * *
5133 ************************************************************************/
5134
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005135void
Daniel Veillardbe803962000-06-28 23:40:59 +00005136xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5137 int level, int format, const char *encoding);
5138static void
5139xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5140 int level, int format, const char *encoding);
5141/**
Daniel Veillardbe803962000-06-28 23:40:59 +00005142 * xmlNsDumpOutput:
5143 * @buf: the XML buffer output
5144 * @cur: a namespace
5145 *
5146 * Dump a local Namespace definition.
5147 * Should be called in the context of attributes dumps.
5148 */
5149static void
5150xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5151 if (cur == NULL) {
5152#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005153 xmlGenericError(xmlGenericErrorContext,
5154 "xmlNsDump : Ns == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005155#endif
5156 return;
5157 }
Daniel Veillarde0854c32000-08-27 21:12:29 +00005158 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005159 /* Within the context of an element attributes */
5160 if (cur->prefix != NULL) {
5161 xmlOutputBufferWriteString(buf, " xmlns:");
5162 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5163 } else
5164 xmlOutputBufferWriteString(buf, " xmlns");
5165 xmlOutputBufferWriteString(buf, "=");
5166 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5167 }
5168}
5169
5170/**
5171 * xmlNsListDumpOutput:
5172 * @buf: the XML buffer output
5173 * @cur: the first namespace
5174 *
5175 * Dump a list of local Namespace definitions.
5176 * Should be called in the context of attributes dumps.
5177 */
5178static void
5179xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5180 while (cur != NULL) {
5181 xmlNsDumpOutput(buf, cur);
5182 cur = cur->next;
5183 }
5184}
5185
5186/**
5187 * xmlDtdDumpOutput:
5188 * @buf: the XML buffer output
5189 * @doc: the document
5190 * @encoding: an optional encoding string
5191 *
5192 * Dump the XML document DTD, if any.
5193 */
5194static void
5195xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5196 if (dtd == NULL) {
5197#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005198 xmlGenericError(xmlGenericErrorContext,
5199 "xmlDtdDump : no internal subset\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005200#endif
5201 return;
5202 }
5203 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5204 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5205 if (dtd->ExternalID != NULL) {
5206 xmlOutputBufferWriteString(buf, " PUBLIC ");
5207 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5208 xmlOutputBufferWriteString(buf, " ");
5209 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5210 } else if (dtd->SystemID != NULL) {
5211 xmlOutputBufferWriteString(buf, " SYSTEM ");
5212 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5213 }
5214 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5215 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5216 xmlOutputBufferWriteString(buf, ">");
5217 return;
5218 }
5219 xmlOutputBufferWriteString(buf, " [\n");
5220 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
5221#if 0
5222 if (dtd->entities != NULL)
5223 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
5224 if (dtd->notations != NULL)
5225 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
5226 if (dtd->elements != NULL)
5227 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
5228 if (dtd->attributes != NULL)
5229 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
5230#endif
5231 xmlOutputBufferWriteString(buf, "]>");
5232}
5233
5234/**
5235 * xmlAttrDumpOutput:
5236 * @buf: the XML buffer output
5237 * @doc: the document
5238 * @cur: the attribute pointer
5239 * @encoding: an optional encoding string
5240 *
5241 * Dump an XML attribute
5242 */
5243static void
5244xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
5245 const char *encoding) {
5246 xmlChar *value;
5247
5248 if (cur == NULL) {
5249#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005250 xmlGenericError(xmlGenericErrorContext,
5251 "xmlAttrDump : property == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005252#endif
5253 return;
5254 }
5255 xmlOutputBufferWriteString(buf, " ");
5256 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5257 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5258 xmlOutputBufferWriteString(buf, ":");
5259 }
5260 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5261 value = xmlNodeListGetString(doc, cur->children, 0);
5262 if (value) {
5263 xmlOutputBufferWriteString(buf, "=");
5264 xmlBufferWriteQuotedString(buf->buffer, value);
5265 xmlFree(value);
5266 } else {
5267 xmlOutputBufferWriteString(buf, "=\"\"");
5268 }
5269}
5270
5271/**
5272 * xmlAttrListDumpOutput:
5273 * @buf: the XML buffer output
5274 * @doc: the document
5275 * @cur: the first attribute pointer
5276 * @encoding: an optional encoding string
5277 *
5278 * Dump a list of XML attributes
5279 */
5280static void
5281xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5282 xmlAttrPtr cur, const char *encoding) {
5283 if (cur == NULL) {
5284#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005285 xmlGenericError(xmlGenericErrorContext,
5286 "xmlAttrListDump : property == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005287#endif
5288 return;
5289 }
5290 while (cur != NULL) {
5291 xmlAttrDumpOutput(buf, doc, cur, encoding);
5292 cur = cur->next;
5293 }
5294}
5295
5296
5297
5298/**
5299 * xmlNodeListDumpOutput:
5300 * @buf: the XML buffer output
5301 * @doc: the document
5302 * @cur: the first node
5303 * @level: the imbrication level for indenting
5304 * @format: is formatting allowed
5305 * @encoding: an optional encoding string
5306 *
5307 * Dump an XML node list, recursive behaviour,children are printed too.
5308 */
5309static void
5310xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5311 xmlNodePtr cur, int level, int format, const char *encoding) {
5312 int i;
5313
5314 if (cur == NULL) {
5315#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005316 xmlGenericError(xmlGenericErrorContext,
5317 "xmlNodeListDump : node == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005318#endif
5319 return;
5320 }
5321 while (cur != NULL) {
5322 if ((format) && (xmlIndentTreeOutput) &&
5323 (cur->type == XML_ELEMENT_NODE))
5324 for (i = 0;i < level;i++)
5325 xmlOutputBufferWriteString(buf, " ");
5326 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5327 if (format) {
5328 xmlOutputBufferWriteString(buf, "\n");
5329 }
5330 cur = cur->next;
5331 }
5332}
5333
5334/**
5335 * xmlNodeDumpOutput:
5336 * @buf: the XML buffer output
5337 * @doc: the document
5338 * @cur: the current node
5339 * @level: the imbrication level for indenting
5340 * @format: is formatting allowed
5341 * @encoding: an optional encoding string
5342 *
5343 * Dump an XML node, recursive behaviour,children are printed too.
5344 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005345void
Daniel Veillardbe803962000-06-28 23:40:59 +00005346xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5347 int level, int format, const char *encoding) {
5348 int i;
5349 xmlNodePtr tmp;
5350
5351 if (cur == NULL) {
5352#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005353 xmlGenericError(xmlGenericErrorContext,
5354 "xmlNodeDump : node == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005355#endif
5356 return;
5357 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00005358 if (cur->type == XML_XINCLUDE_START)
5359 return;
5360 if (cur->type == XML_XINCLUDE_END)
5361 return;
Daniel Veillardbe803962000-06-28 23:40:59 +00005362 if (cur->type == XML_DTD_NODE) {
5363 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5364 return;
5365 }
5366 if (cur->type == XML_ELEMENT_DECL) {
5367 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5368 return;
5369 }
5370 if (cur->type == XML_ATTRIBUTE_DECL) {
5371 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5372 return;
5373 }
5374 if (cur->type == XML_ENTITY_DECL) {
5375 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5376 return;
5377 }
5378 if (cur->type == XML_TEXT_NODE) {
5379 if (cur->content != NULL) {
5380 xmlChar *buffer;
5381
5382#ifndef XML_USE_BUFFER_CONTENT
5383 if (encoding == NULL)
5384 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5385 else
5386 buffer = xmlEncodeSpecialChars(doc, cur->content);
5387#else
5388 if (encoding == NULL)
5389 buffer = xmlEncodeEntitiesReentrant(doc,
5390 xmlBufferContent(cur->content));
5391 else
5392 buffer = xmlEncodeSpecialChars(doc,
5393 xmlBufferContent(cur->content));
5394#endif
5395 if (buffer != NULL) {
5396 xmlOutputBufferWriteString(buf, (const char *)buffer);
5397 xmlFree(buffer);
5398 }
5399 }
5400 return;
5401 }
5402 if (cur->type == XML_PI_NODE) {
5403 if (cur->content != NULL) {
5404 xmlOutputBufferWriteString(buf, "<?");
5405 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5406 if (cur->content != NULL) {
5407 xmlOutputBufferWriteString(buf, " ");
5408#ifndef XML_USE_BUFFER_CONTENT
5409 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5410#else
5411 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5412#endif
5413 }
5414 xmlOutputBufferWriteString(buf, "?>");
5415 } else {
5416 xmlOutputBufferWriteString(buf, "<?");
5417 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5418 xmlOutputBufferWriteString(buf, "?>");
5419 }
5420 return;
5421 }
5422 if (cur->type == XML_COMMENT_NODE) {
5423 if (cur->content != NULL) {
5424 xmlOutputBufferWriteString(buf, "<!--");
5425#ifndef XML_USE_BUFFER_CONTENT
5426 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5427#else
5428 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5429#endif
5430 xmlOutputBufferWriteString(buf, "-->");
5431 }
5432 return;
5433 }
5434 if (cur->type == XML_ENTITY_REF_NODE) {
5435 xmlOutputBufferWriteString(buf, "&");
5436 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5437 xmlOutputBufferWriteString(buf, ";");
5438 return;
5439 }
5440 if (cur->type == XML_CDATA_SECTION_NODE) {
5441 xmlOutputBufferWriteString(buf, "<![CDATA[");
5442 if (cur->content != NULL)
5443#ifndef XML_USE_BUFFER_CONTENT
5444 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5445#else
5446 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5447#endif
5448 xmlOutputBufferWriteString(buf, "]]>");
5449 return;
5450 }
5451
5452 if (format == 1) {
5453 tmp = cur->children;
5454 while (tmp != NULL) {
5455 if ((tmp->type == XML_TEXT_NODE) ||
5456 (tmp->type == XML_ENTITY_REF_NODE)) {
5457 format = 0;
5458 break;
5459 }
5460 tmp = tmp->next;
5461 }
5462 }
5463 xmlOutputBufferWriteString(buf, "<");
5464 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5465 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5466 xmlOutputBufferWriteString(buf, ":");
5467 }
5468
5469 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5470 if (cur->nsDef)
5471 xmlNsListDumpOutput(buf, cur->nsDef);
5472 if (cur->properties != NULL)
5473 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
5474
5475 if ((cur->content == NULL) && (cur->children == NULL) &&
5476 (!xmlSaveNoEmptyTags)) {
5477 xmlOutputBufferWriteString(buf, "/>");
5478 return;
5479 }
5480 xmlOutputBufferWriteString(buf, ">");
5481 if (cur->content != NULL) {
5482 xmlChar *buffer;
5483
5484#ifndef XML_USE_BUFFER_CONTENT
5485 if (encoding == NULL)
5486 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5487 else
5488 buffer = xmlEncodeSpecialChars(doc, cur->content);
5489#else
5490 if (encoding == NULL)
5491 buffer = xmlEncodeEntitiesReentrant(doc,
5492 xmlBufferContent(cur->content));
5493 else
5494 buffer = xmlEncodeSpecialChars(doc,
5495 xmlBufferContent(cur->content));
5496#endif
5497 if (buffer != NULL) {
5498 xmlOutputBufferWriteString(buf, (const char *)buffer);
5499 xmlFree(buffer);
5500 }
5501 }
5502 if (cur->children != NULL) {
5503 if (format) xmlOutputBufferWriteString(buf, "\n");
5504 xmlNodeListDumpOutput(buf, doc, cur->children,
5505 (level >= 0?level+1:-1), format, encoding);
5506 if ((xmlIndentTreeOutput) && (format))
5507 for (i = 0;i < level;i++)
5508 xmlOutputBufferWriteString(buf, " ");
5509 }
5510 xmlOutputBufferWriteString(buf, "</");
5511 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5512 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5513 xmlOutputBufferWriteString(buf, ":");
5514 }
5515
5516 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5517 xmlOutputBufferWriteString(buf, ">");
5518}
5519
5520/**
5521 * xmlDocContentDumpOutput:
5522 * @buf: the XML buffer output
5523 * @cur: the document
5524 * @encoding: an optional encoding string
5525 *
5526 * Dump an XML document.
5527 */
5528static void
5529xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
5530 const char *encoding) {
5531 xmlOutputBufferWriteString(buf, "<?xml version=");
5532 if (cur->version != NULL)
5533 xmlBufferWriteQuotedString(buf->buffer, cur->version);
5534 else
5535 xmlOutputBufferWriteString(buf, "\"1.0\"");
5536 if (encoding == NULL) {
5537 if (cur->encoding != NULL)
5538 encoding = (const char *) cur->encoding;
5539 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005540 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
Daniel Veillardbe803962000-06-28 23:40:59 +00005541 }
5542 if (encoding != NULL) {
5543 xmlOutputBufferWriteString(buf, " encoding=");
5544 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
5545 }
5546 switch (cur->standalone) {
5547 case 0:
5548 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
5549 break;
5550 case 1:
5551 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
5552 break;
5553 }
5554 xmlOutputBufferWriteString(buf, "?>\n");
5555 if (cur->children != NULL) {
5556 xmlNodePtr child = cur->children;
5557
Daniel Veillardbe803962000-06-28 23:40:59 +00005558 while (child != NULL) {
5559 xmlNodeDumpOutput(buf, cur, child, 0, 1, encoding);
5560 xmlOutputBufferWriteString(buf, "\n");
5561 child = child->next;
5562 }
5563 }
5564}
5565
5566/************************************************************************
5567 * *
5568 * Saving functions front-ends *
5569 * *
5570 ************************************************************************/
5571
Daniel Veillard97b58771998-10-20 06:14:16 +00005572/**
5573 * xmlDocDumpMemory:
5574 * @cur: the document
5575 * @mem: OUT: the memory pointer
5576 * @size: OUT: the memory lenght
5577 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005578 * Dump an XML document in memory and return the xmlChar * and it's size.
Daniel Veillard97b58771998-10-20 06:14:16 +00005579 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005580 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005581void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005582xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005583 xmlBufferPtr buf;
5584
Daniel Veillard260a68f1998-08-13 03:39:55 +00005585 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005586#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005587 xmlGenericError(xmlGenericErrorContext,
5588 "xmlDocDumpMemory : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005589#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00005590 *mem = NULL;
5591 *size = 0;
5592 return;
5593 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005594 buf = xmlBufferCreate();
5595 if (buf == NULL) {
5596 *mem = NULL;
5597 *size = 0;
5598 return;
5599 }
5600 xmlDocContentDump(buf, cur);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005601 *mem = xmlStrndup(buf->content, buf->use);
Daniel Veillard5099ae81999-04-21 20:12:07 +00005602 *size = buf->use;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005603 xmlBufferFree(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005604}
5605
Daniel Veillard97b58771998-10-20 06:14:16 +00005606/**
5607 * xmlGetDocCompressMode:
5608 * @doc: the document
5609 *
5610 * get the compression ratio for a document, ZLIB based
Daniel Veillard1e346af1999-02-22 10:33:01 +00005611 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00005612 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005613int
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005614xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005615 if (doc == NULL) return(-1);
5616 return(doc->compression);
5617}
5618
Daniel Veillard97b58771998-10-20 06:14:16 +00005619/**
5620 * xmlSetDocCompressMode:
5621 * @doc: the document
5622 * @mode: the compression ratio
5623 *
5624 * set the compression ratio for a document, ZLIB based
5625 * Correct values: 0 (uncompressed) to 9 (max compression)
5626 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005627void
5628xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005629 if (doc == NULL) return;
5630 if (mode < 0) doc->compression = 0;
5631 else if (mode > 9) doc->compression = 9;
5632 else doc->compression = mode;
5633}
5634
Daniel Veillard97b58771998-10-20 06:14:16 +00005635/**
5636 * xmlGetCompressMode:
5637 *
5638 * get the default compression mode used, ZLIB based.
Daniel Veillard1e346af1999-02-22 10:33:01 +00005639 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00005640 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005641int
5642 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005643 return(xmlCompressMode);
5644}
Daniel Veillard97b58771998-10-20 06:14:16 +00005645
5646/**
5647 * xmlSetCompressMode:
5648 * @mode: the compression ratio
5649 *
5650 * set the default compression mode used, ZLIB based
5651 * Correct values: 0 (uncompressed) to 9 (max compression)
5652 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005653void
5654xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005655 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00005656 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005657 else xmlCompressMode = mode;
5658}
5659
Daniel Veillardbe803962000-06-28 23:40:59 +00005660/**
5661 * xmlDocDump:
5662 * @f: the FILE*
5663 * @cur: the document
5664 *
5665 * Dump an XML document to an open FILE.
5666 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005667 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005668 */
5669int
5670xmlDocDump(FILE *f, xmlDocPtr cur) {
5671 xmlOutputBufferPtr buf;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005672 const char * encoding;
5673 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillardbe803962000-06-28 23:40:59 +00005674 int ret;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005675
Daniel Veillardbe803962000-06-28 23:40:59 +00005676 if (cur == NULL) {
5677#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005678 xmlGenericError(xmlGenericErrorContext,
5679 "xmlDocDump : document == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005680#endif
5681 return(-1);
5682 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005683 encoding = (const char *) cur->encoding;
5684
5685 if (encoding != NULL) {
5686 xmlCharEncoding enc;
5687
5688 enc = xmlParseCharEncoding(encoding);
5689
5690 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005691 xmlGenericError(xmlGenericErrorContext,
5692 "xmlDocDump: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005693 return(-1);
5694 }
5695 if (enc != XML_CHAR_ENCODING_UTF8) {
5696 handler = xmlFindCharEncodingHandler(encoding);
5697 if (handler == NULL) {
5698 xmlFree((char *) cur->encoding);
5699 cur->encoding = NULL;
5700 }
5701 }
5702 }
5703 buf = xmlOutputBufferCreateFile(f, handler);
Daniel Veillardbe803962000-06-28 23:40:59 +00005704 if (buf == NULL) return(-1);
5705 xmlDocContentDumpOutput(buf, cur, NULL);
5706
5707 ret = xmlOutputBufferClose(buf);
5708 return(ret);
5709}
5710
5711/**
Daniel Veillardbe803962000-06-28 23:40:59 +00005712 * xmlSaveFileTo:
5713 * @buf: an output I/O buffer
5714 * @cur: the document
5715 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
5716 *
5717 * Dump an XML document to an I/O buffer.
5718 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005719 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005720 */
5721int
5722xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
5723 int ret;
5724
5725 if (buf == NULL) return(0);
5726 xmlDocContentDumpOutput(buf, cur, encoding);
5727 ret = xmlOutputBufferClose(buf);
5728 return(ret);
5729}
5730
5731/**
5732 * xmlSaveFileEnc:
5733 * @filename: the filename (or URL)
5734 * @cur: the document
5735 * @encoding: the name of an encoding (or NULL)
5736 *
5737 * Dump an XML document, converting it to the given encoding
5738 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005739 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005740 */
5741int
5742xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
5743 xmlOutputBufferPtr buf;
5744 xmlCharEncodingHandlerPtr handler = NULL;
5745 int ret;
5746
5747 if (encoding != NULL) {
5748 xmlCharEncoding enc;
5749
5750 enc = xmlParseCharEncoding(encoding);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005751 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005752 xmlGenericError(xmlGenericErrorContext,
5753 "xmlSaveFileEnc: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005754 return(-1);
5755 }
5756 if (enc != XML_CHAR_ENCODING_UTF8) {
5757 handler = xmlFindCharEncodingHandler(encoding);
5758 if (handler == NULL) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005759 return(-1);
5760 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005761 }
5762 }
5763
5764 /*
5765 * save the content to a temp buffer.
5766 */
5767 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
5768 if (buf == NULL) return(0);
5769
5770 xmlDocContentDumpOutput(buf, cur, encoding);
5771
5772 ret = xmlOutputBufferClose(buf);
5773 return(ret);
5774}
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005775
5776/**
5777 * xmlSaveFile:
5778 * @filename: the filename (or URL)
5779 * @cur: the document
5780 *
5781 * Dump an XML document to a file. Will use compression if
5782 * compiled in and enabled. If @filename is "-" the stdout file is
5783 * used.
5784 * returns: the number of byte written or -1 in case of failure.
5785 */
5786int
5787xmlSaveFile(const char *filename, xmlDocPtr cur) {
5788 xmlOutputBufferPtr buf;
5789 const char *encoding;
5790 xmlCharEncodingHandlerPtr handler = NULL;
5791 int ret;
5792
5793 if (cur == NULL)
5794 return(-1);
5795 encoding = (const char *) cur->encoding;
5796
5797 /*
5798 * save the content to a temp buffer.
5799 */
5800#ifdef HAVE_ZLIB_H
5801 if (cur->compression < 0) cur->compression = xmlCompressMode;
Daniel Veillardbe803962000-06-28 23:40:59 +00005802#endif
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005803 if (encoding != NULL) {
5804 xmlCharEncoding enc;
5805
5806 enc = xmlParseCharEncoding(encoding);
5807
5808 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005809 xmlGenericError(xmlGenericErrorContext,
5810 "xmlSaveFile: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005811 return(-1);
5812 }
5813 if (enc != XML_CHAR_ENCODING_UTF8) {
5814 handler = xmlFindCharEncodingHandler(encoding);
5815 if (handler == NULL) {
5816 xmlFree((char *) cur->encoding);
5817 cur->encoding = NULL;
5818 }
5819 }
5820 }
5821
5822 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
5823 if (buf == NULL) return(0);
5824
5825 xmlDocContentDumpOutput(buf, cur, NULL);
5826
5827 ret = xmlOutputBufferClose(buf);
5828 return(ret);
5829}
5830