blob: 5339e9f4881820f5418093c297ae42da636410c8 [file] [log] [blame]
Daniel Veillard260a68f1998-08-13 03:39:55 +00001/*
2 * tree.c : implemetation of access function for an XML tree.
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006 * Daniel.Veillard@w3.org
Daniel Veillardce6e98d2000-11-25 09:54:49 +00007 *
8 * 14 Nov 2000 ht - Changed the name of function xmlBufferWriteChar under VMS
9 * as it was similar to xmlBufferWriteCHAR when compiling without case
10 * sensitivity.
11 *
Daniel Veillard260a68f1998-08-13 03:39:55 +000012 */
13
Daniel Veillard7f7d1111999-09-22 09:46:25 +000014#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000015#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000016#else
Daniel Veillard151b1b01998-09-23 00:49:46 +000017#include "config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#endif
19
Daniel Veillard260a68f1998-08-13 03:39:55 +000020#include <stdio.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000021#include <string.h> /* for memset() only ! */
22
Daniel Veillard7f7d1111999-09-22 09:46:25 +000023#ifdef HAVE_CTYPE_H
24#include <ctype.h>
25#endif
26#ifdef HAVE_STDLIB_H
27#include <stdlib.h>
28#endif
Daniel Veillard151b1b01998-09-23 00:49:46 +000029#ifdef HAVE_ZLIB_H
30#include <zlib.h>
31#endif
32
Daniel Veillard361d8452000-04-03 19:48:13 +000033#include <libxml/xmlmemory.h>
34#include <libxml/tree.h>
35#include <libxml/parser.h>
36#include <libxml/entities.h>
37#include <libxml/valid.h>
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000038#include <libxml/xmlerror.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000039
Daniel Veillardf6eea272001-01-18 12:17:12 +000040xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
41xmlChar xmlStringTextNoenc[] =
42 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
43xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
Daniel Veillard260a68f1998-08-13 03:39:55 +000044int oldXMLWDcompatibility = 0;
Daniel Veillardcf461992000-03-14 18:30:20 +000045int xmlIndentTreeOutput = 0;
Daniel Veillardf5c2c871999-12-01 09:51:45 +000046xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT;
Daniel Veillard260a68f1998-08-13 03:39:55 +000047
Daniel Veillard15a8df41998-09-24 19:15:06 +000048static int xmlCompressMode = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +000049static int xmlCheckDTD = 1;
Daniel Veillarde41f2b72000-01-30 20:00:07 +000050int xmlSaveNoEmptyTags = 0;
Daniel Veillard3e6d2372000-03-04 11:39:43 +000051
52#define IS_BLANK(c) \
53 (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
Daniel Veillard15a8df41998-09-24 19:15:06 +000054
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000055#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
Daniel Veillardcf461992000-03-14 18:30:20 +000056 xmlNodePtr ulccur = (n)->children; \
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000057 if (ulccur == NULL) { \
58 (n)->last = NULL; \
59 } else { \
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000060 while (ulccur->next != NULL) { \
61 ulccur->parent = (n); \
62 ulccur = ulccur->next; \
63 } \
64 ulccur->parent = (n); \
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000065 (n)->last = ulccur; \
Daniel Veillard1e346af1999-02-22 10:33:01 +000066}}
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000067
Daniel Veillardad8f99d2000-01-15 14:20:03 +000068/* #define DEBUG_BUFFER */
69/* #define DEBUG_TREE */
70
Daniel Veillard260a68f1998-08-13 03:39:55 +000071/************************************************************************
72 * *
73 * Allocation and deallocation of basic structures *
74 * *
75 ************************************************************************/
76
Daniel Veillard97b58771998-10-20 06:14:16 +000077/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +000078 * xmlSetBufferAllocationScheme:
79 * @scheme: allocation method to use
80 *
81 * Set the buffer allocation method. Types are
82 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
83 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
84 * improves performance
85 */
86void
87xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
88 xmlBufferAllocScheme = scheme;
89}
90
91/**
92 * xmlGetBufferAllocationScheme:
93 *
94 * Types are
95 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
96 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
97 * improves performance
98 *
99 * Returns the current allocation scheme
100 */
101xmlBufferAllocationScheme
102xmlGetBufferAllocationScheme() {
103 return xmlBufferAllocScheme;
104}
105
106/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000107 * xmlNewNs:
108 * @node: the element carrying the namespace
109 * @href: the URI associated
110 * @prefix: the prefix for the namespace
111 *
Daniel Veillard686d6b62000-01-03 11:08:02 +0000112 * Creation of a new Namespace. This function will refuse to create
113 * a namespace with a similar prefix than an existing one present on this
114 * node.
Daniel Veillarde0854c32000-08-27 21:12:29 +0000115 * We use href==NULL in the case of an element creation where the namespace
116 * was not defined.
Daniel Veillard686d6b62000-01-03 11:08:02 +0000117 * Returns returns a new namespace pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000118 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000119xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000120xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000121 xmlNsPtr cur;
122
Daniel Veillard2f913b72001-01-31 13:23:49 +0000123 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
124 return(NULL);
125
Daniel Veillard260a68f1998-08-13 03:39:55 +0000126 /*
Daniel Veillardcf461992000-03-14 18:30:20 +0000127 * Allocate a new Namespace and fill the fields.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000128 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000129 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000130 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000131 xmlGenericError(xmlGenericErrorContext,
132 "xmlNewNs : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000133 return(NULL);
134 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000135 memset(cur, 0, sizeof(xmlNs));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000136 cur->type = XML_LOCAL_NAMESPACE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000137
Daniel Veillard260a68f1998-08-13 03:39:55 +0000138 if (href != NULL)
139 cur->href = xmlStrdup(href);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000140 if (prefix != NULL)
141 cur->prefix = xmlStrdup(prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000142
143 /*
144 * Add it at the end to preserve parsing order ...
Daniel Veillard686d6b62000-01-03 11:08:02 +0000145 * and checks for existing use of the prefix
Daniel Veillard260a68f1998-08-13 03:39:55 +0000146 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000147 if (node != NULL) {
148 if (node->nsDef == NULL) {
149 node->nsDef = cur;
150 } else {
151 xmlNsPtr prev = node->nsDef;
152
Daniel Veillard0142b842000-01-14 14:45:24 +0000153 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000154 (xmlStrEqual(prev->prefix, cur->prefix))) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000155 xmlFreeNs(cur);
156 return(NULL);
157 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000158 while (prev->next != NULL) {
Daniel Veillard0142b842000-01-14 14:45:24 +0000159 prev = prev->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +0000160 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000161 (xmlStrEqual(prev->prefix, cur->prefix))) {
Daniel Veillard686d6b62000-01-03 11:08:02 +0000162 xmlFreeNs(cur);
163 return(NULL);
164 }
Daniel Veillard686d6b62000-01-03 11:08:02 +0000165 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000166 prev->next = cur;
167 }
168 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000169 return(cur);
170}
171
Daniel Veillard97b58771998-10-20 06:14:16 +0000172/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000173 * xmlSetNs:
174 * @node: a node in the document
175 * @ns: a namespace pointer
176 *
177 * Associate a namespace to a node, a posteriori.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000178 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000179void
180xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000181 if (node == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000182#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000183 xmlGenericError(xmlGenericErrorContext,
184 "xmlSetNs: node == NULL\n");
Daniel Veillardcf461992000-03-14 18:30:20 +0000185#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000186 return;
187 }
188 node->ns = ns;
189}
190
Daniel Veillard97b58771998-10-20 06:14:16 +0000191/**
192 * xmlFreeNs:
193 * @cur: the namespace pointer
194 *
195 * Free up the structures associated to a namespace
Daniel Veillard260a68f1998-08-13 03:39:55 +0000196 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000197void
198xmlFreeNs(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000199 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000200#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000201 xmlGenericError(xmlGenericErrorContext,
202 "xmlFreeNs : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000203#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000204 return;
205 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000206 if (cur->href != NULL) xmlFree((char *) cur->href);
207 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000208 memset(cur, -1, sizeof(xmlNs));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000209 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000210}
211
Daniel Veillard97b58771998-10-20 06:14:16 +0000212/**
213 * xmlFreeNsList:
214 * @cur: the first namespace pointer
215 *
216 * Free up all the structures associated to the chained namespaces.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000217 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000218void
219xmlFreeNsList(xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000220 xmlNsPtr next;
221 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000222#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000223 xmlGenericError(xmlGenericErrorContext,
224 "xmlFreeNsList : ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000225#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000226 return;
227 }
228 while (cur != NULL) {
229 next = cur->next;
230 xmlFreeNs(cur);
231 cur = next;
232 }
233}
234
Daniel Veillard97b58771998-10-20 06:14:16 +0000235/**
236 * xmlNewDtd:
237 * @doc: the document pointer
238 * @name: the DTD name
239 * @ExternalID: the external ID
240 * @SystemID: the system ID
241 *
Daniel Veillardcf461992000-03-14 18:30:20 +0000242 * Creation of a new DTD for the external subset. To create an
243 * internal subset, use xmlCreateIntSubset().
244 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000245 * Returns a pointer to the new DTD structure
Daniel Veillard260a68f1998-08-13 03:39:55 +0000246 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000247xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000248xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
249 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000250 xmlDtdPtr cur;
251
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000252 if ((doc != NULL) && (doc->extSubset != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000253#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000254 xmlGenericError(xmlGenericErrorContext,
255 "xmlNewDtd(%s): document %s already have a DTD %s\n",
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000256 /* !!! */ (char *) name, doc->name,
257 /* !!! */ (char *)doc->extSubset->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000258#endif
259 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000260 }
261
262 /*
263 * Allocate a new DTD and fill the fields.
264 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000265 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000266 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000267 xmlGenericError(xmlGenericErrorContext,
268 "xmlNewDtd : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000269 return(NULL);
270 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000271 memset(cur, 0 , sizeof(xmlDtd));
272 cur->type = XML_DTD_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000273
274 if (name != NULL)
275 cur->name = xmlStrdup(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000276 if (ExternalID != NULL)
277 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000278 if (SystemID != NULL)
279 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000280 if (doc != NULL)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000281 doc->extSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000282 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000283
284 return(cur);
285}
286
287/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000288 * xmlGetIntSubset:
289 * @doc: the document pointer
290 *
291 * Get the internal subset of a document
292 * Returns a pointer to the DTD structure or NULL if not found
293 */
294
295xmlDtdPtr
296xmlGetIntSubset(xmlDocPtr doc) {
297 xmlNodePtr cur;
298
299 if (doc == NULL)
300 return(NULL);
301 cur = doc->children;
302 while (cur != NULL) {
303 if (cur->type == XML_DTD_NODE)
304 return((xmlDtdPtr) cur);
305 cur = cur->next;
306 }
307 return((xmlDtdPtr) doc->intSubset);
308}
309
310/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000311 * xmlCreateIntSubset:
312 * @doc: the document pointer
313 * @name: the DTD name
314 * @ExternalID: the external ID
315 * @SystemID: the system ID
316 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000317 * Create the internal subset of a document
318 * Returns a pointer to the new DTD structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000319 */
320xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000321xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
322 const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000323 xmlDtdPtr cur;
324
Daniel Veillardcf461992000-03-14 18:30:20 +0000325 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000326#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000327 xmlGenericError(xmlGenericErrorContext,
328
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000329 "xmlCreateIntSubset(): document %s already have an internal subset\n",
330 doc->name);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000331#endif
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000332 return(NULL);
333 }
334
335 /*
336 * Allocate a new DTD and fill the fields.
337 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000338 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000339 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000340 xmlGenericError(xmlGenericErrorContext,
341 "xmlNewDtd : malloc failed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000342 return(NULL);
343 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000344 memset(cur, 0, sizeof(xmlDtd));
345 cur->type = XML_DTD_NODE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000346
347 if (name != NULL)
348 cur->name = xmlStrdup(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000349 if (ExternalID != NULL)
350 cur->ExternalID = xmlStrdup(ExternalID);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000351 if (SystemID != NULL)
352 cur->SystemID = xmlStrdup(SystemID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000353 if (doc != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000354 doc->intSubset = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000355 cur->parent = doc;
356 cur->doc = doc;
357 if (doc->children == NULL) {
358 doc->children = (xmlNodePtr) cur;
359 doc->last = (xmlNodePtr) cur;
360 } else {
361 xmlNodePtr prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000362
Daniel Veillardb8f25c92000-08-19 19:52:36 +0000363 if (doc->type == XML_HTML_DOCUMENT_NODE) {
364 prev = doc->children;
365 prev->prev = (xmlNodePtr) cur;
366 cur->next = prev;
367 doc->children = (xmlNodePtr) cur;
368 } else {
369 prev = doc->last;
370 prev->next = (xmlNodePtr) cur;
371 cur->prev = prev;
372 doc->last = (xmlNodePtr) cur;
373 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000374 }
375 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000376 return(cur);
377}
378
Daniel Veillard97b58771998-10-20 06:14:16 +0000379/**
380 * xmlFreeDtd:
381 * @cur: the DTD structure to free up
382 *
383 * Free a DTD structure.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000384 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000385void
386xmlFreeDtd(xmlDtdPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000387 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000388#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000389 xmlGenericError(xmlGenericErrorContext,
390 "xmlFreeDtd : DTD == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000391#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000392 return;
393 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000394 if (cur->children != NULL) {
395 xmlNodePtr next, c = cur->children;
396
397 /*
398 * Cleanup all the DTD comments they are not in the Dtd
399 * indexes.
400 */
401 while (c != NULL) {
402 next = c->next;
403 if (c->type == XML_COMMENT_NODE) {
404 xmlUnlinkNode(c);
405 xmlFreeNode(c);
406 }
407 c = next;
408 }
409 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000410 if (cur->name != NULL) xmlFree((char *) cur->name);
411 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
412 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
Daniel Veillardcf461992000-03-14 18:30:20 +0000413 /* TODO !!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000414 if (cur->notations != NULL)
415 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
Daniel Veillardcf461992000-03-14 18:30:20 +0000416
Daniel Veillard260a68f1998-08-13 03:39:55 +0000417 if (cur->elements != NULL)
Daniel Veillard3b9def11999-01-31 22:15:06 +0000418 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000419 if (cur->attributes != NULL)
420 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000421 if (cur->entities != NULL)
422 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
Daniel Veillard126f2792000-10-24 17:10:12 +0000423 if (cur->pentities != NULL)
424 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
Daniel Veillardcf461992000-03-14 18:30:20 +0000425
Daniel Veillard260a68f1998-08-13 03:39:55 +0000426 memset(cur, -1, sizeof(xmlDtd));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000427 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000428}
429
Daniel Veillard97b58771998-10-20 06:14:16 +0000430/**
431 * xmlNewDoc:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000432 * @version: xmlChar string giving the version of XML "1.0"
Daniel Veillard97b58771998-10-20 06:14:16 +0000433 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000434 * Returns a new document
Daniel Veillard260a68f1998-08-13 03:39:55 +0000435 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000436xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000437xmlNewDoc(const xmlChar *version) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000438 xmlDocPtr cur;
439
Daniel Veillard7eda8452000-10-14 23:38:43 +0000440 if (version == NULL)
441 version = (const xmlChar *) "1.0";
Daniel Veillard260a68f1998-08-13 03:39:55 +0000442
443 /*
444 * Allocate a new document and fill the fields.
445 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000446 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000447 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000448 xmlGenericError(xmlGenericErrorContext,
449 "xmlNewDoc : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000450 return(NULL);
451 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000452 memset(cur, 0, sizeof(xmlDoc));
Daniel Veillard33942841998-10-18 19:12:41 +0000453 cur->type = XML_DOCUMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000454
Daniel Veillard260a68f1998-08-13 03:39:55 +0000455 cur->version = xmlStrdup(version);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000456 cur->standalone = -1;
Daniel Veillard11a48ec1999-11-23 10:40:46 +0000457 cur->compression = -1; /* not initialized */
Daniel Veillardcf461992000-03-14 18:30:20 +0000458 cur->doc = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000459 return(cur);
460}
461
Daniel Veillard97b58771998-10-20 06:14:16 +0000462/**
463 * xmlFreeDoc:
464 * @cur: pointer to the document
465 * @:
466 *
467 * Free up all the structures used by a document, tree included.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000468 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000469void
470xmlFreeDoc(xmlDocPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000471 if (cur == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000472#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000473 xmlGenericError(xmlGenericErrorContext,
474 "xmlFreeDoc : document == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000475#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000476 return;
477 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000478 if (cur->version != NULL) xmlFree((char *) cur->version);
479 if (cur->name != NULL) xmlFree((char *) cur->name);
480 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
Daniel Veillardcf461992000-03-14 18:30:20 +0000481 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000482 if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
483 if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000484 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000485 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000486 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
Daniel Veillardcf461992000-03-14 18:30:20 +0000487 if (cur->URL != NULL) xmlFree((char *) cur->URL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000488 memset(cur, -1, sizeof(xmlDoc));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000489 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000490}
491
Daniel Veillard97b58771998-10-20 06:14:16 +0000492/**
Daniel Veillard16253641998-10-28 22:58:05 +0000493 * xmlStringLenGetNodeList:
494 * @doc: the document
495 * @value: the value of the text
Daniel Veillard1e346af1999-02-22 10:33:01 +0000496 * @len: the length of the string value
Daniel Veillard16253641998-10-28 22:58:05 +0000497 *
498 * Parse the value string and build the node list associated. Should
499 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000500 * Returns a pointer to the first child
Daniel Veillard16253641998-10-28 22:58:05 +0000501 */
502xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000503xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
Daniel Veillard16253641998-10-28 22:58:05 +0000504 xmlNodePtr ret = NULL, last = NULL;
505 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000506 xmlChar *val;
507 const xmlChar *cur = value;
508 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000509 xmlEntityPtr ent;
Daniel Veillard16253641998-10-28 22:58:05 +0000510
511 if (value == NULL) return(NULL);
512
513 q = cur;
514 while ((*cur != 0) && (cur - value < len)) {
515 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000516 /*
517 * Save the current text.
518 */
Daniel Veillard16253641998-10-28 22:58:05 +0000519 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000520 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
521 xmlNodeAddContentLen(last, q, cur - q);
522 } else {
523 node = xmlNewDocTextLen(doc, q, cur - q);
524 if (node == NULL) return(ret);
525 if (last == NULL)
526 last = ret = node;
527 else {
528 last->next = node;
529 node->prev = last;
530 last = node;
531 }
Daniel Veillard16253641998-10-28 22:58:05 +0000532 }
533 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000534 /*
535 * Read the entity string
536 */
Daniel Veillard16253641998-10-28 22:58:05 +0000537 cur++;
538 q = cur;
539 while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
540 if ((*cur == 0) || (cur - value >= len)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000541#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000542 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard011b63c1999-06-02 17:44:04 +0000543 "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000544#endif
Daniel Veillard16253641998-10-28 22:58:05 +0000545 return(ret);
546 }
547 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000548 /*
549 * Predefined entities don't generate nodes
550 */
Daniel Veillard16253641998-10-28 22:58:05 +0000551 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000552 ent = xmlGetDocEntity(doc, val);
553 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000554 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000555 if (last == NULL) {
556 node = xmlNewDocText(doc, ent->content);
557 last = ret = node;
558 } else
559 xmlNodeAddContent(last, ent->content);
560
561 } else {
562 /*
563 * Create a new REFERENCE_REF node
564 */
565 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000566 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000567 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000568 return(ret);
569 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000570 if (last == NULL)
571 last = ret = node;
572 else {
573 last->next = node;
574 node->prev = last;
575 last = node;
576 }
Daniel Veillard16253641998-10-28 22:58:05 +0000577 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000578 xmlFree(val);
Daniel Veillard16253641998-10-28 22:58:05 +0000579 }
580 cur++;
581 q = cur;
582 } else
583 cur++;
584 }
585 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000586 /*
587 * Handle the last piece of text.
588 */
589 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
590 xmlNodeAddContentLen(last, q, cur - q);
591 } else {
592 node = xmlNewDocTextLen(doc, q, cur - q);
593 if (node == NULL) return(ret);
594 if (last == NULL)
595 last = ret = node;
596 else {
597 last->next = node;
598 node->prev = last;
599 last = node;
600 }
Daniel Veillard16253641998-10-28 22:58:05 +0000601 }
602 }
603 return(ret);
604}
605
606/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000607 * xmlStringGetNodeList:
608 * @doc: the document
609 * @value: the value of the attribute
610 *
611 * Parse the value string and build the node list associated. Should
612 * produce a flat tree with only TEXTs and ENTITY_REFs.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000613 * Returns a pointer to the first child
Daniel Veillardccb09631998-10-27 06:21:04 +0000614 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000615xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000616xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000617 xmlNodePtr ret = NULL, last = NULL;
618 xmlNodePtr node;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000619 xmlChar *val;
620 const xmlChar *cur = value;
621 const xmlChar *q;
Daniel Veillard25940b71998-10-29 05:51:30 +0000622 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +0000623
624 if (value == NULL) return(NULL);
625
626 q = cur;
627 while (*cur != 0) {
628 if (*cur == '&') {
Daniel Veillard25940b71998-10-29 05:51:30 +0000629 /*
630 * Save the current text.
631 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000632 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000633 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
634 xmlNodeAddContentLen(last, q, cur - q);
635 } else {
636 node = xmlNewDocTextLen(doc, q, cur - q);
637 if (node == NULL) return(ret);
638 if (last == NULL)
639 last = ret = node;
640 else {
641 last->next = node;
642 node->prev = last;
643 last = node;
644 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000645 }
646 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000647 /*
648 * Read the entity string
649 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000650 cur++;
651 q = cur;
652 while ((*cur != 0) && (*cur != ';')) cur++;
653 if (*cur == 0) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000654#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000655 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardccb09631998-10-27 06:21:04 +0000656 "xmlStringGetNodeList: unterminated entity %30s\n", q);
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000657#endif
Daniel Veillardccb09631998-10-27 06:21:04 +0000658 return(ret);
659 }
660 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000661 /*
662 * Predefined entities don't generate nodes
663 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000664 val = xmlStrndup(q, cur - q);
Daniel Veillard25940b71998-10-29 05:51:30 +0000665 ent = xmlGetDocEntity(doc, val);
666 if ((ent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000667 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000668 if (last == NULL) {
669 node = xmlNewDocText(doc, ent->content);
670 last = ret = node;
671 } else
672 xmlNodeAddContent(last, ent->content);
673
674 } else {
675 /*
676 * Create a new REFERENCE_REF node
677 */
Daniel Veillard25940b71998-10-29 05:51:30 +0000678 node = xmlNewReference(doc, val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000679 if (node == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000680 if (val != NULL) xmlFree(val);
Daniel Veillard242590e1998-11-13 18:04:35 +0000681 return(ret);
682 }
Daniel Veillard25940b71998-10-29 05:51:30 +0000683 if (last == NULL)
684 last = ret = node;
685 else {
686 last->next = node;
687 node->prev = last;
688 last = node;
689 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000690 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000691 xmlFree(val);
Daniel Veillardccb09631998-10-27 06:21:04 +0000692 }
693 cur++;
694 q = cur;
695 } else
696 cur++;
697 }
698 if (cur != q) {
Daniel Veillard25940b71998-10-29 05:51:30 +0000699 /*
700 * Handle the last piece of text.
701 */
702 if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
703 xmlNodeAddContentLen(last, q, cur - q);
704 } else {
705 node = xmlNewDocTextLen(doc, q, cur - q);
706 if (node == NULL) return(ret);
707 if (last == NULL)
708 last = ret = node;
709 else {
710 last->next = node;
711 node->prev = last;
712 last = node;
713 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000714 }
715 }
716 return(ret);
717}
718
719/**
720 * xmlNodeListGetString:
721 * @doc: the document
722 * @list: a Node list
723 * @inLine: should we replace entity contents or show their external form
724 *
725 * Returns the string equivalent to the text contained in the Node list
726 * made of TEXTs and ENTITY_REFs
Daniel Veillard1e346af1999-02-22 10:33:01 +0000727 * Returns a pointer to the string copy, the calller must free it.
Daniel Veillardccb09631998-10-27 06:21:04 +0000728 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000729xmlChar *
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000730xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000731 xmlNodePtr node = list;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000732 xmlChar *ret = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000733 xmlEntityPtr ent;
734
735 if (list == NULL) return(NULL);
736
737 while (node != NULL) {
Daniel Veillard87b95392000-08-12 21:12:04 +0000738 if ((node->type == XML_TEXT_NODE) ||
739 (node->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard71b656e2000-01-05 14:46:17 +0000740 if (inLine) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000741#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000742 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000743#else
744 ret = xmlStrcat(ret, xmlBufferContent(node->content));
745#endif
746 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000747 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +0000748
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000749#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +0000750 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000751#else
752 buffer = xmlEncodeEntitiesReentrant(doc,
753 xmlBufferContent(node->content));
754#endif
Daniel Veillard14fff061999-06-22 21:49:07 +0000755 if (buffer != NULL) {
756 ret = xmlStrcat(ret, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000757 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +0000758 }
759 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000760 } else if (node->type == XML_ENTITY_REF_NODE) {
761 if (inLine) {
762 ent = xmlGetDocEntity(doc, node->name);
763 if (ent != NULL)
764 ret = xmlStrcat(ret, ent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000765 else {
766#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +0000767 ret = xmlStrcat(ret, node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +0000768#else
769 ret = xmlStrcat(ret, xmlBufferContent(node->content));
770#endif
771 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000772 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000773 xmlChar buf[2];
Daniel Veillardccb09631998-10-27 06:21:04 +0000774 buf[0] = '&'; buf[1] = 0;
775 ret = xmlStrncat(ret, buf, 1);
776 ret = xmlStrcat(ret, node->name);
777 buf[0] = ';'; buf[1] = 0;
778 ret = xmlStrncat(ret, buf, 1);
779 }
780 }
781#if 0
782 else {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000783 xmlGenericError(xmlGenericErrorContext,
784 "xmlGetNodeListString : invalide node type %d\n",
Daniel Veillardccb09631998-10-27 06:21:04 +0000785 node->type);
786 }
787#endif
788 node = node->next;
789 }
790 return(ret);
791}
792
793/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000794 * xmlNodeListGetRawString:
795 * @doc: the document
796 * @list: a Node list
797 * @inLine: should we replace entity contents or show their external form
798 *
799 * Returns the string equivalent to the text contained in the Node list
800 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
801 * this function doesn't do any character encoding handling.
802 *
803 * Returns a pointer to the string copy, the calller must free it.
804 */
805xmlChar *
806xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
807 xmlNodePtr node = list;
808 xmlChar *ret = NULL;
809 xmlEntityPtr ent;
810
811 if (list == NULL) return(NULL);
812
813 while (node != NULL) {
814 if (node->type == XML_TEXT_NODE) {
815 if (inLine) {
816#ifndef XML_USE_BUFFER_CONTENT
817 ret = xmlStrcat(ret, node->content);
818#else
819 ret = xmlStrcat(ret, xmlBufferContent(node->content));
820#endif
821 } else {
822 xmlChar *buffer;
823
824#ifndef XML_USE_BUFFER_CONTENT
825 buffer = xmlEncodeSpecialChars(doc, node->content);
826#else
827 buffer = xmlEncodeSpecialChars(doc,
828 xmlBufferContent(node->content));
829#endif
830 if (buffer != NULL) {
831 ret = xmlStrcat(ret, buffer);
832 xmlFree(buffer);
833 }
834 }
835 } else if (node->type == XML_ENTITY_REF_NODE) {
836 if (inLine) {
837 ent = xmlGetDocEntity(doc, node->name);
838 if (ent != NULL)
839 ret = xmlStrcat(ret, ent->content);
840 else {
841#ifndef XML_USE_BUFFER_CONTENT
842 ret = xmlStrcat(ret, node->content);
843#else
844 ret = xmlStrcat(ret, xmlBufferContent(node->content));
845#endif
846 }
847 } else {
848 xmlChar buf[2];
849 buf[0] = '&'; buf[1] = 0;
850 ret = xmlStrncat(ret, buf, 1);
851 ret = xmlStrcat(ret, node->name);
852 buf[0] = ';'; buf[1] = 0;
853 ret = xmlStrncat(ret, buf, 1);
854 }
855 }
856#if 0
857 else {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000858 xmlGenericError(xmlGenericErrorContext,
859 "xmlGetNodeListString : invalide node type %d\n",
Daniel Veillardbe803962000-06-28 23:40:59 +0000860 node->type);
861 }
862#endif
863 node = node->next;
864 }
865 return(ret);
866}
867
868/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000869 * xmlNewProp:
870 * @node: the holding node
871 * @name: the name of the attribute
872 * @value: the value of the attribute
873 *
874 * Create a new property carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000875 * Returns a pointer to the attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +0000876 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +0000877xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000878xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000879 xmlAttrPtr cur;
Daniel Veillarde4566462001-01-22 09:58:39 +0000880 xmlDocPtr doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000881
882 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000883#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000884 xmlGenericError(xmlGenericErrorContext,
885 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000886#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000887 return(NULL);
888 }
889
890 /*
891 * Allocate a new property and fill the fields.
892 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000893 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000894 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000895 xmlGenericError(xmlGenericErrorContext,
896 "xmlNewProp : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000897 return(NULL);
898 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000899 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillard33942841998-10-18 19:12:41 +0000900 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000901
902 cur->parent = node;
Daniel Veillarde4566462001-01-22 09:58:39 +0000903 if (node != NULL) {
904 doc = node->doc;
905 cur->doc = doc;
906 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000907 cur->name = xmlStrdup(name);
Daniel Veillard51e3b151999-11-12 17:02:31 +0000908 if (value != NULL) {
909 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +0000910 xmlNodePtr tmp;
911
Daniel Veillarde4566462001-01-22 09:58:39 +0000912 buffer = xmlEncodeEntitiesReentrant(doc, value);
913 cur->children = xmlStringGetNodeList(doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000914 cur->last = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +0000915 tmp = cur->children;
916 while (tmp != NULL) {
917 tmp->parent = (xmlNodePtr) cur;
Daniel Veillarde4566462001-01-22 09:58:39 +0000918 tmp->doc = doc;
Daniel Veillardcf461992000-03-14 18:30:20 +0000919 if (tmp->next == NULL)
920 cur->last = tmp;
921 tmp = tmp->next;
922 }
Daniel Veillard51e3b151999-11-12 17:02:31 +0000923 xmlFree(buffer);
924 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000925
926 /*
927 * Add it at the end to preserve parsing order ...
928 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000929 if (node != NULL) {
930 if (node->properties == NULL) {
931 node->properties = cur;
932 } else {
933 xmlAttrPtr prev = node->properties;
934
935 while (prev->next != NULL) prev = prev->next;
936 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000937 cur->prev = prev;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000938 }
939 }
940 return(cur);
941}
942
943/**
944 * xmlNewNsProp:
945 * @node: the holding node
946 * @ns: the namespace
947 * @name: the name of the attribute
948 * @value: the value of the attribute
949 *
950 * Create a new property tagged with a namespace and carried by a node.
951 * Returns a pointer to the attribute
952 */
953xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000954xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
955 const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000956 xmlAttrPtr cur;
957
958 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000959#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000960 xmlGenericError(xmlGenericErrorContext,
961 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +0000962#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +0000963 return(NULL);
964 }
965
966 /*
967 * Allocate a new property and fill the fields.
968 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000969 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000970 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000971 xmlGenericError(xmlGenericErrorContext,
972 "xmlNewProp : malloc failed\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +0000973 return(NULL);
974 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000975 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000976 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +0000977
978 cur->parent = node;
979 if (node != NULL)
980 cur->doc = node->doc;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000981 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000982 cur->name = xmlStrdup(name);
Daniel Veillardcf461992000-03-14 18:30:20 +0000983 if (value != NULL) {
984 xmlChar *buffer;
985 xmlNodePtr tmp;
986
987 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
988 cur->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000989 cur->last = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +0000990 tmp = cur->children;
991 while (tmp != NULL) {
992 tmp->parent = (xmlNodePtr) cur;
993 if (tmp->next == NULL)
994 cur->last = tmp;
995 tmp = tmp->next;
996 }
997 xmlFree(buffer);
998 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000999
1000 /*
1001 * Add it at the end to preserve parsing order ...
1002 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00001003 if (node != NULL) {
1004 if (node->properties == NULL) {
1005 node->properties = cur;
1006 } else {
1007 xmlAttrPtr prev = node->properties;
1008
1009 while (prev->next != NULL) prev = prev->next;
1010 prev->next = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00001011 cur->prev = prev;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001012 }
1013 }
1014 return(cur);
1015}
1016
Daniel Veillard97b58771998-10-20 06:14:16 +00001017/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001018 * xmlNewDocProp:
1019 * @doc: the document
1020 * @name: the name of the attribute
1021 * @value: the value of the attribute
1022 *
1023 * Create a new property carried by a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001024 * Returns a pointer to the attribute
Daniel Veillardccb09631998-10-27 06:21:04 +00001025 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001026xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001027xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001028 xmlAttrPtr cur;
1029
1030 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001031#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001032 xmlGenericError(xmlGenericErrorContext,
1033 "xmlNewProp : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001034#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00001035 return(NULL);
1036 }
1037
1038 /*
1039 * Allocate a new property and fill the fields.
1040 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001041 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001042 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001043 xmlGenericError(xmlGenericErrorContext,
1044 "xmlNewProp : malloc failed\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00001045 return(NULL);
1046 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001047 memset(cur, 0, sizeof(xmlAttr));
Daniel Veillardccb09631998-10-27 06:21:04 +00001048 cur->type = XML_ATTRIBUTE_NODE;
Daniel Veillardccb09631998-10-27 06:21:04 +00001049
Daniel Veillardcf461992000-03-14 18:30:20 +00001050 cur->name = xmlStrdup(name);
1051 cur->doc = doc;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001052 if (value != NULL) {
1053 xmlNodePtr tmp;
1054
Daniel Veillardcf461992000-03-14 18:30:20 +00001055 cur->children = xmlStringGetNodeList(doc, value);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001056 cur->last = NULL;
1057
1058 tmp = cur->children;
1059 while (tmp != NULL) {
1060 tmp->parent = (xmlNodePtr) cur;
1061 if (tmp->next == NULL)
1062 cur->last = tmp;
1063 tmp = tmp->next;
1064 }
1065 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001066 return(cur);
1067}
1068
1069/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001070 * xmlFreePropList:
1071 * @cur: the first property in the list
1072 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001073 * Free a property and all its siblings, all the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001074 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001075void
1076xmlFreePropList(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001077 xmlAttrPtr next;
1078 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001079#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001080 xmlGenericError(xmlGenericErrorContext,
1081 "xmlFreePropList : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001082#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001083 return;
1084 }
1085 while (cur != NULL) {
1086 next = cur->next;
1087 xmlFreeProp(cur);
1088 cur = next;
1089 }
1090}
1091
Daniel Veillard97b58771998-10-20 06:14:16 +00001092/**
1093 * xmlFreeProp:
Daniel Veillard686d6b62000-01-03 11:08:02 +00001094 * @cur: an attribute
Daniel Veillard97b58771998-10-20 06:14:16 +00001095 *
Daniel Veillard686d6b62000-01-03 11:08:02 +00001096 * Free one attribute, all the content is freed too
Daniel Veillard260a68f1998-08-13 03:39:55 +00001097 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001098void
1099xmlFreeProp(xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001100 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001101#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001102 xmlGenericError(xmlGenericErrorContext,
1103 "xmlFreeProp : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001104#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001105 return;
1106 }
Daniel Veillard71b656e2000-01-05 14:46:17 +00001107 /* Check for ID removal -> leading to invalid references ! */
Daniel Veillardcf461992000-03-14 18:30:20 +00001108 if ((cur->parent != NULL) &&
1109 (xmlIsID(cur->parent->doc, cur->parent, cur)))
1110 xmlRemoveID(cur->parent->doc, cur);
Daniel Veillard6454aec1999-09-02 22:04:43 +00001111 if (cur->name != NULL) xmlFree((char *) cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001112 if (cur->children != NULL) xmlFreeNodeList(cur->children);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001113 memset(cur, -1, sizeof(xmlAttr));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001114 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001115}
1116
Daniel Veillard97b58771998-10-20 06:14:16 +00001117/**
Daniel Veillard686d6b62000-01-03 11:08:02 +00001118 * xmlRemoveProp:
1119 * @cur: an attribute
1120 *
1121 * Unlink and free one attribute, all the content is freed too
1122 * Note this doesn't work for namespace definition attributes
1123 *
1124 * Returns 0 if success and -1 in case of error.
1125 */
1126int
1127xmlRemoveProp(xmlAttrPtr cur) {
1128 xmlAttrPtr tmp;
1129 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001130#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001131 xmlGenericError(xmlGenericErrorContext,
1132 "xmlRemoveProp : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001133#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001134 return(-1);
1135 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001136 if (cur->parent == NULL) {
1137#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001138 xmlGenericError(xmlGenericErrorContext,
1139 "xmlRemoveProp : cur->parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001140#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001141 return(-1);
1142 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001143 tmp = cur->parent->properties;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001144 if (tmp == cur) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001145 cur->parent->properties = cur->next;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001146 xmlFreeProp(cur);
1147 return(0);
1148 }
1149 while (tmp != NULL) {
1150 if (tmp->next == cur) {
1151 tmp->next = cur->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00001152 if (tmp->next != NULL)
1153 tmp->next->prev = tmp;
Daniel Veillard686d6b62000-01-03 11:08:02 +00001154 xmlFreeProp(cur);
1155 return(0);
1156 }
1157 tmp = tmp->next;
1158 }
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001159#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001160 xmlGenericError(xmlGenericErrorContext,
1161 "xmlRemoveProp : attribute not owned by its node\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001162#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001163 return(-1);
1164}
1165
1166/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001167 * xmlNewPI:
1168 * @name: the processing instruction name
1169 * @content: the PI content
1170 *
1171 * Creation of a processing instruction element.
1172 * Returns a pointer to the new node object.
1173 */
1174xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001175xmlNewPI(const xmlChar *name, const xmlChar *content) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001176 xmlNodePtr cur;
1177
1178 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001179#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001180 xmlGenericError(xmlGenericErrorContext,
1181 "xmlNewPI : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001182#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001183 return(NULL);
1184 }
1185
1186 /*
1187 * Allocate a new node and fill the fields.
1188 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001189 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001190 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001191 xmlGenericError(xmlGenericErrorContext,
1192 "xmlNewPI : malloc failed\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00001193 return(NULL);
1194 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001195 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001196 cur->type = XML_PI_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001197
Daniel Veillardb96e6431999-08-29 21:02:19 +00001198 cur->name = xmlStrdup(name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001199 if (content != NULL) {
1200#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00001201 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001202#else
1203 cur->content = xmlBufferCreateSize(0);
1204 xmlBufferSetAllocationScheme(cur->content,
1205 xmlGetBufferAllocationScheme());
1206 xmlBufferAdd(cur->content, content, -1);
1207#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001208 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001209 return(cur);
1210}
1211
1212/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001213 * xmlNewNode:
1214 * @ns: namespace if any
1215 * @name: the node name
Daniel Veillard97b58771998-10-20 06:14:16 +00001216 *
Daniel Veillarde0854c32000-08-27 21:12:29 +00001217 * Creation of a new node element. @ns is optionnal (NULL).
1218 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001219 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001220 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001221xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001222xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001223 xmlNodePtr cur;
1224
1225 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001226#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001227 xmlGenericError(xmlGenericErrorContext,
1228 "xmlNewNode : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001229#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001230 return(NULL);
1231 }
1232
1233 /*
1234 * Allocate a new node and fill the fields.
1235 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001236 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001237 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001238 xmlGenericError(xmlGenericErrorContext,
1239 "xmlNewNode : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001240 return(NULL);
1241 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001242 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard33942841998-10-18 19:12:41 +00001243 cur->type = XML_ELEMENT_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001244
Daniel Veillard260a68f1998-08-13 03:39:55 +00001245 cur->name = xmlStrdup(name);
1246 cur->ns = ns;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001247 return(cur);
1248}
1249
Daniel Veillard97b58771998-10-20 06:14:16 +00001250/**
1251 * xmlNewDocNode:
1252 * @doc: the document
1253 * @ns: namespace if any
1254 * @name: the node name
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001255 * @content: the XML text content if any
Daniel Veillard97b58771998-10-20 06:14:16 +00001256 *
1257 * Creation of a new node element within a document. @ns and @content
1258 * are optionnal (NULL).
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001259 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1260 * references, but XML special chars need to be escaped first by using
1261 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
1262 * need entities support.
1263 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001264 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001265 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001266xmlNodePtr
1267xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001268 const xmlChar *name, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001269 xmlNodePtr cur;
1270
Daniel Veillardccb09631998-10-27 06:21:04 +00001271 cur = xmlNewNode(ns, name);
1272 if (cur != NULL) {
1273 cur->doc = doc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001274 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001275 cur->children = xmlStringGetNodeList(doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001276 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001277 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001278 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00001279 return(cur);
1280}
1281
1282
Daniel Veillard97b58771998-10-20 06:14:16 +00001283/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001284 * xmlNewDocRawNode:
1285 * @doc: the document
1286 * @ns: namespace if any
1287 * @name: the node name
1288 * @content: the text content if any
1289 *
1290 * Creation of a new node element within a document. @ns and @content
1291 * are optionnal (NULL).
1292 *
1293 * Returns a pointer to the new node object.
1294 */
1295xmlNodePtr
1296xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
1297 const xmlChar *name, const xmlChar *content) {
1298 xmlNodePtr cur;
1299
1300 cur = xmlNewNode(ns, name);
1301 if (cur != NULL) {
1302 cur->doc = doc;
1303 if (content != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001304 cur->children = xmlNewDocText(doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001305 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001306 }
1307 }
1308 return(cur);
1309}
1310
Daniel Veillard2eac5032000-01-09 21:08:56 +00001311/**
1312 * xmlNewDocFragment:
1313 * @doc: the document owning the fragment
1314 *
1315 * Creation of a new Fragment node.
1316 * Returns a pointer to the new node object.
1317 */
1318xmlNodePtr
1319xmlNewDocFragment(xmlDocPtr doc) {
1320 xmlNodePtr cur;
1321
1322 /*
1323 * Allocate a new DocumentFragment node and fill the fields.
1324 */
1325 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1326 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001327 xmlGenericError(xmlGenericErrorContext,
1328 "xmlNewDocFragment : malloc failed\n");
Daniel Veillard2eac5032000-01-09 21:08:56 +00001329 return(NULL);
1330 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001331 memset(cur, 0, sizeof(xmlNode));
Daniel Veillard2eac5032000-01-09 21:08:56 +00001332 cur->type = XML_DOCUMENT_FRAG_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001333
Daniel Veillard2eac5032000-01-09 21:08:56 +00001334 cur->doc = doc;
Daniel Veillard2eac5032000-01-09 21:08:56 +00001335 return(cur);
1336}
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001337
1338/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001339 * xmlNewText:
1340 * @content: the text content
1341 *
1342 * Creation of a new text node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001343 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001344 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001345xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001346xmlNewText(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001347 xmlNodePtr cur;
1348
1349 /*
1350 * Allocate a new node and fill the fields.
1351 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001352 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001353 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001354 xmlGenericError(xmlGenericErrorContext,
1355 "xmlNewText : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001356 return(NULL);
1357 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001358 memset(cur, 0, sizeof(xmlNode));
1359 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001360
Daniel Veillardf6eea272001-01-18 12:17:12 +00001361 cur->name = xmlStringText;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001362 if (content != NULL) {
1363#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001364 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001365#else
1366 cur->content = xmlBufferCreateSize(0);
1367 xmlBufferSetAllocationScheme(cur->content,
1368 xmlGetBufferAllocationScheme());
1369 xmlBufferAdd(cur->content, content, -1);
1370#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001371 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001372 return(cur);
1373}
1374
Daniel Veillard97b58771998-10-20 06:14:16 +00001375/**
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001376 * xmlNewTextChild:
1377 * @parent: the parent node
1378 * @ns: a namespace if any
1379 * @name: the name of the child
1380 * @content: the text content of the child if any.
1381 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001382 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001383 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1384 * a child TEXT node will be created containing the string content.
1385 *
1386 * Returns a pointer to the new node object.
1387 */
1388xmlNodePtr
1389xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
1390 const xmlChar *name, const xmlChar *content) {
1391 xmlNodePtr cur, prev;
1392
1393 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001394#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001395 xmlGenericError(xmlGenericErrorContext,
1396 "xmlNewTextChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001397#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001398 return(NULL);
1399 }
1400
1401 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001402#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001403 xmlGenericError(xmlGenericErrorContext,
1404 "xmlNewTextChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001405#endif
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001406 return(NULL);
1407 }
1408
1409 /*
1410 * Allocate a new node
1411 */
1412 if (ns == NULL)
1413 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
1414 else
1415 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
1416 if (cur == NULL) return(NULL);
1417
1418 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001419 * add the new element at the end of the children list.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001420 */
1421 cur->type = XML_ELEMENT_NODE;
1422 cur->parent = parent;
1423 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001424 if (parent->children == NULL) {
1425 parent->children = cur;
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001426 parent->last = cur;
1427 } else {
1428 prev = parent->last;
1429 prev->next = cur;
1430 cur->prev = prev;
1431 parent->last = cur;
1432 }
1433
1434 return(cur);
1435}
1436
1437/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001438 * xmlNewCharRef:
1439 * @doc: the document
1440 * @name: the char ref string, starting with # or "&# ... ;"
1441 *
1442 * Creation of a new character reference node.
1443 * Returns a pointer to the new node object.
1444 */
1445xmlNodePtr
1446xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
1447 xmlNodePtr cur;
1448
1449 /*
1450 * Allocate a new node and fill the fields.
1451 */
1452 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
1453 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001454 xmlGenericError(xmlGenericErrorContext,
1455 "xmlNewText : malloc failed\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00001456 return(NULL);
1457 }
1458 memset(cur, 0, sizeof(xmlNode));
1459 cur->type = XML_ENTITY_REF_NODE;
1460
1461 cur->doc = doc;
1462 if (name[0] == '&') {
1463 int len;
1464 name++;
1465 len = xmlStrlen(name);
1466 if (name[len - 1] == ';')
1467 cur->name = xmlStrndup(name, len - 1);
1468 else
1469 cur->name = xmlStrndup(name, len);
1470 } else
1471 cur->name = xmlStrdup(name);
1472 return(cur);
1473}
1474
1475/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001476 * xmlNewReference:
1477 * @doc: the document
1478 * @name: the reference name, or the reference string with & and ;
1479 *
1480 * Creation of a new reference node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001481 * Returns a pointer to the new node object.
Daniel Veillardccb09631998-10-27 06:21:04 +00001482 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001483xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001484xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +00001485 xmlNodePtr cur;
1486 xmlEntityPtr ent;
1487
1488 /*
1489 * Allocate a new node and fill the fields.
1490 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001491 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001492 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001493 xmlGenericError(xmlGenericErrorContext,
1494 "xmlNewText : malloc failed\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00001495 return(NULL);
1496 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001497 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardccb09631998-10-27 06:21:04 +00001498 cur->type = XML_ENTITY_REF_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001499
Daniel Veillard10c6a8f1998-10-28 01:00:12 +00001500 cur->doc = doc;
Daniel Veillardccb09631998-10-27 06:21:04 +00001501 if (name[0] == '&') {
1502 int len;
1503 name++;
1504 len = xmlStrlen(name);
1505 if (name[len - 1] == ';')
1506 cur->name = xmlStrndup(name, len - 1);
1507 else
1508 cur->name = xmlStrndup(name, len);
1509 } else
1510 cur->name = xmlStrdup(name);
Daniel Veillardccb09631998-10-27 06:21:04 +00001511
1512 ent = xmlGetDocEntity(doc, cur->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001513 if (ent != NULL) {
1514#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00001515 cur->content = ent->content;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001516#else
1517 /*
1518 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
1519 * a copy of this pointer. Let's hope we don't manipulate it
1520 * later
1521 */
1522 cur->content = xmlBufferCreateSize(0);
1523 xmlBufferSetAllocationScheme(cur->content,
1524 xmlGetBufferAllocationScheme());
1525 if (ent->content != NULL)
1526 xmlBufferAdd(cur->content, ent->content, -1);
1527#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001528 /*
1529 * The parent pointer in entity is a Dtd pointer and thus is NOT
1530 * updated. Not sure if this is 100% correct.
1531 * -George
1532 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001533 cur->children = (xmlNodePtr) ent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001534 cur->last = (xmlNodePtr) ent;
Daniel Veillardcf461992000-03-14 18:30:20 +00001535 }
Daniel Veillardccb09631998-10-27 06:21:04 +00001536 return(cur);
1537}
1538
1539/**
Daniel Veillard97b58771998-10-20 06:14:16 +00001540 * xmlNewDocText:
1541 * @doc: the document
1542 * @content: the text content
1543 *
1544 * Creation of a new text node within a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001545 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001546 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001547xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001548xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001549 xmlNodePtr cur;
1550
1551 cur = xmlNewText(content);
1552 if (cur != NULL) cur->doc = doc;
1553 return(cur);
1554}
1555
Daniel Veillard97b58771998-10-20 06:14:16 +00001556/**
Daniel Veillardccb09631998-10-27 06:21:04 +00001557 * xmlNewTextLen:
Daniel Veillard97b58771998-10-20 06:14:16 +00001558 * @content: the text content
1559 * @len: the text len.
1560 *
1561 * Creation of a new text node with an extra parameter for the content's lenght
Daniel Veillard1e346af1999-02-22 10:33:01 +00001562 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001563 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001564xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001565xmlNewTextLen(const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001566 xmlNodePtr cur;
1567
1568 /*
1569 * Allocate a new node and fill the fields.
1570 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001571 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001572 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001573 xmlGenericError(xmlGenericErrorContext,
1574 "xmlNewText : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001575 return(NULL);
1576 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001577 memset(cur, 0, sizeof(xmlNode));
1578 cur->type = XML_TEXT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001579
Daniel Veillardf6eea272001-01-18 12:17:12 +00001580 cur->name = xmlStringText;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001581 if (content != NULL) {
1582#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001583 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001584#else
1585 cur->content = xmlBufferCreateSize(len);
1586 xmlBufferSetAllocationScheme(cur->content,
1587 xmlGetBufferAllocationScheme());
1588 xmlBufferAdd(cur->content, content, len);
1589#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001590 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001591 return(cur);
1592}
1593
Daniel Veillard97b58771998-10-20 06:14:16 +00001594/**
1595 * xmlNewDocTextLen:
1596 * @doc: the document
1597 * @content: the text content
1598 * @len: the text len.
1599 *
1600 * Creation of a new text node with an extra content lenght parameter. The
1601 * text node pertain to a given document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001602 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001603 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001604xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001605xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001606 xmlNodePtr cur;
1607
1608 cur = xmlNewTextLen(content, len);
1609 if (cur != NULL) cur->doc = doc;
1610 return(cur);
1611}
1612
Daniel Veillard97b58771998-10-20 06:14:16 +00001613/**
1614 * xmlNewComment:
1615 * @content: the comment content
1616 *
1617 * Creation of a new node containing a comment.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001618 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001619 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001620xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001621xmlNewComment(const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001622 xmlNodePtr cur;
1623
1624 /*
1625 * Allocate a new node and fill the fields.
1626 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001627 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001628 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001629 xmlGenericError(xmlGenericErrorContext,
1630 "xmlNewComment : malloc failed\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001631 return(NULL);
1632 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001633 memset(cur, 0, sizeof(xmlNode));
1634 cur->type = XML_COMMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001635
Daniel Veillardf6eea272001-01-18 12:17:12 +00001636 cur->name = xmlStringComment;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001637 if (content != NULL) {
1638#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00001639 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001640#else
1641 cur->content = xmlBufferCreateSize(0);
1642 xmlBufferSetAllocationScheme(cur->content,
1643 xmlGetBufferAllocationScheme());
1644 xmlBufferAdd(cur->content, content, -1);
1645#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001646 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001647 return(cur);
1648}
1649
Daniel Veillard97b58771998-10-20 06:14:16 +00001650/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001651 * xmlNewCDataBlock:
1652 * @doc: the document
1653 * @content: the CData block content content
1654 * @len: the length of the block
1655 *
1656 * Creation of a new node containing a CData block.
1657 * Returns a pointer to the new node object.
1658 */
1659xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001660xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001661 xmlNodePtr cur;
1662
1663 /*
1664 * Allocate a new node and fill the fields.
1665 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00001666 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001667 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001668 xmlGenericError(xmlGenericErrorContext,
1669 "xmlNewCDataBlock : malloc failed\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +00001670 return(NULL);
1671 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001672 memset(cur, 0, sizeof(xmlNode));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001673 cur->type = XML_CDATA_SECTION_NODE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001674
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001675 if (content != NULL) {
1676#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00001677 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00001678#else
1679 cur->content = xmlBufferCreateSize(len);
1680 xmlBufferSetAllocationScheme(cur->content,
1681 xmlGetBufferAllocationScheme());
1682 xmlBufferAdd(cur->content, content, len);
1683#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001684 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001685 return(cur);
1686}
1687
1688/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001689 * xmlNewDocComment:
Daniel Veillard97b58771998-10-20 06:14:16 +00001690 * @doc: the document
1691 * @content: the comment content
1692 *
1693 * Creation of a new node containing a commentwithin a document.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001694 * Returns a pointer to the new node object.
Daniel Veillard97b58771998-10-20 06:14:16 +00001695 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001696xmlNodePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001697xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
Daniel Veillard0bef1311998-10-14 02:36:47 +00001698 xmlNodePtr cur;
1699
1700 cur = xmlNewComment(content);
1701 if (cur != NULL) cur->doc = doc;
1702 return(cur);
1703}
1704
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001705/**
1706 * xmlSetTreeDoc:
1707 * @tree: the top element
1708 * @doc: the document
1709 *
1710 * update all nodes under the tree to point to the right document
1711 */
1712void
1713xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
1714 if (tree == NULL)
1715 return;
1716 if (tree->type == XML_ENTITY_DECL)
1717 return;
1718 if (tree->doc != doc) {
1719 if (tree->children != NULL)
1720 xmlSetListDoc(tree->children, doc);
1721 tree->doc = doc;
1722 }
1723}
1724
1725/**
1726 * xmlSetListDoc:
1727 * @tree: the first element
1728 * @doc: the document
1729 *
1730 * update all nodes in the list to point to the right document
1731 */
1732void
1733xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
1734 xmlNodePtr cur;
1735
1736 if (list == NULL)
1737 return;
1738 cur = list;
1739 while (cur != NULL) {
1740 if (cur->doc != doc)
1741 xmlSetTreeDoc(cur, doc);
1742 cur = cur->next;
1743 }
1744}
1745
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001746
Daniel Veillard97b58771998-10-20 06:14:16 +00001747/**
1748 * xmlNewChild:
1749 * @parent: the parent node
1750 * @ns: a namespace if any
1751 * @name: the name of the child
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001752 * @content: the XML content of the child if any.
Daniel Veillard97b58771998-10-20 06:14:16 +00001753 *
Daniel Veillardcf461992000-03-14 18:30:20 +00001754 * Creation of a new child element, added at the end of @parent children list.
Daniel Veillardccb09631998-10-27 06:21:04 +00001755 * @ns and @content parameters are optionnal (NULL). If content is non NULL,
1756 * a child list containing the TEXTs and ENTITY_REFs node will be created.
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001757 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
1758 * references, but XML special chars need to be escaped first by using
1759 * xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
1760 * support is not needed.
1761 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001762 * Returns a pointer to the new node object.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001763 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00001764xmlNodePtr
1765xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
Daniel Veillard11a48ec1999-11-23 10:40:46 +00001766 const xmlChar *name, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001767 xmlNodePtr cur, prev;
1768
1769 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001770#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001771 xmlGenericError(xmlGenericErrorContext,
1772 "xmlNewChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001773#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001774 return(NULL);
1775 }
1776
1777 if (name == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001778#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001779 xmlGenericError(xmlGenericErrorContext,
1780 "xmlNewChild : name == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001781#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001782 return(NULL);
1783 }
1784
1785 /*
1786 * Allocate a new node
1787 */
1788 if (ns == NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00001789 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001790 else
Daniel Veillardccb09631998-10-27 06:21:04 +00001791 cur = xmlNewDocNode(parent->doc, ns, name, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001792 if (cur == NULL) return(NULL);
1793
1794 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00001795 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001796 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001797 cur->type = XML_ELEMENT_NODE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001798 cur->parent = parent;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001799 cur->doc = parent->doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00001800 if (parent->children == NULL) {
1801 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001802 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001803 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001804 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001805 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00001806 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001807 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001808 }
1809
1810 return(cur);
1811}
1812
Daniel Veillard97b58771998-10-20 06:14:16 +00001813/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001814 * xmlAddNextSibling:
1815 * @cur: the child node
1816 * @elem: the new node
1817 *
1818 * Add a new element @elem as the next siblings of @cur
1819 * If the new element was already inserted in a document it is
1820 * first unlinked from its existing context.
Daniel Veillard683cb022000-10-22 12:04:13 +00001821 * As a result of text merging @elem may be freed.
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001822 *
1823 * Returns the new element or NULL in case of error.
1824 */
1825xmlNodePtr
1826xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
1827 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001828#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001829 xmlGenericError(xmlGenericErrorContext,
1830 "xmlAddNextSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001831#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001832 return(NULL);
1833 }
1834 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001835#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001836 xmlGenericError(xmlGenericErrorContext,
1837 "xmlAddNextSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001838#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001839 return(NULL);
1840 }
1841
1842 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00001843
1844 if (elem->type == XML_TEXT_NODE) {
1845 if (cur->type == XML_TEXT_NODE) {
1846#ifndef XML_USE_BUFFER_CONTENT
1847 xmlNodeAddContent(cur, elem->content);
1848#else
1849 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
1850#endif
1851 xmlFreeNode(elem);
1852 return(cur);
1853 }
1854 if ((cur->next != NULL) && (cur->type == XML_TEXT_NODE)) {
1855#ifndef XML_USE_BUFFER_CONTENT
1856 xmlChar *tmp;
1857
1858 tmp = xmlStrdup(elem->content);
1859 tmp = xmlStrcat(tmp, cur->next->content);
1860 xmlNodeSetContent(cur->next, tmp);
1861 xmlFree(tmp);
1862#else
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001863 xmlBufferAddHead(cur->next->content,
1864 xmlBufferContent(elem->content),
Daniel Veillard683cb022000-10-22 12:04:13 +00001865 xmlBufferLength(elem->content));
1866#endif
1867 xmlFreeNode(elem);
1868 return(cur->next);
1869 }
1870 }
1871
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001872 if (elem->doc != cur->doc) {
1873 xmlSetTreeDoc(elem, cur->doc);
1874 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001875 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001876 elem->prev = cur;
1877 elem->next = cur->next;
1878 cur->next = elem;
1879 if (elem->next != NULL)
1880 elem->next->prev = elem;
1881 if ((elem->parent != NULL) && (elem->parent->last == cur))
1882 elem->parent->last = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001883 return(elem);
1884}
1885
1886/**
1887 * xmlAddPrevSibling:
1888 * @cur: the child node
1889 * @elem: the new node
1890 *
1891 * Add a new element @elem as the previous siblings of @cur
Daniel Veillard683cb022000-10-22 12:04:13 +00001892 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001893 * If the new element was already inserted in a document it is
1894 * first unlinked from its existing context.
1895 *
1896 * Returns the new element or NULL in case of error.
1897 */
1898xmlNodePtr
1899xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
1900 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001901#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001902 xmlGenericError(xmlGenericErrorContext,
1903 "xmlAddPrevSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001904#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001905 return(NULL);
1906 }
1907 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001908#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001909 xmlGenericError(xmlGenericErrorContext,
1910 "xmlAddPrevSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001911#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001912 return(NULL);
1913 }
1914
1915 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00001916
1917 if (elem->type == XML_TEXT_NODE) {
1918 if (cur->type == XML_TEXT_NODE) {
1919#ifndef XML_USE_BUFFER_CONTENT
1920 xmlChar *tmp;
1921
1922 tmp = xmlStrdup(elem->content);
1923 tmp = xmlStrcat(tmp, cur->content);
1924 xmlNodeSetContent(cur, tmp);
1925 xmlFree(tmp);
1926#else
1927 xmlBufferAddHead(cur->content, xmlBufferContent(elem->content),
1928 xmlBufferLength(elem->content));
1929#endif
1930 xmlFreeNode(elem);
1931 return(cur);
1932 }
1933 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE)) {
1934#ifndef XML_USE_BUFFER_CONTENT
1935 xmlNodeAddContent(cur->prev, elem->content);
1936#else
1937 xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
1938#endif
1939 xmlFreeNode(elem);
1940 return(cur->prev);
1941 }
1942 }
1943
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001944 if (elem->doc != cur->doc) {
1945 xmlSetTreeDoc(elem, cur->doc);
1946 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001947 elem->parent = cur->parent;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001948 elem->next = cur;
1949 elem->prev = cur->prev;
1950 cur->prev = elem;
1951 if (elem->prev != NULL)
1952 elem->prev->next = elem;
1953 if ((elem->parent != NULL) && (elem->parent->children == cur))
1954 elem->parent->children = elem;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001955 return(elem);
1956}
1957
1958/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001959 * xmlAddSibling:
1960 * @cur: the child node
1961 * @elem: the new node
1962 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001963 * Add a new element @elem to the list of siblings of @cur
Daniel Veillard683cb022000-10-22 12:04:13 +00001964 * merging adjacent TEXT nodes (@elem may be freed)
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001965 * If the new element was already inserted in a document it is
1966 * first unlinked from its existing context.
1967 *
1968 * Returns the new element or NULL in case of error.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001969 */
1970xmlNodePtr
1971xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
1972 xmlNodePtr parent;
1973
1974 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001975#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001976 xmlGenericError(xmlGenericErrorContext,
1977 "xmlAddSibling : cur == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001978#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001979 return(NULL);
1980 }
1981
1982 if (elem == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001983#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001984 xmlGenericError(xmlGenericErrorContext,
1985 "xmlAddSibling : elem == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00001986#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001987 return(NULL);
1988 }
1989
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001990 /*
1991 * Constant time is we can rely on the ->parent->last to find
1992 * the last sibling.
1993 */
1994 if ((cur->parent != NULL) &&
Daniel Veillardcf461992000-03-14 18:30:20 +00001995 (cur->parent->children != NULL) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00001996 (cur->parent->last != NULL) &&
1997 (cur->parent->last->next == NULL)) {
1998 cur = cur->parent->last;
1999 } else {
2000 while (cur->next != NULL) cur = cur->next;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002001 }
2002
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002003 xmlUnlinkNode(elem);
Daniel Veillard683cb022000-10-22 12:04:13 +00002004
2005 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
2006#ifndef XML_USE_BUFFER_CONTENT
2007 xmlNodeAddContent(cur, elem->content);
2008#else
2009 xmlNodeAddContent(cur, xmlBufferContent(elem->content));
2010#endif
2011 xmlFreeNode(elem);
2012 return(cur);
2013 }
2014
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002015 if (elem->doc != cur->doc) {
2016 xmlSetTreeDoc(elem, cur->doc);
2017 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002018 parent = cur->parent;
2019 elem->prev = cur;
2020 elem->next = NULL;
2021 elem->parent = parent;
2022 cur->next = elem;
2023 if (parent != NULL)
2024 parent->last = elem;
2025
2026 return(elem);
2027}
2028
2029/**
Daniel Veillard87b95392000-08-12 21:12:04 +00002030 * xmlAddChildList:
2031 * @parent: the parent node
2032 * @cur: the first node in the list
2033 *
2034 * Add a list of node at the end of the child list of the parent
Daniel Veillard683cb022000-10-22 12:04:13 +00002035 * merging adjacent TEXT nodes (@cur may be freed)
Daniel Veillard87b95392000-08-12 21:12:04 +00002036 *
2037 * Returns the last child or NULL in case of error.
2038 */
2039xmlNodePtr
2040xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
2041 xmlNodePtr prev;
2042
2043 if (parent == NULL) {
2044#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002045 xmlGenericError(xmlGenericErrorContext,
2046 "xmlAddChild : parent == NULL\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002047#endif
2048 return(NULL);
2049 }
2050
2051 if (cur == NULL) {
2052#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002053 xmlGenericError(xmlGenericErrorContext,
2054 "xmlAddChild : child == NULL\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002055#endif
2056 return(NULL);
2057 }
2058
2059 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2060 (cur->doc != parent->doc)) {
2061#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002062 xmlGenericError(xmlGenericErrorContext,
2063 "Elements moved to a different document\n");
Daniel Veillard87b95392000-08-12 21:12:04 +00002064#endif
2065 }
2066
2067 /*
2068 * add the first element at the end of the children list.
2069 */
2070 if (parent->children == NULL) {
2071 parent->children = cur;
2072 } else {
Daniel Veillard683cb022000-10-22 12:04:13 +00002073 /*
2074 * If cur and parent->last both are TEXT nodes, then merge them.
2075 */
2076 if ((cur->type == XML_TEXT_NODE) &&
Daniel Veillard5dd2f0a2001-02-12 17:36:05 +00002077 (parent->last->type == XML_TEXT_NODE) &&
2078 (cur->name == parent->last->name)) {
Daniel Veillard683cb022000-10-22 12:04:13 +00002079#ifndef XML_USE_BUFFER_CONTENT
2080 xmlNodeAddContent(parent->last, cur->content);
2081#else
2082 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2083#endif
2084 /*
2085 * if it's the only child, nothing more to be done.
2086 */
2087 if (cur->next == NULL) {
2088 xmlFreeNode(cur);
2089 return(parent->last);
2090 }
2091 prev = cur;
2092 cur = cur->next;
2093 xmlFreeNode(prev);
2094 }
Daniel Veillard87b95392000-08-12 21:12:04 +00002095 prev = parent->last;
2096 prev->next = cur;
2097 cur->prev = prev;
2098 }
2099 while (cur->next != NULL) {
2100 cur->parent = parent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002101 if (cur->doc != parent->doc) {
2102 xmlSetTreeDoc(cur, parent->doc);
2103 }
Daniel Veillard87b95392000-08-12 21:12:04 +00002104 cur = cur->next;
2105 }
2106 cur->parent = parent;
2107 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2108 parent->last = cur;
2109
2110 return(cur);
2111}
2112
2113/**
Daniel Veillard97b58771998-10-20 06:14:16 +00002114 * xmlAddChild:
2115 * @parent: the parent node
2116 * @cur: the child node
2117 *
Daniel Veillard683cb022000-10-22 12:04:13 +00002118 * Add a new child element, to @parent, at the end of the child list
2119 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillard1e346af1999-02-22 10:33:01 +00002120 * Returns the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002121 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002122xmlNodePtr
2123xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002124 xmlNodePtr prev;
2125
2126 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002127#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002128 xmlGenericError(xmlGenericErrorContext,
2129 "xmlAddChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002130#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002131 return(NULL);
2132 }
2133
2134 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002135#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002136 xmlGenericError(xmlGenericErrorContext,
2137 "xmlAddChild : child == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002138#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002139 return(NULL);
2140 }
2141
Daniel Veillard0bef1311998-10-14 02:36:47 +00002142 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2143 (cur->doc != parent->doc)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002144#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002145 xmlGenericError(xmlGenericErrorContext,
2146 "Elements moved to a different document\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002147#endif
Daniel Veillard0bef1311998-10-14 02:36:47 +00002148 }
2149
Daniel Veillard260a68f1998-08-13 03:39:55 +00002150 /*
Daniel Veillard683cb022000-10-22 12:04:13 +00002151 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
2152 * or with parent->content if parent->content != NULL.
2153 * cur is then freed.
2154 */
2155 if (cur->type == XML_TEXT_NODE) {
2156 if (((parent->type == XML_ELEMENT_NODE) ||
2157 (parent->type == XML_TEXT_NODE)) &&
2158 (parent->content != NULL)) {
2159#ifndef XML_USE_BUFFER_CONTENT
2160 xmlNodeAddContent(parent, cur->content);
2161#else
2162 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2163#endif
2164 xmlFreeNode(cur);
2165 return(parent);
2166 }
Daniel Veillard5dd2f0a2001-02-12 17:36:05 +00002167 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
2168 (parent->last->name == cur->name)) {
Daniel Veillard683cb022000-10-22 12:04:13 +00002169#ifndef XML_USE_BUFFER_CONTENT
2170 xmlNodeAddContent(parent->last, cur->content);
2171#else
2172 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2173#endif
2174 xmlFreeNode(cur);
2175 return(parent->last);
2176 }
2177 }
2178
2179 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00002180 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002181 */
2182 cur->parent = parent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002183 if (cur->doc != parent->doc) {
2184 xmlSetTreeDoc(cur, parent->doc);
2185 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002186
Daniel Veillardccb09631998-10-27 06:21:04 +00002187 /*
2188 * Handle the case where parent->content != NULL, in that case it will
2189 * create a intermediate TEXT node.
2190 */
Daniel Veillardcf461992000-03-14 18:30:20 +00002191 if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
2192 (parent->content != NULL)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002193 xmlNodePtr text;
2194
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002195#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00002196 text = xmlNewDocText(parent->doc, parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002197#else
2198 text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
2199#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002200 if (text != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002201 text->next = parent->children;
Daniel Veillardccb09631998-10-27 06:21:04 +00002202 if (text->next != NULL)
2203 text->next->prev = text;
Daniel Veillardcf461992000-03-14 18:30:20 +00002204 parent->children = text;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002205 UPDATE_LAST_CHILD_AND_PARENT(parent)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002206#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002207 xmlFree(parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002208#else
2209 xmlBufferFree(parent->content);
2210#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002211 parent->content = NULL;
2212 }
2213 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002214 if (parent->children == NULL) {
2215 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002216 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002217 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002218 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002219 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00002220 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002221 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002222 }
2223
2224 return(cur);
2225}
2226
Daniel Veillard97b58771998-10-20 06:14:16 +00002227/**
2228 * xmlGetLastChild:
2229 * @parent: the parent node
2230 *
2231 * Search the last child of a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002232 * Returns the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002233 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002234xmlNodePtr
2235xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002236 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002237#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002238 xmlGenericError(xmlGenericErrorContext,
2239 "xmlGetLastChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002240#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002241 return(NULL);
2242 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002243 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002244}
2245
Daniel Veillard97b58771998-10-20 06:14:16 +00002246/**
2247 * xmlFreeNodeList:
2248 * @cur: the first node in the list
2249 *
2250 * Free a node and all its siblings, this is a recursive behaviour, all
Daniel Veillardcf461992000-03-14 18:30:20 +00002251 * the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002252 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002253void
2254xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002255 xmlNodePtr next;
2256 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002257#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002258 xmlGenericError(xmlGenericErrorContext,
2259 "xmlFreeNodeList : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002260#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002261 return;
2262 }
2263 while (cur != NULL) {
2264 next = cur->next;
2265 xmlFreeNode(cur);
2266 cur = next;
2267 }
2268}
2269
Daniel Veillard97b58771998-10-20 06:14:16 +00002270/**
2271 * xmlFreeNode:
2272 * @cur: the node
2273 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002274 * Free a node, this is a recursive behaviour, all the children are freed too.
2275 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002276 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002277void
2278xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002279 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002280#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002281 xmlGenericError(xmlGenericErrorContext,
2282 "xmlFreeNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002283#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002284 return;
2285 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002286 if (cur->type == XML_DTD_NODE)
2287 return;
Daniel Veillardccb09631998-10-27 06:21:04 +00002288 cur->doc = NULL;
2289 cur->parent = NULL;
2290 cur->next = NULL;
2291 cur->prev = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002292 if ((cur->children != NULL) &&
2293 (cur->type != XML_ENTITY_REF_NODE))
2294 xmlFreeNodeList(cur->children);
Daniel Veillardccb09631998-10-27 06:21:04 +00002295 if (cur->properties != NULL) xmlFreePropList(cur->properties);
2296 if (cur->type != XML_ENTITY_REF_NODE)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002297#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002298 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002299#else
2300 if (cur->content != NULL) xmlBufferFree(cur->content);
2301#endif
Daniel Veillardf6eea272001-01-18 12:17:12 +00002302 if ((cur->name != NULL) &&
2303 (cur->name != xmlStringText) &&
2304 (cur->name != xmlStringTextNoenc) &&
2305 (cur->name != xmlStringComment))
2306 xmlFree((char *) cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002307 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
2308 memset(cur, -1, sizeof(xmlNode));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002309 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002310}
2311
Daniel Veillard16253641998-10-28 22:58:05 +00002312/**
2313 * xmlUnlinkNode:
2314 * @cur: the node
2315 *
2316 * Unlink a node from it's current context, the node is not freed
2317 */
2318void
2319xmlUnlinkNode(xmlNodePtr cur) {
2320 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002321#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002322 xmlGenericError(xmlGenericErrorContext,
2323 "xmlUnlinkNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002324#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002325 return;
2326 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002327 if ((cur->parent != NULL) && (cur->parent->children == cur))
2328 cur->parent->children = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002329 if ((cur->parent != NULL) && (cur->parent->last == cur))
2330 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00002331 if (cur->next != NULL)
2332 cur->next->prev = cur->prev;
2333 if (cur->prev != NULL)
2334 cur->prev->next = cur->next;
2335 cur->next = cur->prev = NULL;
2336 cur->parent = NULL;
2337}
2338
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002339/**
2340 * xmlReplaceNode:
2341 * @old: the old node
2342 * @cur: the node
2343 *
2344 * Unlink the old node from it's current context, prune the new one
2345 * at the same place. If cur was already inserted in a document it is
2346 * first unlinked from its existing context.
2347 *
2348 * Returns the old node
2349 */
2350xmlNodePtr
2351xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2352 if (old == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002353#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002354 xmlGenericError(xmlGenericErrorContext,
2355 "xmlReplaceNode : old == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002356#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002357 return(NULL);
2358 }
2359 if (cur == NULL) {
2360 xmlUnlinkNode(old);
2361 return(old);
2362 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002363 if (cur == old) {
2364 return(old);
2365 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002366 xmlUnlinkNode(cur);
2367 cur->doc = old->doc;
2368 cur->parent = old->parent;
2369 cur->next = old->next;
2370 if (cur->next != NULL)
2371 cur->next->prev = cur;
2372 cur->prev = old->prev;
2373 if (cur->prev != NULL)
2374 cur->prev->next = cur;
2375 if (cur->parent != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002376 if (cur->parent->children == old)
2377 cur->parent->children = cur;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002378 if (cur->parent->last == old)
2379 cur->parent->last = cur;
2380 }
2381 old->next = old->prev = NULL;
2382 old->parent = NULL;
2383 return(old);
2384}
2385
Daniel Veillard260a68f1998-08-13 03:39:55 +00002386/************************************************************************
2387 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002388 * Copy operations *
2389 * *
2390 ************************************************************************/
2391
2392/**
2393 * xmlCopyNamespace:
2394 * @cur: the namespace
2395 *
2396 * Do a copy of the namespace.
2397 *
2398 * Returns: a new xmlNsPtr, or NULL in case of error.
2399 */
2400xmlNsPtr
2401xmlCopyNamespace(xmlNsPtr cur) {
2402 xmlNsPtr ret;
2403
2404 if (cur == NULL) return(NULL);
2405 switch (cur->type) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002406 case XML_LOCAL_NAMESPACE:
2407 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2408 break;
2409 default:
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002410#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002411 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda4964b72000-10-31 18:23:44 +00002412 "xmlCopyNamespace: invalid type %d\n", cur->type);
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002413#endif
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002414 return(NULL);
2415 }
2416 return(ret);
2417}
2418
2419/**
2420 * xmlCopyNamespaceList:
2421 * @cur: the first namespace
2422 *
2423 * Do a copy of an namespace list.
2424 *
2425 * Returns: a new xmlNsPtr, or NULL in case of error.
2426 */
2427xmlNsPtr
2428xmlCopyNamespaceList(xmlNsPtr cur) {
2429 xmlNsPtr ret = NULL;
2430 xmlNsPtr p = NULL,q;
2431
2432 while (cur != NULL) {
2433 q = xmlCopyNamespace(cur);
2434 if (p == NULL) {
2435 ret = p = q;
2436 } else {
2437 p->next = q;
2438 p = q;
2439 }
2440 cur = cur->next;
2441 }
2442 return(ret);
2443}
2444
Daniel Veillard389e6b72001-01-15 19:41:13 +00002445static xmlNodePtr
2446xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002447/**
2448 * xmlCopyProp:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002449 * @target: the element where the attribute will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002450 * @cur: the attribute
2451 *
2452 * Do a copy of the attribute.
2453 *
2454 * Returns: a new xmlAttrPtr, or NULL in case of error.
2455 */
2456xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002457xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002458 xmlAttrPtr ret;
2459
2460 if (cur == NULL) return(NULL);
Daniel Veillard389e6b72001-01-15 19:41:13 +00002461 if (target != NULL)
2462 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2463 else if (cur->parent != NULL)
Daniel Veillardcf461992000-03-14 18:30:20 +00002464 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2465 else if (cur->children != NULL)
2466 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002467 else
2468 ret = xmlNewDocProp(NULL, cur->name, NULL);
2469 if (ret == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002470 ret->parent = target;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002471
2472 if ((cur->ns != NULL) && (target != NULL)) {
2473 xmlNsPtr ns;
2474
2475 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2476 ret->ns = ns;
2477 } else
2478 ret->ns = NULL;
2479
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002480 if (cur->children != NULL) {
2481 xmlNodePtr tmp;
2482
Daniel Veillard389e6b72001-01-15 19:41:13 +00002483 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002484 ret->last = NULL;
2485 tmp = ret->children;
2486 while (tmp != NULL) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00002487 /* tmp->parent = (xmlNodePtr)ret; */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002488 if (tmp->next == NULL)
2489 ret->last = tmp;
2490 tmp = tmp->next;
2491 }
2492 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002493 return(ret);
2494}
2495
2496/**
2497 * xmlCopyPropList:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002498 * @target: the element where the attributes will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002499 * @cur: the first attribute
2500 *
2501 * Do a copy of an attribute list.
2502 *
2503 * Returns: a new xmlAttrPtr, or NULL in case of error.
2504 */
2505xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002506xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002507 xmlAttrPtr ret = NULL;
2508 xmlAttrPtr p = NULL,q;
2509
2510 while (cur != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002511 q = xmlCopyProp(target, cur);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002512 if (p == NULL) {
2513 ret = p = q;
2514 } else {
2515 p->next = q;
Daniel Veillardcf461992000-03-14 18:30:20 +00002516 q->prev = p;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002517 p = q;
2518 }
2519 cur = cur->next;
2520 }
2521 return(ret);
2522}
2523
2524/*
Daniel Veillard11a48ec1999-11-23 10:40:46 +00002525 * NOTE abeut the CopyNode operations !
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002526 *
2527 * They are splitted into external and internal parts for one
2528 * tricky reason: namespaces. Doing a direct copy of a node
2529 * say RPM:Copyright without changing the namespace pointer to
2530 * something else can produce stale links. One way to do it is
2531 * to keep a reference counter but this doesn't work as soon
2532 * as one move the element or the subtree out of the scope of
2533 * the existing namespace. The actual solution seems to add
2534 * a copy of the namespace at the top of the copied tree if
2535 * not available in the subtree.
2536 * Hence two functions, the public front-end call the inner ones
2537 */
2538
2539static xmlNodePtr
2540xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2541
2542static xmlNodePtr
2543xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
2544 int recursive) {
2545 xmlNodePtr ret;
2546
2547 if (node == NULL) return(NULL);
2548 /*
2549 * Allocate a new node and fill the fields.
2550 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00002551 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002552 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002553 xmlGenericError(xmlGenericErrorContext,
2554 "xmlStaticCopyNode : malloc failed\n");
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002555 return(NULL);
2556 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002557 memset(ret, 0, sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002558 ret->type = node->type;
Daniel Veillardcf461992000-03-14 18:30:20 +00002559
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002560 ret->doc = doc;
2561 ret->parent = parent;
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00002562 if (node->name == xmlStringText)
2563 ret->name = xmlStringText;
2564 else if (node->name == xmlStringTextNoenc)
2565 ret->name = xmlStringTextNoenc;
2566 else if (node->name == xmlStringComment)
2567 ret->name = xmlStringComment;
2568 else if (node->name != NULL)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002569 ret->name = xmlStrdup(node->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002570 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
2571#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002572 ret->content = xmlStrdup(node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002573#else
2574 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2575 xmlBufferSetAllocationScheme(ret->content,
2576 xmlGetBufferAllocationScheme());
2577 xmlBufferAdd(ret->content,
2578 xmlBufferContent(node->content),
2579 xmlBufferLength(node->content));
2580#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002581 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002582 if (parent != NULL)
2583 xmlAddChild(parent, ret);
2584
2585 if (!recursive) return(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002586 if (node->nsDef != NULL)
2587 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2588
2589 if (node->ns != NULL) {
2590 xmlNsPtr ns;
2591
2592 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2593 if (ns == NULL) {
2594 /*
2595 * Humm, we are copying an element whose namespace is defined
2596 * out of the new tree scope. Search it in the original tree
2597 * and add it at the top of the new tree
2598 */
2599 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2600 if (ns != NULL) {
2601 xmlNodePtr root = ret;
2602
2603 while (root->parent != NULL) root = root->parent;
2604 xmlNewNs(root, ns->href, ns->prefix);
2605 }
2606 } else {
2607 /*
2608 * reference the existing namespace definition in our own tree.
2609 */
2610 ret->ns = ns;
2611 }
2612 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002613 if (node->properties != NULL)
2614 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardcf461992000-03-14 18:30:20 +00002615 if (node->children != NULL)
2616 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002617 UPDATE_LAST_CHILD_AND_PARENT(ret)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002618 return(ret);
2619}
2620
2621static xmlNodePtr
2622xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2623 xmlNodePtr ret = NULL;
2624 xmlNodePtr p = NULL,q;
2625
2626 while (node != NULL) {
Daniel Veillardde55cf62001-01-31 15:53:13 +00002627 if( node->type == XML_DTD_NODE )
2628 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2629 else
2630 q = xmlStaticCopyNode(node, doc, parent, 1);
Daniel Veillard06047432000-04-24 11:33:38 +00002631 if (ret == NULL) {
2632 q->prev = NULL;
2633 ret = p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002634 } else {
Daniel Veillard06047432000-04-24 11:33:38 +00002635 p->next = q;
2636 q->prev = p;
2637 p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002638 }
2639 node = node->next;
2640 }
2641 return(ret);
2642}
2643
2644/**
2645 * xmlCopyNode:
2646 * @node: the node
2647 * @recursive: if 1 do a recursive copy.
2648 *
2649 * Do a copy of the node.
2650 *
2651 * Returns: a new xmlNodePtr, or NULL in case of error.
2652 */
2653xmlNodePtr
2654xmlCopyNode(xmlNodePtr node, int recursive) {
2655 xmlNodePtr ret;
2656
2657 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2658 return(ret);
2659}
2660
2661/**
2662 * xmlCopyNodeList:
2663 * @node: the first node in the list.
2664 *
2665 * Do a recursive copy of the node list.
2666 *
2667 * Returns: a new xmlNodePtr, or NULL in case of error.
2668 */
2669xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2670 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2671 return(ret);
2672}
2673
2674/**
2675 * xmlCopyElement:
2676 * @elem: the element
2677 *
2678 * Do a copy of the element definition.
2679 *
2680 * Returns: a new xmlElementPtr, or NULL in case of error.
2681xmlElementPtr
2682xmlCopyElement(xmlElementPtr elem) {
2683 xmlElementPtr ret;
2684
2685 if (elem == NULL) return(NULL);
2686 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
2687 if (ret == NULL) return(NULL);
2688 if (!recursive) return(ret);
2689 if (elem->properties != NULL)
2690 ret->properties = xmlCopyPropList(elem->properties);
2691
2692 if (elem->nsDef != NULL)
2693 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
Daniel Veillardcf461992000-03-14 18:30:20 +00002694 if (elem->children != NULL)
2695 ret->children = xmlCopyElementList(elem->children);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002696 return(ret);
2697}
2698 */
2699
2700/**
2701 * xmlCopyDtd:
2702 * @dtd: the dtd
2703 *
2704 * Do a copy of the dtd.
2705 *
2706 * Returns: a new xmlDtdPtr, or NULL in case of error.
2707 */
2708xmlDtdPtr
2709xmlCopyDtd(xmlDtdPtr dtd) {
2710 xmlDtdPtr ret;
2711
2712 if (dtd == NULL) return(NULL);
2713 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2714 if (ret == NULL) return(NULL);
2715 if (dtd->entities != NULL)
2716 ret->entities = (void *) xmlCopyEntitiesTable(
2717 (xmlEntitiesTablePtr) dtd->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002718 if (dtd->notations != NULL)
2719 ret->notations = (void *) xmlCopyNotationTable(
2720 (xmlNotationTablePtr) dtd->notations);
2721 if (dtd->elements != NULL)
2722 ret->elements = (void *) xmlCopyElementTable(
2723 (xmlElementTablePtr) dtd->elements);
2724 if (dtd->attributes != NULL)
2725 ret->attributes = (void *) xmlCopyAttributeTable(
2726 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002727 return(ret);
2728}
2729
2730/**
2731 * xmlCopyDoc:
2732 * @doc: the document
2733 * @recursive: if 1 do a recursive copy.
2734 *
2735 * Do a copy of the document info. If recursive, the content tree will
2736 * be copied too as well as Dtd, namespaces and entities.
2737 *
2738 * Returns: a new xmlDocPtr, or NULL in case of error.
2739 */
2740xmlDocPtr
2741xmlCopyDoc(xmlDocPtr doc, int recursive) {
2742 xmlDocPtr ret;
2743
2744 if (doc == NULL) return(NULL);
2745 ret = xmlNewDoc(doc->version);
2746 if (ret == NULL) return(NULL);
2747 if (doc->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002748 ret->name = xmlMemStrdup(doc->name);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002749 if (doc->encoding != NULL)
2750 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardde55cf62001-01-31 15:53:13 +00002751 ret->charset = doc->charset;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002752 ret->compression = doc->compression;
2753 ret->standalone = doc->standalone;
2754 if (!recursive) return(ret);
2755
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002756 if (doc->intSubset != NULL)
2757 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002758 if (doc->oldNs != NULL)
2759 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002760 if (doc->children != NULL) {
2761 xmlNodePtr tmp;
Daniel Veillard06047432000-04-24 11:33:38 +00002762 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2763 (xmlNodePtr)ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002764 ret->last = NULL;
2765 tmp = ret->children;
2766 while (tmp != NULL) {
2767 if (tmp->next == NULL)
2768 ret->last = tmp;
2769 tmp = tmp->next;
2770 }
2771 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002772 return(ret);
2773}
2774
2775/************************************************************************
2776 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002777 * Content access functions *
2778 * *
2779 ************************************************************************/
2780
Daniel Veillard97b58771998-10-20 06:14:16 +00002781/**
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002782 * xmlDocGetRootElement:
2783 * @doc: the document
2784 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002785 * Get the root element of the document (doc->children is a list
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002786 * containing possibly comments, PIs, etc ...).
2787 *
2788 * Returns the xmlNodePtr for the root or NULL
2789 */
2790xmlNodePtr
2791xmlDocGetRootElement(xmlDocPtr doc) {
2792 xmlNodePtr ret;
2793
2794 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002795 ret = doc->children;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002796 while (ret != NULL) {
2797 if (ret->type == XML_ELEMENT_NODE)
2798 return(ret);
2799 ret = ret->next;
2800 }
2801 return(ret);
2802}
2803
2804/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002805 * xmlDocSetRootElement:
2806 * @doc: the document
2807 * @root: the new document root element
2808 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002809 * Set the root element of the document (doc->children is a list
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002810 * containing possibly comments, PIs, etc ...).
2811 *
2812 * Returns the old root element if any was found
2813 */
2814xmlNodePtr
2815xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
2816 xmlNodePtr old = NULL;
2817
2818 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002819 old = doc->children;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002820 while (old != NULL) {
2821 if (old->type == XML_ELEMENT_NODE)
2822 break;
2823 old = old->next;
2824 }
2825 if (old == NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002826 if (doc->children == NULL) {
2827 doc->children = root;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002828 doc->last = root;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002829 } else {
Daniel Veillardcf461992000-03-14 18:30:20 +00002830 xmlAddSibling(doc->children, root);
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002831 }
2832 } else {
2833 xmlReplaceNode(old, root);
2834 }
2835 return(old);
2836}
2837
2838/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002839 * xmlNodeSetLang:
2840 * @cur: the node being changed
2841 * @lang: the langage description
2842 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002843 * Set the language of a node, i.e. the values of the xml:lang
2844 * attribute.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002845 */
2846void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002847xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002848 if (cur == NULL) return;
2849 switch(cur->type) {
2850 case XML_TEXT_NODE:
2851 case XML_CDATA_SECTION_NODE:
2852 case XML_COMMENT_NODE:
2853 case XML_DOCUMENT_NODE:
2854 case XML_DOCUMENT_TYPE_NODE:
2855 case XML_DOCUMENT_FRAG_NODE:
2856 case XML_NOTATION_NODE:
2857 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002858 case XML_DTD_NODE:
2859 case XML_ELEMENT_DECL:
2860 case XML_ATTRIBUTE_DECL:
2861 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002862 case XML_PI_NODE:
2863 case XML_ENTITY_REF_NODE:
2864 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002865 case XML_NAMESPACE_DECL:
Daniel Veillard04698d92000-09-17 16:00:22 +00002866#ifdef LIBXML_SGML_ENABLED
2867 case XML_SGML_DOCUMENT_NODE:
2868#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002869 case XML_XINCLUDE_START:
2870 case XML_XINCLUDE_END:
Daniel Veillard39c7d712000-09-10 16:14:55 +00002871 return;
2872 case XML_ELEMENT_NODE:
2873 case XML_ATTRIBUTE_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002874 break;
2875 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002876 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
2877}
2878
2879/**
2880 * xmlNodeGetLang:
2881 * @cur: the node being checked
2882 *
2883 * Searches the language of a node, i.e. the values of the xml:lang
2884 * attribute or the one carried by the nearest ancestor.
2885 *
2886 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillarda819dac1999-11-24 18:04:22 +00002887 * It's up to the caller to free the memory.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002888 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00002889xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00002890xmlNodeGetLang(xmlNodePtr cur) {
Daniel Veillarda819dac1999-11-24 18:04:22 +00002891 xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002892
2893 while (cur != NULL) {
2894 lang = xmlGetProp(cur, BAD_CAST "xml:lang");
2895 if (lang != NULL)
2896 return(lang);
2897 cur = cur->parent;
2898 }
2899 return(NULL);
2900}
2901
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002902
2903/**
2904 * xmlNodeSetSpacePreserve:
2905 * @cur: the node being changed
2906 * @val: the xml:space value ("0": default, 1: "preserve")
2907 *
2908 * Set (or reset) the space preserving behaviour of a node, i.e. the
2909 * value of the xml:space attribute.
2910 */
2911void
2912xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
2913 if (cur == NULL) return;
2914 switch(cur->type) {
2915 case XML_TEXT_NODE:
2916 case XML_CDATA_SECTION_NODE:
2917 case XML_COMMENT_NODE:
2918 case XML_DOCUMENT_NODE:
2919 case XML_DOCUMENT_TYPE_NODE:
2920 case XML_DOCUMENT_FRAG_NODE:
2921 case XML_NOTATION_NODE:
2922 case XML_HTML_DOCUMENT_NODE:
2923 case XML_DTD_NODE:
2924 case XML_ELEMENT_DECL:
2925 case XML_ATTRIBUTE_DECL:
2926 case XML_ENTITY_DECL:
2927 case XML_PI_NODE:
2928 case XML_ENTITY_REF_NODE:
2929 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002930 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002931 case XML_XINCLUDE_START:
2932 case XML_XINCLUDE_END:
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002933#ifdef LIBXML_SGML_ENABLED
2934 case XML_SGML_DOCUMENT_NODE:
2935#endif
2936 return;
2937 case XML_ELEMENT_NODE:
2938 case XML_ATTRIBUTE_NODE:
2939 break;
2940 }
2941 switch (val) {
2942 case 0:
2943 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
2944 break;
2945 case 1:
2946 xmlSetProp(cur, BAD_CAST "xml:space",
2947 BAD_CAST "preserve");
2948 break;
2949 }
2950}
2951
Daniel Veillardb96e6431999-08-29 21:02:19 +00002952/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002953 * xmlNodeGetSpacePreserve:
2954 * @cur: the node being checked
2955 *
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002956 * Searches the space preserving behaviour of a node, i.e. the values
2957 * of the xml:space attribute or the one carried by the nearest
2958 * ancestor.
Daniel Veillardcf461992000-03-14 18:30:20 +00002959 *
2960 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
2961 */
2962int
2963xmlNodeGetSpacePreserve(xmlNodePtr cur) {
2964 xmlChar *space;
2965
2966 while (cur != NULL) {
2967 space = xmlGetProp(cur, BAD_CAST "xml:space");
2968 if (space != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002969 if (xmlStrEqual(space, BAD_CAST "preserve")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002970 xmlFree(space);
2971 return(1);
2972 }
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002973 if (xmlStrEqual(space, BAD_CAST "default")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002974 xmlFree(space);
2975 return(0);
2976 }
2977 xmlFree(space);
2978 }
2979 cur = cur->parent;
2980 }
2981 return(-1);
2982}
2983
2984/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002985 * xmlNodeSetName:
2986 * @cur: the node being changed
2987 * @name: the new tag name
2988 *
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002989 * Set (or reset) the name of a node.
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002990 */
2991void
2992xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
2993 if (cur == NULL) return;
2994 if (name == NULL) return;
2995 switch(cur->type) {
2996 case XML_TEXT_NODE:
2997 case XML_CDATA_SECTION_NODE:
2998 case XML_COMMENT_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002999 case XML_DOCUMENT_TYPE_NODE:
3000 case XML_DOCUMENT_FRAG_NODE:
3001 case XML_NOTATION_NODE:
3002 case XML_HTML_DOCUMENT_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003003 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003004 case XML_XINCLUDE_START:
3005 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003006#ifdef LIBXML_SGML_ENABLED
3007 case XML_SGML_DOCUMENT_NODE:
3008#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00003009 return;
3010 case XML_ELEMENT_NODE:
3011 case XML_ATTRIBUTE_NODE:
3012 case XML_PI_NODE:
3013 case XML_ENTITY_REF_NODE:
3014 case XML_ENTITY_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003015 case XML_DTD_NODE:
3016 case XML_DOCUMENT_NODE:
3017 case XML_ELEMENT_DECL:
3018 case XML_ATTRIBUTE_DECL:
3019 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00003020 break;
3021 }
3022 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3023 cur->name = xmlStrdup(name);
3024}
3025
3026/**
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00003027 * xmlNodeSetBase:
3028 * @cur: the node being changed
3029 * @uri: the new base URI
3030 *
3031 * Set (or reset) the base URI of a node, i.e. the value of the
3032 * xml:base attribute.
3033 */
3034void
3035xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3036 if (cur == NULL) return;
3037 switch(cur->type) {
3038 case XML_TEXT_NODE:
3039 case XML_CDATA_SECTION_NODE:
3040 case XML_COMMENT_NODE:
3041 case XML_DOCUMENT_NODE:
3042 case XML_DOCUMENT_TYPE_NODE:
3043 case XML_DOCUMENT_FRAG_NODE:
3044 case XML_NOTATION_NODE:
3045 case XML_HTML_DOCUMENT_NODE:
3046 case XML_DTD_NODE:
3047 case XML_ELEMENT_DECL:
3048 case XML_ATTRIBUTE_DECL:
3049 case XML_ENTITY_DECL:
3050 case XML_PI_NODE:
3051 case XML_ENTITY_REF_NODE:
3052 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003053 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003054 case XML_XINCLUDE_START:
3055 case XML_XINCLUDE_END:
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00003056#ifdef LIBXML_SGML_ENABLED
3057 case XML_SGML_DOCUMENT_NODE:
3058#endif
3059 return;
3060 case XML_ELEMENT_NODE:
3061 case XML_ATTRIBUTE_NODE:
3062 break;
3063 }
3064 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3065}
3066
3067/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003068 * xmlDocumentGetBase:
3069 * @doc: the document
3070 *
3071 * Searches for the Document BASE URL. The code should work on both XML
3072 * and HTML document.
3073 * It returns the base as defined in RFC 2396 section
3074 * 5.1.3. Base URI from the Retrieval URI
3075 * However it does not return the computed base (5.1.1 and 5.1.2), use
3076 * xmlNodeGetBase() for this
3077 *
3078 * Returns a pointer to the base URL, or NULL if not found
3079 * It's up to the caller to free the memory.
3080 */
3081xmlChar *
3082xmlDocumentGetBase(xmlDocPtr doc) {
3083 if (doc == NULL)
3084 return(NULL);
3085 if (doc->type == XML_HTML_DOCUMENT_NODE) {
3086 if (doc->URL != NULL)
3087 return(xmlStrdup(doc->URL));
3088 return(NULL);
3089 }
3090 if (doc->URL != NULL)
3091 return(xmlStrdup(doc->URL));
3092 return(NULL);
3093}
3094
3095/**
Daniel Veillard10a2c651999-12-12 13:03:50 +00003096 * xmlNodeGetBase:
3097 * @doc: the document the node pertains to
3098 * @cur: the node being checked
3099 *
3100 * Searches for the BASE URL. The code should work on both XML
3101 * and HTML document even if base mechanisms are completely different.
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003102 * It returns the base as defined in RFC 2396 sections
3103 * 5.1.1. Base URI within Document Content
3104 * and
3105 * 5.1.2. Base URI from the Encapsulating Entity
3106 * However it does not return the document base (5.1.3), use
3107 * xmlDocumentGetBase() for this
Daniel Veillard10a2c651999-12-12 13:03:50 +00003108 *
3109 * Returns a pointer to the base URL, or NULL if not found
3110 * It's up to the caller to free the memory.
3111 */
3112xmlChar *
3113xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
3114 xmlChar *base;
3115
3116 if ((cur == NULL) && (doc == NULL))
3117 return(NULL);
3118 if (doc == NULL) doc = cur->doc;
3119 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003120 cur = doc->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003121 while ((cur != NULL) && (cur->name != NULL)) {
3122 if (cur->type != XML_ELEMENT_NODE) {
3123 cur = cur->next;
3124 continue;
3125 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003126 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003127 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003128 continue;
3129 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003130 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003131 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003132 continue;
3133 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003134 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3135 return(xmlGetProp(cur, BAD_CAST "href"));
Daniel Veillard10a2c651999-12-12 13:03:50 +00003136 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003137 cur = cur->next;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003138 }
3139 return(NULL);
3140 }
3141 while (cur != NULL) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003142 if (cur->type == XML_ENTITY_DECL) {
3143 xmlEntityPtr ent = (xmlEntityPtr) cur;
3144 return(xmlStrdup(ent->URI));
3145 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003146 base = xmlGetProp(cur, BAD_CAST "xml:base");
3147 if (base != NULL)
3148 return(base);
3149 cur = cur->parent;
3150 }
Daniel Veillard5dd2f0a2001-02-12 17:36:05 +00003151 if ((doc != NULL) && (doc->URL != NULL))
3152 return(xmlStrdup(doc->URL));
Daniel Veillard10a2c651999-12-12 13:03:50 +00003153 return(NULL);
3154}
3155
3156/**
Daniel Veillard16253641998-10-28 22:58:05 +00003157 * xmlNodeGetContent:
3158 * @cur: the node being read
3159 *
3160 * Read the value of a node, this can be either the text carried
3161 * directly by this node if it's a TEXT node or the aggregate string
3162 * of the values carried by this node child's (TEXT and ENTITY_REF).
3163 * Entity references are substitued.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003164 * Returns a new xmlChar * or NULL if no content is available.
Daniel Veillard5099ae81999-04-21 20:12:07 +00003165 * It's up to the caller to free the memory.
Daniel Veillard16253641998-10-28 22:58:05 +00003166 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003167xmlChar *
Daniel Veillard16253641998-10-28 22:58:05 +00003168xmlNodeGetContent(xmlNodePtr cur) {
3169 if (cur == NULL) return(NULL);
3170 switch (cur->type) {
3171 case XML_DOCUMENT_FRAG_NODE:
3172 case XML_ELEMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003173 return(xmlNodeListGetString(cur->doc, cur->children, 1));
Daniel Veillard16253641998-10-28 22:58:05 +00003174 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003175 case XML_ATTRIBUTE_NODE: {
3176 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00003177 if (attr->parent != NULL)
3178 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003179 else
Daniel Veillardcf461992000-03-14 18:30:20 +00003180 return(xmlNodeListGetString(NULL, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003181 break;
3182 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003183 case XML_COMMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003184 case XML_PI_NODE:
3185 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003186#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00003187 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003188#else
3189 return(xmlStrdup(xmlBufferContent(cur->content)));
3190#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00003191 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00003192 case XML_ENTITY_REF_NODE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003193 /*
3194 * Locate the entity, and get it's content
3195 * @@@
3196 */
3197 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00003198 case XML_ENTITY_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003199 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003200 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003201 case XML_DOCUMENT_TYPE_NODE:
3202 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003203 case XML_DTD_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003204 case XML_XINCLUDE_START:
3205 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003206#ifdef LIBXML_SGML_ENABLED
3207 case XML_SGML_DOCUMENT_NODE:
3208#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00003209 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00003210 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003211 return(xmlStrdup(((xmlNsPtr)cur)->href));
Daniel Veillardcf461992000-03-14 18:30:20 +00003212 case XML_ELEMENT_DECL:
3213 /* TODO !!! */
3214 return(NULL);
3215 case XML_ATTRIBUTE_DECL:
3216 /* TODO !!! */
3217 return(NULL);
3218 case XML_ENTITY_DECL:
3219 /* TODO !!! */
Daniel Veillard16253641998-10-28 22:58:05 +00003220 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003221 case XML_CDATA_SECTION_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003222 case XML_TEXT_NODE:
3223 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003224#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003225 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003226#else
3227 return(xmlStrdup(xmlBufferContent(cur->content)));
3228#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003229 return(NULL);
3230 }
3231 return(NULL);
3232}
3233
3234/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003235 * xmlNodeSetContent:
3236 * @cur: the node being modified
3237 * @content: the new value of the content
3238 *
3239 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003240 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003241void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003242xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003243 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003244#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003245 xmlGenericError(xmlGenericErrorContext,
3246 "xmlNodeSetContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003247#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003248 return;
3249 }
Daniel Veillard16253641998-10-28 22:58:05 +00003250 switch (cur->type) {
3251 case XML_DOCUMENT_FRAG_NODE:
3252 case XML_ELEMENT_NODE:
3253 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003254#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003255 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003256#else
3257 xmlBufferFree(cur->content);
3258#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003259 cur->content = NULL;
3260 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003261 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3262 cur->children = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003263 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00003264 break;
3265 case XML_ATTRIBUTE_NODE:
3266 break;
3267 case XML_TEXT_NODE:
3268 case XML_CDATA_SECTION_NODE:
3269 case XML_ENTITY_REF_NODE:
3270 case XML_ENTITY_NODE:
3271 case XML_PI_NODE:
3272 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003273 if (cur->content != NULL) {
3274#ifndef XML_USE_BUFFER_CONTENT
3275 xmlFree(cur->content);
3276#else
3277 xmlBufferFree(cur->content);
3278#endif
3279 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003280 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3281 cur->last = cur->children = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003282 if (content != NULL) {
3283#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003284 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003285#else
3286 cur->content = xmlBufferCreateSize(0);
3287 xmlBufferSetAllocationScheme(cur->content,
3288 xmlGetBufferAllocationScheme());
3289 xmlBufferAdd(cur->content, content, -1);
3290#endif
3291 } else
Daniel Veillard16253641998-10-28 22:58:05 +00003292 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003293 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003294 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003295 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003296 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003297 case XML_XINCLUDE_START:
3298 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003299#ifdef LIBXML_SGML_ENABLED
3300 case XML_SGML_DOCUMENT_NODE:
3301#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003302 break;
3303 case XML_NOTATION_NODE:
3304 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003305 case XML_DTD_NODE:
3306 break;
Daniel Veillarda4964b72000-10-31 18:23:44 +00003307 case XML_NAMESPACE_DECL:
3308 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003309 case XML_ELEMENT_DECL:
3310 /* TODO !!! */
3311 break;
3312 case XML_ATTRIBUTE_DECL:
3313 /* TODO !!! */
3314 break;
3315 case XML_ENTITY_DECL:
3316 /* TODO !!! */
3317 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003318 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003319}
3320
Daniel Veillard97b58771998-10-20 06:14:16 +00003321/**
3322 * xmlNodeSetContentLen:
3323 * @cur: the node being modified
3324 * @content: the new value of the content
3325 * @len: the size of @content
3326 *
3327 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003328 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003329void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003330xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003331 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003332#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003333 xmlGenericError(xmlGenericErrorContext,
3334 "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003335#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003336 return;
3337 }
Daniel Veillard16253641998-10-28 22:58:05 +00003338 switch (cur->type) {
3339 case XML_DOCUMENT_FRAG_NODE:
3340 case XML_ELEMENT_NODE:
3341 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003342#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003343 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003344#else
3345 xmlBufferFree(cur->content);
3346#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003347 cur->content = NULL;
3348 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003349 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3350 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003351 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00003352 break;
3353 case XML_ATTRIBUTE_NODE:
3354 break;
3355 case XML_TEXT_NODE:
3356 case XML_CDATA_SECTION_NODE:
3357 case XML_ENTITY_REF_NODE:
3358 case XML_ENTITY_NODE:
3359 case XML_PI_NODE:
3360 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003361 case XML_NOTATION_NODE:
3362 if (cur->content != NULL) {
3363#ifndef XML_USE_BUFFER_CONTENT
3364 xmlFree(cur->content);
3365#else
3366 xmlBufferFree(cur->content);
3367#endif
3368 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003369 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3370 cur->children = cur->last = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003371 if (content != NULL) {
3372#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003373 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003374#else
3375 cur->content = xmlBufferCreateSize(len);
3376 xmlBufferSetAllocationScheme(cur->content,
3377 xmlGetBufferAllocationScheme());
3378 xmlBufferAdd(cur->content, content, len);
3379#endif
3380 } else
Daniel Veillard16253641998-10-28 22:58:05 +00003381 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003382 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003383 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003384 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003385 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003386 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003387 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003388 case XML_XINCLUDE_START:
3389 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003390#ifdef LIBXML_SGML_ENABLED
3391 case XML_SGML_DOCUMENT_NODE:
3392#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003393 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003394 case XML_ELEMENT_DECL:
3395 /* TODO !!! */
3396 break;
3397 case XML_ATTRIBUTE_DECL:
3398 /* TODO !!! */
3399 break;
3400 case XML_ENTITY_DECL:
3401 /* TODO !!! */
3402 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003403 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003404}
3405
Daniel Veillard97b58771998-10-20 06:14:16 +00003406/**
3407 * xmlNodeAddContentLen:
3408 * @cur: the node being modified
3409 * @content: extra content
3410 * @len: the size of @content
3411 *
3412 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003413 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003414void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003415xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003416 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003417#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003418 xmlGenericError(xmlGenericErrorContext,
3419 "xmlNodeAddContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003420#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003421 return;
3422 }
3423 if (len <= 0) return;
3424 switch (cur->type) {
3425 case XML_DOCUMENT_FRAG_NODE:
3426 case XML_ELEMENT_NODE: {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003427 xmlNodePtr last = NULL, newNode;
Daniel Veillard16253641998-10-28 22:58:05 +00003428
Daniel Veillardcf461992000-03-14 18:30:20 +00003429 if (cur->children != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003430 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003431 } else {
3432 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003433#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardcf461992000-03-14 18:30:20 +00003434 cur->children = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003435#else
Daniel Veillardcf461992000-03-14 18:30:20 +00003436 cur->children = xmlStringGetNodeList(cur->doc,
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003437 xmlBufferContent(cur->content));
3438#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003439 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003440#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003441 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003442#else
3443 xmlBufferFree(cur->content);
3444#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003445 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003446 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003447 }
3448 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003449 newNode = xmlNewTextLen(content, len);
3450 if (newNode != NULL) {
3451 xmlAddChild(cur, newNode);
3452 if ((last != NULL) && (last->next == newNode)) {
3453 xmlTextMerge(last, newNode);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003454 }
Daniel Veillard16253641998-10-28 22:58:05 +00003455 }
3456 break;
3457 }
3458 case XML_ATTRIBUTE_NODE:
3459 break;
3460 case XML_TEXT_NODE:
3461 case XML_CDATA_SECTION_NODE:
3462 case XML_ENTITY_REF_NODE:
3463 case XML_ENTITY_NODE:
3464 case XML_PI_NODE:
3465 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003466 case XML_NOTATION_NODE:
3467 if (content != NULL) {
3468#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003469 cur->content = xmlStrncat(cur->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003470#else
3471 xmlBufferAdd(cur->content, content, len);
3472#endif
3473 }
Daniel Veillard16253641998-10-28 22:58:05 +00003474 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003475 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003476 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003477 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003478 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003479 case XML_XINCLUDE_START:
3480 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003481#ifdef LIBXML_SGML_ENABLED
3482 case XML_SGML_DOCUMENT_NODE:
3483#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003484 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003485 case XML_ELEMENT_DECL:
3486 case XML_ATTRIBUTE_DECL:
3487 case XML_ENTITY_DECL:
3488 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003489 }
3490}
3491
3492/**
3493 * xmlNodeAddContent:
3494 * @cur: the node being modified
3495 * @content: extra content
3496 *
3497 * Append the extra substring to the node content.
3498 */
3499void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003500xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard16253641998-10-28 22:58:05 +00003501 int len;
3502
3503 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003504#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003505 xmlGenericError(xmlGenericErrorContext,
3506 "xmlNodeAddContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003507#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003508 return;
3509 }
Daniel Veillard16253641998-10-28 22:58:05 +00003510 if (content == NULL) return;
3511 len = xmlStrlen(content);
3512 xmlNodeAddContentLen(cur, content, len);
3513}
3514
3515/**
3516 * xmlTextMerge:
3517 * @first: the first text node
3518 * @second: the second text node being merged
3519 *
3520 * Merge two text nodes into one
Daniel Veillard1e346af1999-02-22 10:33:01 +00003521 * Returns the first text node augmented
Daniel Veillard16253641998-10-28 22:58:05 +00003522 */
3523xmlNodePtr
3524xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3525 if (first == NULL) return(second);
3526 if (second == NULL) return(first);
3527 if (first->type != XML_TEXT_NODE) return(first);
3528 if (second->type != XML_TEXT_NODE) return(first);
Daniel Veillard5dd2f0a2001-02-12 17:36:05 +00003529 if (second->name != first->name)
3530 return(first);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003531#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003532 xmlNodeAddContent(first, second->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003533#else
3534 xmlNodeAddContent(first, xmlBufferContent(second->content));
3535#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003536 xmlUnlinkNode(second);
3537 xmlFreeNode(second);
3538 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003539}
3540
Daniel Veillard97b58771998-10-20 06:14:16 +00003541/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003542 * xmlGetNsList:
3543 * @doc: the document
3544 * @node: the current node
3545 *
3546 * Search all the namespace applying to a given element.
3547 * Returns an NULL terminated array of all the xmlNsPtr found
3548 * that need to be freed by the caller or NULL if no
3549 * namespace if defined
3550 */
3551xmlNsPtr *
3552xmlGetNsList(xmlDocPtr doc, xmlNodePtr node) {
3553 xmlNsPtr cur;
3554 xmlNsPtr *ret = NULL;
3555 int nbns = 0;
3556 int maxns = 10;
3557 int i;
3558
3559 while (node != NULL) {
3560 cur = node->nsDef;
3561 while (cur != NULL) {
3562 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003563 ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003564 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003565 xmlGenericError(xmlGenericErrorContext,
3566 "xmlGetNsList : out of memory!\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00003567 return(NULL);
3568 }
3569 ret[nbns] = NULL;
3570 }
3571 for (i = 0;i < nbns;i++) {
3572 if ((cur->prefix == ret[i]->prefix) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003573 (xmlStrEqual(cur->prefix, ret[i]->prefix))) break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003574 }
3575 if (i >= nbns) {
3576 if (nbns >= maxns) {
3577 maxns *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003578 ret = (xmlNsPtr *) xmlRealloc(ret,
Daniel Veillardb96e6431999-08-29 21:02:19 +00003579 (maxns + 1) * sizeof(xmlNsPtr));
3580 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003581 xmlGenericError(xmlGenericErrorContext,
3582 "xmlGetNsList : realloc failed!\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00003583 return(NULL);
3584 }
3585 }
3586 ret[nbns++] = cur;
3587 ret[nbns] = NULL;
3588 }
3589
3590 cur = cur->next;
3591 }
3592 node = node->parent;
3593 }
3594 return(ret);
3595}
3596
3597/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003598 * xmlSearchNs:
3599 * @doc: the document
3600 * @node: the current node
3601 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00003602 *
Daniel Veillard97b58771998-10-20 06:14:16 +00003603 * Search a Ns registered under a given name space for a document.
3604 * recurse on the parents until it finds the defined namespace
3605 * or return NULL otherwise.
3606 * @nameSpace can be NULL, this is a search for the default namespace.
Daniel Veillarde0854c32000-08-27 21:12:29 +00003607 * We don't allow to cross entities boundaries. If you don't declare
3608 * the namespace within those you will be in troubles !!! A warning
3609 * is generated to cover this case.
3610 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003611 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003612 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003613xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003614xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003615 xmlNsPtr cur;
3616
Daniel Veillard62ba71e1999-12-16 17:52:19 +00003617 if (node == NULL) return(NULL);
Daniel Veillarde0e26512001-02-16 00:11:46 +00003618 if ((nameSpace != NULL) &&
3619 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
3620 if (doc->oldNs == NULL) {
3621 /*
3622 * Allocate a new Namespace and fill the fields.
3623 */
3624 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3625 if (doc->oldNs == NULL) {
3626 xmlGenericError(xmlGenericErrorContext,
3627 "xmlSearchNsByHref : malloc failed\n");
3628 return(NULL);
3629 }
3630 memset(doc->oldNs, 0, sizeof(xmlNs));
3631 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3632
3633 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3634 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3635 }
3636 return(doc->oldNs);
3637 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003638 while (node != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003639 if ((node->type == XML_ENTITY_REF_NODE) ||
3640 (node->type == XML_ENTITY_NODE) ||
3641 (node->type == XML_ENTITY_DECL))
3642 return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00003643 if (node->type == XML_ELEMENT_NODE) {
3644 cur = node->nsDef;
3645 while (cur != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003646 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3647 (cur->href != NULL))
Daniel Veillardcf461992000-03-14 18:30:20 +00003648 return(cur);
3649 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
Daniel Veillarde0854c32000-08-27 21:12:29 +00003650 (cur->href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003651 (xmlStrEqual(cur->prefix, nameSpace)))
Daniel Veillardcf461992000-03-14 18:30:20 +00003652 return(cur);
3653 cur = cur->next;
3654 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003655 }
3656 node = node->parent;
3657 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003658 return(NULL);
3659}
3660
Daniel Veillard97b58771998-10-20 06:14:16 +00003661/**
3662 * xmlSearchNsByHref:
3663 * @doc: the document
3664 * @node: the current node
3665 * @href: the namespace value
3666 *
3667 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3668 * the defined namespace or return NULL otherwise.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003669 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003670 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003671xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003672xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003673 xmlNsPtr cur;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003674 xmlNodePtr orig = node;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003675
Daniel Veillard10a2c651999-12-12 13:03:50 +00003676 if ((node == NULL) || (href == NULL)) return(NULL);
Daniel Veillarde0e26512001-02-16 00:11:46 +00003677 if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
3678 if (doc->oldNs == NULL) {
3679 /*
3680 * Allocate a new Namespace and fill the fields.
3681 */
3682 doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3683 if (doc->oldNs == NULL) {
3684 xmlGenericError(xmlGenericErrorContext,
3685 "xmlSearchNsByHref : malloc failed\n");
3686 return(NULL);
3687 }
3688 memset(doc->oldNs, 0, sizeof(xmlNs));
3689 doc->oldNs->type = XML_LOCAL_NAMESPACE;
3690
3691 doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE);
3692 doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml");
3693 }
3694 return(doc->oldNs);
3695 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003696 while (node != NULL) {
3697 cur = node->nsDef;
3698 while (cur != NULL) {
3699 if ((cur->href != NULL) && (href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003700 (xmlStrEqual(cur->href, href))) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003701 /*
3702 * Check that the prefix is not shadowed between orig and node
3703 */
3704 xmlNodePtr check = orig;
3705 xmlNsPtr tst;
3706
3707 while (check != node) {
3708 tst = check->nsDef;
3709 while (tst != NULL) {
3710 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3711 goto shadowed;
3712 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003713 (xmlStrEqual(tst->prefix, cur->prefix)))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003714 goto shadowed;
3715 tst = tst->next;
3716 }
Daniel Veillardc4f4f0b2000-10-29 17:46:30 +00003717 check = check->parent;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003718 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003719 return(cur);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003720 }
3721shadowed:
Daniel Veillard260a68f1998-08-13 03:39:55 +00003722 cur = cur->next;
3723 }
3724 node = node->parent;
3725 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003726 return(NULL);
3727}
3728
3729/**
3730 * xmlNewReconciliedNs
3731 * @doc: the document
3732 * @tree: a node expected to hold the new namespace
3733 * @ns: the original namespace
3734 *
3735 * This function tries to locate a namespace definition in a tree
3736 * ancestors, or create a new namespace definition node similar to
3737 * @ns trying to reuse the same prefix. However if the given prefix is
3738 * null (default namespace) or reused within the subtree defined by
3739 * @tree or on one of its ancestors then a new prefix is generated.
3740 * Returns the (new) namespace definition or NULL in case of error
3741 */
3742xmlNsPtr
3743xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3744 xmlNsPtr def;
3745 xmlChar prefix[50];
3746 int counter = 1;
3747
3748 if (tree == NULL) {
3749#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003750 xmlGenericError(xmlGenericErrorContext,
3751 "xmlNewReconciliedNs : tree == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003752#endif
3753 return(NULL);
3754 }
3755 if (ns == NULL) {
3756#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003757 xmlGenericError(xmlGenericErrorContext,
3758 "xmlNewReconciliedNs : ns == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003759#endif
3760 return(NULL);
3761 }
3762 /*
3763 * Search an existing namespace definition inherited.
3764 */
3765 def = xmlSearchNsByHref(doc, tree, ns->href);
3766 if (def != NULL)
3767 return(def);
3768
3769 /*
3770 * Find a close prefix which is not already in use.
3771 * Let's strip namespace prefixes longer than 20 chars !
3772 */
3773 sprintf((char *) prefix, "%.20s", ns->prefix);
3774 def = xmlSearchNs(doc, tree, prefix);
3775 while (def != NULL) {
3776 if (counter > 1000) return(NULL);
3777 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
3778 def = xmlSearchNs(doc, tree, prefix);
3779 }
3780
3781 /*
3782 * Ok, now we are ready to create a new one.
3783 */
3784 def = xmlNewNs(tree, ns->href, prefix);
3785 return(def);
3786}
3787
3788/**
3789 * xmlReconciliateNs
3790 * @doc: the document
3791 * @tree: a node defining the subtree to reconciliate
3792 *
3793 * This function checks that all the namespaces declared within the given
3794 * tree are properly declared. This is needed for example after Copy or Cut
3795 * and then paste operations. The subtree may still hold pointers to
3796 * namespace declarations outside the subtree or invalid/masked. As much
3797 * as possible the function try tu reuse the existing namespaces found in
3798 * the new environment. If not possible the new namespaces are redeclared
3799 * on @tree at the top of the given subtree.
3800 * Returns the number of namespace declarations created or -1 in case of error.
3801 */
3802int
3803xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
3804 xmlNsPtr *oldNs = NULL;
3805 xmlNsPtr *newNs = NULL;
3806 int sizeCache = 0;
3807 int nbCache = 0;
3808
3809 xmlNsPtr n;
3810 xmlNodePtr node = tree;
3811 xmlAttrPtr attr;
3812 int ret = 0, i;
3813
3814 while (node != NULL) {
3815 /*
3816 * Reconciliate the node namespace
3817 */
3818 if (node->ns != NULL) {
3819 /*
3820 * initialize the cache if needed
3821 */
3822 if (sizeCache == 0) {
3823 sizeCache = 10;
3824 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3825 sizeof(xmlNsPtr));
3826 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003827 xmlGenericError(xmlGenericErrorContext,
3828 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003829 return(-1);
3830 }
3831 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3832 sizeof(xmlNsPtr));
3833 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003834 xmlGenericError(xmlGenericErrorContext,
3835 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003836 xmlFree(oldNs);
3837 return(-1);
3838 }
3839 }
3840 for (i = 0;i < nbCache;i++) {
3841 if (oldNs[i] == node->ns) {
3842 node->ns = newNs[i];
3843 break;
3844 }
3845 }
3846 if (i == nbCache) {
3847 /*
3848 * Ok we need to recreate a new namespace definition
3849 */
3850 n = xmlNewReconciliedNs(doc, tree, node->ns);
3851 if (n != NULL) { /* :-( what if else ??? */
3852 /*
3853 * check if we need to grow the cache buffers.
3854 */
3855 if (sizeCache <= nbCache) {
3856 sizeCache *= 2;
3857 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3858 sizeof(xmlNsPtr));
3859 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003860 xmlGenericError(xmlGenericErrorContext,
3861 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003862 xmlFree(newNs);
3863 return(-1);
3864 }
3865 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3866 sizeof(xmlNsPtr));
3867 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003868 xmlGenericError(xmlGenericErrorContext,
3869 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003870 xmlFree(oldNs);
3871 return(-1);
3872 }
3873 }
3874 newNs[nbCache] = n;
3875 oldNs[nbCache++] = node->ns;
3876 node->ns = n;
3877 }
3878 }
3879 }
3880 /*
3881 * now check for namespace hold by attributes on the node.
3882 */
3883 attr = node->properties;
3884 while (attr != NULL) {
3885 if (attr->ns != NULL) {
3886 /*
3887 * initialize the cache if needed
3888 */
3889 if (sizeCache == 0) {
3890 sizeCache = 10;
3891 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3892 sizeof(xmlNsPtr));
3893 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003894 xmlGenericError(xmlGenericErrorContext,
3895 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003896 return(-1);
3897 }
3898 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3899 sizeof(xmlNsPtr));
3900 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003901 xmlGenericError(xmlGenericErrorContext,
3902 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003903 xmlFree(oldNs);
3904 return(-1);
3905 }
3906 }
3907 for (i = 0;i < nbCache;i++) {
3908 if (oldNs[i] == attr->ns) {
3909 node->ns = newNs[i];
3910 break;
3911 }
3912 }
3913 if (i == nbCache) {
3914 /*
3915 * Ok we need to recreate a new namespace definition
3916 */
3917 n = xmlNewReconciliedNs(doc, tree, attr->ns);
3918 if (n != NULL) { /* :-( what if else ??? */
3919 /*
3920 * check if we need to grow the cache buffers.
3921 */
3922 if (sizeCache <= nbCache) {
3923 sizeCache *= 2;
3924 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3925 sizeof(xmlNsPtr));
3926 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003927 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003928 "xmlReconciliateNs : memory pbm\n");
3929 xmlFree(newNs);
3930 return(-1);
3931 }
3932 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3933 sizeof(xmlNsPtr));
3934 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003935 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003936 "xmlReconciliateNs : memory pbm\n");
3937 xmlFree(oldNs);
3938 return(-1);
3939 }
3940 }
3941 newNs[nbCache] = n;
3942 oldNs[nbCache++] = attr->ns;
3943 attr->ns = n;
3944 }
3945 }
3946 }
3947 attr = attr->next;
3948 }
3949
3950 /*
3951 * Browse the full subtree, deep first
3952 */
Daniel Veillardcf461992000-03-14 18:30:20 +00003953 if (node->children != NULL) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003954 /* deep first */
Daniel Veillardcf461992000-03-14 18:30:20 +00003955 node = node->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003956 } else if ((node != tree) && (node->next != NULL)) {
3957 /* then siblings */
3958 node = node->next;
3959 } else if (node != tree) {
3960 /* go up to parents->next if needed */
3961 while (node != tree) {
3962 if (node->parent != NULL)
3963 node = node->parent;
3964 if ((node != tree) && (node->next != NULL)) {
3965 node = node->next;
3966 break;
3967 }
3968 if (node->parent == NULL) {
3969 node = NULL;
3970 break;
3971 }
3972 }
3973 /* exit condition */
3974 if (node == tree)
3975 node = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003976 }
3977 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003978 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003979}
3980
Daniel Veillard97b58771998-10-20 06:14:16 +00003981/**
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003982 * xmlHasProp:
3983 * @node: the node
3984 * @name: the attribute name
3985 *
3986 * Search an attribute associated to a node
3987 * This function also looks in DTD attribute declaration for #FIXED or
3988 * default declaration values unless DTD use has been turned off.
3989 *
3990 * Returns the attribute or the attribute declaration or NULL if
3991 * neither was found.
3992 */
3993xmlAttrPtr
3994xmlHasProp(xmlNodePtr node, const xmlChar *name) {
3995 xmlAttrPtr prop;
3996 xmlDocPtr doc;
3997
3998 if ((node == NULL) || (name == NULL)) return(NULL);
3999 /*
4000 * Check on the properties attached to the node
4001 */
4002 prop = node->properties;
4003 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004004 if (xmlStrEqual(prop->name, name)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004005 return(prop);
4006 }
4007 prop = prop->next;
4008 }
4009 if (!xmlCheckDTD) return(NULL);
4010
4011 /*
4012 * Check if there is a default declaration in the internal
4013 * or external subsets
4014 */
4015 doc = node->doc;
4016 if (doc != NULL) {
4017 xmlAttributePtr attrDecl;
4018 if (doc->intSubset != NULL) {
4019 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4020 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4021 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4022 if (attrDecl != NULL)
4023 return((xmlAttrPtr) attrDecl);
4024 }
4025 }
4026 return(NULL);
4027}
4028
4029/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004030 * xmlGetProp:
4031 * @node: the node
4032 * @name: the attribute name
4033 *
4034 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00004035 * This does the entity substitution.
Daniel Veillard10a2c651999-12-12 13:03:50 +00004036 * This function looks in DTD attribute declaration for #FIXED or
4037 * default declaration values unless DTD use has been turned off.
4038 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004039 * Returns the attribute value or NULL if not found.
Daniel Veillarda819dac1999-11-24 18:04:22 +00004040 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004041 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00004042xmlChar *
4043xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00004044 xmlAttrPtr prop;
4045 xmlDocPtr doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004046
Daniel Veillard10a2c651999-12-12 13:03:50 +00004047 if ((node == NULL) || (name == NULL)) return(NULL);
4048 /*
4049 * Check on the properties attached to the node
4050 */
4051 prop = node->properties;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004052 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004053 if (xmlStrEqual(prop->name, name)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004054 xmlChar *ret;
Daniel Veillard6800ef31999-02-08 18:33:22 +00004055
Daniel Veillardcf461992000-03-14 18:30:20 +00004056 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004057 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
Daniel Veillard6800ef31999-02-08 18:33:22 +00004058 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00004059 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004060 prop = prop->next;
4061 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00004062 if (!xmlCheckDTD) return(NULL);
4063
4064 /*
4065 * Check if there is a default declaration in the internal
4066 * or external subsets
4067 */
4068 doc = node->doc;
4069 if (doc != NULL) {
4070 xmlAttributePtr attrDecl;
4071 if (doc->intSubset != NULL) {
4072 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4073 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4074 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillardf967b902000-01-17 16:06:10 +00004075 if (attrDecl != NULL)
4076 return(xmlStrdup(attrDecl->defaultValue));
Daniel Veillard10a2c651999-12-12 13:03:50 +00004077 }
4078 }
4079 return(NULL);
4080}
4081
4082/**
4083 * xmlGetNsProp:
4084 * @node: the node
4085 * @name: the attribute name
4086 * @namespace: the URI of the namespace
4087 *
4088 * Search and get the value of an attribute associated to a node
4089 * This attribute has to be anchored in the namespace specified.
4090 * This does the entity substitution.
4091 * This function looks in DTD attribute declaration for #FIXED or
4092 * default declaration values unless DTD use has been turned off.
4093 *
4094 * Returns the attribute value or NULL if not found.
4095 * It's up to the caller to free the memory.
4096 */
4097xmlChar *
4098xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00004099 xmlAttrPtr prop;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004100 xmlDocPtr doc;
4101 xmlNsPtr ns;
4102
Daniel Veillard389e6b72001-01-15 19:41:13 +00004103 if (node == NULL)
4104 return(NULL);
4105
4106 prop = node->properties;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004107 if (namespace == NULL)
4108 return(xmlGetProp(node, name));
4109 while (prop != NULL) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00004110 /*
4111 * One need to have
4112 * - same attribute names
4113 * - and the attribute carrying that namespace
4114 * or
4115 * no namespace on the attribute and the element carrying it
4116 */
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004117 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00004118 (((prop->ns == NULL) && (node->ns != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004119 (xmlStrEqual(node->ns->href, namespace))) ||
4120 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, namespace))))) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00004121 xmlChar *ret;
4122
Daniel Veillardcf461992000-03-14 18:30:20 +00004123 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillard10a2c651999-12-12 13:03:50 +00004124 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4125 return(ret);
4126 }
4127 prop = prop->next;
4128 }
4129 if (!xmlCheckDTD) return(NULL);
4130
4131 /*
4132 * Check if there is a default declaration in the internal
4133 * or external subsets
4134 */
4135 doc = node->doc;
4136 if (doc != NULL) {
4137 xmlAttributePtr attrDecl;
4138 if (doc->intSubset != NULL) {
4139 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4140 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4141 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4142
Daniel Veillardc2f4df22001-01-04 14:06:39 +00004143 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00004144 /*
4145 * The DTD declaration only allows a prefix search
4146 */
4147 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004148 if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
Daniel Veillard10a2c651999-12-12 13:03:50 +00004149 return(xmlStrdup(attrDecl->defaultValue));
4150 }
4151 }
4152 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004153 return(NULL);
4154}
4155
Daniel Veillard97b58771998-10-20 06:14:16 +00004156/**
Daniel Veillardccb09631998-10-27 06:21:04 +00004157 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00004158 * @node: the node
4159 * @name: the attribute name
4160 * @value: the attribute value
4161 *
4162 * Set (or reset) an attribute carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00004163 * Returns the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004164 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004165xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004166xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004167 xmlAttrPtr prop = node->properties;
Daniel Veillarde4566462001-01-22 09:58:39 +00004168 xmlDocPtr doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004169
Daniel Veillarde4566462001-01-22 09:58:39 +00004170 if ((node == NULL) || (name == NULL))
4171 return(NULL);
4172 doc = node->doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004173 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004174 if (xmlStrEqual(prop->name, name)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00004175 if (prop->children != NULL)
4176 xmlFreeNodeList(prop->children);
4177 prop->children = NULL;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004178 prop->last = NULL;
Daniel Veillard51e3b151999-11-12 17:02:31 +00004179 if (value != NULL) {
4180 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +00004181 xmlNodePtr tmp;
4182
Daniel Veillard51e3b151999-11-12 17:02:31 +00004183 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +00004184 prop->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004185 prop->last = NULL;
Daniel Veillarde4566462001-01-22 09:58:39 +00004186 prop->doc = doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00004187 tmp = prop->children;
4188 while (tmp != NULL) {
4189 tmp->parent = (xmlNodePtr) prop;
Daniel Veillarde4566462001-01-22 09:58:39 +00004190 tmp->doc = doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00004191 if (tmp->next == NULL)
4192 prop->last = tmp;
4193 tmp = tmp->next;
4194 }
Daniel Veillard51e3b151999-11-12 17:02:31 +00004195 xmlFree(buffer);
4196 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004197 return(prop);
4198 }
4199 prop = prop->next;
4200 }
4201 prop = xmlNewProp(node, name, value);
4202 return(prop);
4203}
4204
Daniel Veillard97b58771998-10-20 06:14:16 +00004205/**
Daniel Veillard389e6b72001-01-15 19:41:13 +00004206 * xmlSetNsProp:
4207 * @node: the node
4208 * @ns: the namespace definition
4209 * @name: the attribute name
4210 * @value: the attribute value
4211 *
4212 * Set (or reset) an attribute carried by a node.
4213 * The ns structure must be in scope, this is not checked.
4214 *
4215 * Returns the attribute pointer.
4216 */
4217xmlAttrPtr
4218xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4219 const xmlChar *value) {
4220 xmlAttrPtr prop;
4221
4222 if ((node == NULL) || (name == NULL))
4223 return(NULL);
4224
4225 if (ns == NULL)
4226 return(xmlSetProp(node, name, value));
4227 if (ns->href == NULL)
4228 return(NULL);
4229 prop = node->properties;
4230
4231 while (prop != NULL) {
4232 /*
4233 * One need to have
4234 * - same attribute names
4235 * - and the attribute carrying that namespace
4236 * or
4237 * no namespace on the attribute and the element carrying it
4238 */
4239 if ((xmlStrEqual(prop->name, name)) &&
4240 (((prop->ns == NULL) && (node->ns != NULL) &&
4241 (xmlStrEqual(node->ns->href, ns->href))) ||
4242 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4243 if (prop->children != NULL)
4244 xmlFreeNodeList(prop->children);
4245 prop->children = NULL;
4246 prop->last = NULL;
4247 prop->ns = ns;
4248 if (value != NULL) {
4249 xmlChar *buffer;
4250 xmlNodePtr tmp;
4251
4252 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4253 prop->children = xmlStringGetNodeList(node->doc, buffer);
4254 prop->last = NULL;
4255 tmp = prop->children;
4256 while (tmp != NULL) {
4257 tmp->parent = (xmlNodePtr) prop;
4258 if (tmp->next == NULL)
4259 prop->last = tmp;
4260 tmp = tmp->next;
4261 }
4262 xmlFree(buffer);
4263 }
4264 return(prop);
4265 }
4266 prop = prop->next;
4267 }
4268 prop = xmlNewNsProp(node, ns, name, value);
4269 return(prop);
4270}
4271
4272/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004273 * xmlNodeIsText:
4274 * @node: the node
4275 *
4276 * Is this node a Text node ?
Daniel Veillard1e346af1999-02-22 10:33:01 +00004277 * Returns 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00004278 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004279int
4280xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004281 if (node == NULL) return(0);
4282
Daniel Veillard0bef1311998-10-14 02:36:47 +00004283 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004284 return(0);
4285}
4286
Daniel Veillard97b58771998-10-20 06:14:16 +00004287/**
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004288 * xmlIsBlankNode:
4289 * @node: the node
4290 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004291 * Checks whether this node is an empty or whitespace only
4292 * (and possibly ignorable) text-node.
4293 *
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004294 * Returns 1 yes, 0 no
4295 */
4296int
4297xmlIsBlankNode(xmlNodePtr node) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004298 const xmlChar *cur;
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004299 if (node == NULL) return(0);
4300
4301 if (node->type != XML_TEXT_NODE) return(0);
Daniel Veillardcd429612000-10-11 15:57:05 +00004302 if (node->content == NULL) return(1);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004303#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004304 cur = node->content;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004305#else
4306 cur = xmlBufferContent(node->content);
4307#endif
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004308 while (*cur != 0) {
4309 if (!IS_BLANK(*cur)) return(0);
4310 cur++;
4311 }
4312
4313 return(1);
4314}
4315
4316/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00004317 * xmlTextConcat:
Daniel Veillard97b58771998-10-20 06:14:16 +00004318 * @node: the node
4319 * @content: the content
4320 * @len: @content lenght
4321 *
4322 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00004323 */
Daniel Veillard97b58771998-10-20 06:14:16 +00004324
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004325void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004326xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004327 if (node == NULL) return;
4328
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004329 if ((node->type != XML_TEXT_NODE) &&
4330 (node->type != XML_CDATA_SECTION_NODE)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004331#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004332 xmlGenericError(xmlGenericErrorContext,
4333 "xmlTextConcat: node is not text nor cdata\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004334#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004335 return;
4336 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004337#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00004338 node->content = xmlStrncat(node->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004339#else
4340 xmlBufferAdd(node->content, content, len);
4341#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004342}
4343
4344/************************************************************************
4345 * *
4346 * Output : to a FILE or in memory *
4347 * *
4348 ************************************************************************/
4349
Daniel Veillard5099ae81999-04-21 20:12:07 +00004350#define BASE_BUFFER_SIZE 4000
4351
4352/**
4353 * xmlBufferCreate:
4354 *
4355 * routine to create an XML buffer.
4356 * returns the new structure.
4357 */
4358xmlBufferPtr
4359xmlBufferCreate(void) {
4360 xmlBufferPtr ret;
4361
Daniel Veillard6454aec1999-09-02 22:04:43 +00004362 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
Daniel Veillard5099ae81999-04-21 20:12:07 +00004363 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004364 xmlGenericError(xmlGenericErrorContext,
4365 "xmlBufferCreate : out of memory!\n");
Daniel Veillard5099ae81999-04-21 20:12:07 +00004366 return(NULL);
4367 }
4368 ret->use = 0;
4369 ret->size = BASE_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004370 ret->alloc = xmlBufferAllocScheme;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004371 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
Daniel Veillard5099ae81999-04-21 20:12:07 +00004372 if (ret->content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004373 xmlGenericError(xmlGenericErrorContext,
4374 "xmlBufferCreate : out of memory!\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00004375 xmlFree(ret);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004376 return(NULL);
4377 }
4378 ret->content[0] = 0;
4379 return(ret);
4380}
4381
4382/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004383 * xmlBufferCreateSize:
4384 * @size: initial size of buffer
4385 *
4386 * routine to create an XML buffer.
4387 * returns the new structure.
4388 */
4389xmlBufferPtr
4390xmlBufferCreateSize(size_t size) {
4391 xmlBufferPtr ret;
4392
4393 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4394 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004395 xmlGenericError(xmlGenericErrorContext,
4396 "xmlBufferCreate : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004397 return(NULL);
4398 }
4399 ret->use = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004400 ret->alloc = xmlBufferAllocScheme;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004401 ret->size = (size ? size+2 : 0); /* +1 for ending null */
Daniel Veillard10a2c651999-12-12 13:03:50 +00004402 if (ret->size){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004403 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4404 if (ret->content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004405 xmlGenericError(xmlGenericErrorContext,
4406 "xmlBufferCreate : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004407 xmlFree(ret);
4408 return(NULL);
4409 }
4410 ret->content[0] = 0;
4411 } else
4412 ret->content = NULL;
4413 return(ret);
4414}
4415
4416/**
Daniel Veillard06047432000-04-24 11:33:38 +00004417 * xmlBufferSetAllocationScheme:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004418 * @buf: the buffer to free
4419 * @scheme: allocation scheme to use
4420 *
4421 * Sets the allocation scheme for this buffer
4422 */
4423void
4424xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4425 xmlBufferAllocationScheme scheme) {
4426 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004427#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004428 xmlGenericError(xmlGenericErrorContext,
4429 "xmlBufferSetAllocationScheme: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004430#endif
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004431 return;
4432 }
4433
4434 buf->alloc = scheme;
4435}
4436
4437/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004438 * xmlBufferFree:
4439 * @buf: the buffer to free
4440 *
4441 * Frees an XML buffer.
4442 */
4443void
4444xmlBufferFree(xmlBufferPtr buf) {
4445 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004446#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004447 xmlGenericError(xmlGenericErrorContext,
4448 "xmlBufferFree: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004449#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004450 return;
4451 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004452 if (buf->content != NULL) {
4453#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00004454 memset(buf->content, -1, BASE_BUFFER_SIZE);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004455#else
4456 memset(buf->content, -1, buf->size);
4457#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004458 xmlFree(buf->content);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004459 }
4460 memset(buf, -1, sizeof(xmlBuffer));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004461 xmlFree(buf);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004462}
4463
4464/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004465 * xmlBufferEmpty:
4466 * @buf: the buffer
4467 *
4468 * empty a buffer.
4469 */
4470void
4471xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +00004472 if (buf->content == NULL) return;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004473 buf->use = 0;
4474 memset(buf->content, -1, buf->size);/* just for debug */
4475}
4476
4477/**
4478 * xmlBufferShrink:
4479 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004480 * @len: the number of xmlChar to remove
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004481 *
4482 * Remove the beginning of an XML buffer.
4483 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004484 * Returns the number of xmlChar removed, or -1 in case of failure.
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004485 */
4486int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004487xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004488 if (len == 0) return(0);
4489 if (len > buf->use) return(-1);
4490
4491 buf->use -= len;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004492 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004493
4494 buf->content[buf->use] = 0;
4495 return(len);
4496}
4497
4498/**
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004499 * xmlBufferGrow:
4500 * @buf: the buffer
Daniel Veillard4a6845d2001-01-03 13:32:39 +00004501 * @len: the minimum free size to allocate
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004502 *
4503 * Grow the available space of an XML buffer.
4504 *
4505 * Returns the new available space or -1 in case of error
4506 */
4507int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004508xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004509 int size;
4510 xmlChar *newbuf;
4511
Daniel Veillard4a6845d2001-01-03 13:32:39 +00004512 if (len + buf->use < buf->size) return(0);
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004513
Daniel Veillardbe803962000-06-28 23:40:59 +00004514 size = buf->use + len + 100;
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004515
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004516 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004517 if (newbuf == NULL) return(-1);
4518 buf->content = newbuf;
4519 buf->size = size;
4520 return(buf->size - buf->use);
4521}
4522
4523/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004524 * xmlBufferDump:
4525 * @file: the file output
4526 * @buf: the buffer to dump
4527 *
4528 * Dumps an XML buffer to a FILE *.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004529 * Returns the number of xmlChar written
Daniel Veillard5099ae81999-04-21 20:12:07 +00004530 */
4531int
4532xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4533 int ret;
4534
4535 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004536#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004537 xmlGenericError(xmlGenericErrorContext,
4538 "xmlBufferDump: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004539#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004540 return(0);
4541 }
4542 if (buf->content == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004543#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004544 xmlGenericError(xmlGenericErrorContext,
4545 "xmlBufferDump: buf->content == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004546#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004547 return(0);
4548 }
4549 if (file == NULL) file = stdout;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004550 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004551 return(ret);
4552}
4553
4554/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004555 * xmlBufferContent:
4556 * @buf: the buffer to resize
4557 *
4558 * Returns the internal content
4559 */
4560
4561const xmlChar*
4562xmlBufferContent(const xmlBufferPtr buf)
4563{
4564 if(!buf)
4565 return NULL;
4566
4567 return buf->content;
4568}
4569
4570/**
4571 * xmlBufferLength:
4572 * @buf: the buffer
4573 *
4574 * Returns the length of data in the internal content
4575 */
4576
4577int
4578xmlBufferLength(const xmlBufferPtr buf)
4579{
4580 if(!buf)
4581 return 0;
4582
4583 return buf->use;
4584}
4585
4586/**
4587 * xmlBufferResize:
4588 * @buf: the buffer to resize
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004589 * @size: the desired size
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004590 *
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004591 * Resize a buffer to accomodate minimum size of @size.
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004592 *
4593 * Returns 0 in case of problems, 1 otherwise
4594 */
4595int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004596xmlBufferResize(xmlBufferPtr buf, unsigned int size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004597{
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004598 unsigned int newSize;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004599 xmlChar* rebuf = NULL;
4600
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004601 /*take care of empty case*/
4602 newSize = (buf->size ? buf->size*2 : size);
4603
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004604 /* Don't resize if we don't have to */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004605 if (size < buf->size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004606 return 1;
4607
4608 /* figure out new size */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004609 switch (buf->alloc){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004610 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004611 while (size > newSize) newSize *= 2;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004612 break;
4613 case XML_BUFFER_ALLOC_EXACT:
4614 newSize = size+10;
4615 break;
4616 default:
4617 newSize = size+10;
4618 break;
4619 }
4620
4621 if (buf->content == NULL)
4622 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
4623 else
4624 rebuf = (xmlChar *) xmlRealloc(buf->content,
4625 newSize * sizeof(xmlChar));
4626 if (rebuf == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004627 xmlGenericError(xmlGenericErrorContext,
4628 "xmlBufferAdd : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004629 return 0;
4630 }
4631 buf->content = rebuf;
4632 buf->size = newSize;
4633
4634 return 1;
4635}
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004636
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004637/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004638 * xmlBufferAdd:
4639 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004640 * @str: the xmlChar string
4641 * @len: the number of xmlChar to add
Daniel Veillard5099ae81999-04-21 20:12:07 +00004642 *
Daniel Veillard10a2c651999-12-12 13:03:50 +00004643 * Add a string range to an XML buffer. if len == -1, the lenght of
4644 * str is recomputed.
Daniel Veillard5099ae81999-04-21 20:12:07 +00004645 */
4646void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004647xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004648 unsigned int needSize;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004649
4650 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004651#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004652 xmlGenericError(xmlGenericErrorContext,
4653 "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004654#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004655 return;
4656 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00004657 if (len < -1) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004658#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004659 xmlGenericError(xmlGenericErrorContext,
4660 "xmlBufferAdd: len < 0\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004661#endif
Daniel Veillard10a2c651999-12-12 13:03:50 +00004662 return;
4663 }
4664 if (len == 0) return;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004665
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004666 if (len < 0)
Daniel Veillardcf461992000-03-14 18:30:20 +00004667 len = xmlStrlen(str);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004668
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004669 if (len <= 0) return;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004670
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004671 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004672 if (needSize > buf->size){
4673 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004674 xmlGenericError(xmlGenericErrorContext,
4675 "xmlBufferAdd : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004676 return;
4677 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004678 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004679
4680 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004681 buf->use += len;
4682 buf->content[buf->use] = 0;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004683}
4684
4685/**
Daniel Veillardbe803962000-06-28 23:40:59 +00004686 * xmlBufferAddHead:
4687 * @buf: the buffer
4688 * @str: the xmlChar string
4689 * @len: the number of xmlChar to add
4690 *
4691 * Add a string range to the beginning of an XML buffer.
4692 * if len == -1, the lenght of @str is recomputed.
4693 */
4694void
4695xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004696 unsigned int needSize;
Daniel Veillardbe803962000-06-28 23:40:59 +00004697
4698 if (str == NULL) {
4699#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004700 xmlGenericError(xmlGenericErrorContext,
4701 "xmlBufferAdd: str == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004702#endif
4703 return;
4704 }
4705 if (len < -1) {
4706#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004707 xmlGenericError(xmlGenericErrorContext,
4708 "xmlBufferAdd: len < 0\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004709#endif
4710 return;
4711 }
4712 if (len == 0) return;
4713
4714 if (len < 0)
4715 len = xmlStrlen(str);
4716
4717 if (len <= 0) return;
4718
4719 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004720 if (needSize > buf->size){
4721 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004722 xmlGenericError(xmlGenericErrorContext,
4723 "xmlBufferAddHead : out of memory!\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004724 return;
4725 }
4726 }
4727
4728 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
4729 memmove(&buf->content[0], str, len * sizeof(xmlChar));
4730 buf->use += len;
4731 buf->content[buf->use] = 0;
4732}
4733
4734/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004735 * xmlBufferCat:
4736 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004737 * @str: the xmlChar string
Daniel Veillard5099ae81999-04-21 20:12:07 +00004738 *
4739 * Append a zero terminated string to an XML buffer.
4740 */
4741void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004742xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004743 if (str != NULL)
4744 xmlBufferAdd(buf, str, -1);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004745}
4746
4747/**
4748 * xmlBufferCCat:
4749 * @buf: the buffer to dump
4750 * @str: the C char string
4751 *
4752 * Append a zero terminated C string to an XML buffer.
4753 */
4754void
4755xmlBufferCCat(xmlBufferPtr buf, const char *str) {
4756 const char *cur;
4757
4758 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004759#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004760 xmlGenericError(xmlGenericErrorContext,
4761 "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004762#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004763 return;
4764 }
4765 for (cur = str;*cur != 0;cur++) {
4766 if (buf->use + 10 >= buf->size) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004767 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004768 xmlGenericError(xmlGenericErrorContext,
4769 "xmlBufferCCat : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004770 return;
4771 }
4772 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004773 buf->content[buf->use++] = *cur;
4774 }
Daniel Veillard65c295d2001-01-26 09:32:39 +00004775 buf->content[buf->use] = 0;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004776}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004777
Daniel Veillard97b58771998-10-20 06:14:16 +00004778/**
4779 * xmlBufferWriteCHAR:
Daniel Veillard5099ae81999-04-21 20:12:07 +00004780 * @buf: the XML buffer
Daniel Veillard97b58771998-10-20 06:14:16 +00004781 * @string: the string to add
4782 *
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004783 * routine which manages and grows an output buffer. This one adds
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004784 * xmlChars at the end of the buffer.
Daniel Veillard97b58771998-10-20 06:14:16 +00004785 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004786void
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004787#ifdef VMS
4788xmlBufferWriteXmlCHAR
4789#else
4790xmlBufferWriteCHAR
4791#endif
4792(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004793 xmlBufferCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004794}
4795
Daniel Veillard97b58771998-10-20 06:14:16 +00004796/**
4797 * xmlBufferWriteChar:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004798 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004799 * @string: the string to add
4800 *
4801 * routine which manage and grows an output buffer. This one add
4802 * C chars at the end of the array.
4803 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004804void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004805xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
4806 xmlBufferCCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004807}
4808
Daniel Veillard5099ae81999-04-21 20:12:07 +00004809
Daniel Veillard97b58771998-10-20 06:14:16 +00004810/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004811 * xmlBufferWriteQuotedString:
4812 * @buf: the XML buffer output
4813 * @string: the string to add
4814 *
4815 * routine which manage and grows an output buffer. This one writes
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004816 * a quoted or double quoted xmlChar string, checking first if it holds
Daniel Veillard011b63c1999-06-02 17:44:04 +00004817 * quote or double-quotes internally
4818 */
4819void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004820xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004821 if (xmlStrchr(string, '"')) {
4822 if (xmlStrchr(string, '\'')) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004823#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004824 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard011b63c1999-06-02 17:44:04 +00004825 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004826#endif
Daniel Veillard011b63c1999-06-02 17:44:04 +00004827 }
4828 xmlBufferCCat(buf, "'");
4829 xmlBufferCat(buf, string);
4830 xmlBufferCCat(buf, "'");
4831 } else {
4832 xmlBufferCCat(buf, "\"");
4833 xmlBufferCat(buf, string);
4834 xmlBufferCCat(buf, "\"");
4835 }
4836}
4837
4838
Daniel Veillardbe803962000-06-28 23:40:59 +00004839/************************************************************************
4840 * *
4841 * Dumping XML tree content to a simple buffer *
4842 * *
4843 ************************************************************************/
4844
Daniel Veillardb656ebe2000-09-22 13:51:48 +00004845void
Daniel Veillardcf461992000-03-14 18:30:20 +00004846xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4847 int format);
4848static void
4849xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4850 int format);
4851void
4852htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
4853
Daniel Veillard011b63c1999-06-02 17:44:04 +00004854/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004855 * xmlNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004856 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004857 * @cur: a namespace
4858 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004859 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00004860 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004861 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004862static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004863xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004864 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004865#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004866 xmlGenericError(xmlGenericErrorContext,
4867 "xmlNsDump : Ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004868#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004869 return;
4870 }
4871 if (cur->type == XML_LOCAL_NAMESPACE) {
4872 /* Within the context of an element attributes */
4873 if (cur->prefix != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004874 xmlBufferWriteChar(buf, " xmlns:");
4875 xmlBufferWriteCHAR(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004876 } else
Daniel Veillard5099ae81999-04-21 20:12:07 +00004877 xmlBufferWriteChar(buf, " xmlns");
Daniel Veillard011b63c1999-06-02 17:44:04 +00004878 xmlBufferWriteChar(buf, "=");
4879 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004880 }
4881}
4882
Daniel Veillard97b58771998-10-20 06:14:16 +00004883/**
4884 * xmlNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004885 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004886 * @cur: the first namespace
4887 *
4888 * Dump a list of local Namespace definitions.
4889 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004890 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004891static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004892xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004893 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004894 xmlNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004895 cur = cur->next;
4896 }
4897}
4898
Daniel Veillard97b58771998-10-20 06:14:16 +00004899/**
4900 * xmlDtdDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004901 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004902 * @doc: the document
4903 *
4904 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004905 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004906static void
Daniel Veillardcf461992000-03-14 18:30:20 +00004907xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
4908 if (dtd == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004909#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004910 xmlGenericError(xmlGenericErrorContext,
4911 "xmlDtdDump : no internal subset\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004912#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004913 return;
4914 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004915 xmlBufferWriteChar(buf, "<!DOCTYPE ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004916 xmlBufferWriteCHAR(buf, dtd->name);
4917 if (dtd->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004918 xmlBufferWriteChar(buf, " PUBLIC ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004919 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004920 xmlBufferWriteChar(buf, " ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004921 xmlBufferWriteQuotedString(buf, dtd->SystemID);
4922 } else if (dtd->SystemID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004923 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004924 xmlBufferWriteQuotedString(buf, dtd->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004925 }
Daniel Veillardcf461992000-03-14 18:30:20 +00004926 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
4927 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
4928 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004929 return;
4930 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004931 xmlBufferWriteChar(buf, " [\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00004932 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
4933#if 0
4934 if (dtd->entities != NULL)
4935 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
4936 if (dtd->notations != NULL)
4937 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
4938 if (dtd->elements != NULL)
4939 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
4940 if (dtd->attributes != NULL)
4941 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
4942#endif
4943 xmlBufferWriteChar(buf, "]>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004944}
4945
Daniel Veillard97b58771998-10-20 06:14:16 +00004946/**
4947 * xmlAttrDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004948 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004949 * @doc: the document
4950 * @cur: the attribute pointer
4951 *
4952 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00004953 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004954static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004955xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004956 xmlChar *value;
Daniel Veillardccb09631998-10-27 06:21:04 +00004957
Daniel Veillard260a68f1998-08-13 03:39:55 +00004958 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004959#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004960 xmlGenericError(xmlGenericErrorContext,
4961 "xmlAttrDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004962#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004963 return;
4964 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004965 xmlBufferWriteChar(buf, " ");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004966 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4967 xmlBufferWriteCHAR(buf, cur->ns->prefix);
4968 xmlBufferWriteChar(buf, ":");
4969 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004970 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00004971 value = xmlNodeListGetString(doc, cur->children, 0);
Daniel Veillardf060a412001-01-03 20:52:44 +00004972 if (value != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004973 xmlBufferWriteChar(buf, "=");
4974 xmlBufferWriteQuotedString(buf, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004975 xmlFree(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00004976 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004977 xmlBufferWriteChar(buf, "=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004978 }
4979}
4980
Daniel Veillard97b58771998-10-20 06:14:16 +00004981/**
4982 * xmlAttrListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004983 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004984 * @doc: the document
4985 * @cur: the first attribute pointer
4986 *
4987 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00004988 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004989static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004990xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004991 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004992#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004993 xmlGenericError(xmlGenericErrorContext,
4994 "xmlAttrListDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004995#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004996 return;
4997 }
4998 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004999 xmlAttrDump(buf, doc, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005000 cur = cur->next;
5001 }
5002}
5003
Daniel Veillard260a68f1998-08-13 03:39:55 +00005004
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005005
Daniel Veillard97b58771998-10-20 06:14:16 +00005006/**
5007 * xmlNodeListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00005008 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00005009 * @doc: the document
5010 * @cur: the first node
Daniel Veillardcf461992000-03-14 18:30:20 +00005011 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005012 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00005013 *
5014 * Dump an XML node list, recursive behaviour,children are printed too.
5015 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005016static void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005017xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5018 int format) {
5019 int i;
Daniel Veillardccb09631998-10-27 06:21:04 +00005020
Daniel Veillard260a68f1998-08-13 03:39:55 +00005021 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00005022#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005023 xmlGenericError(xmlGenericErrorContext,
5024 "xmlNodeListDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00005025#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00005026 return;
5027 }
5028 while (cur != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005029 if ((format) && (xmlIndentTreeOutput) &&
5030 (cur->type == XML_ELEMENT_NODE))
5031 for (i = 0;i < level;i++)
5032 xmlBufferWriteChar(buf, " ");
5033 xmlNodeDump(buf, doc, cur, level, format);
5034 if (format) {
5035 xmlBufferWriteChar(buf, "\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00005036 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005037 cur = cur->next;
5038 }
5039}
5040
Daniel Veillard97b58771998-10-20 06:14:16 +00005041/**
Daniel Veillardccb09631998-10-27 06:21:04 +00005042 * xmlNodeDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00005043 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00005044 * @doc: the document
5045 * @cur: the current node
Daniel Veillardcf461992000-03-14 18:30:20 +00005046 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005047 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00005048 *
5049 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005050 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005051void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005052xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5053 int format) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005054 int i;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005055 xmlNodePtr tmp;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005056
5057 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00005058#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005059 xmlGenericError(xmlGenericErrorContext,
5060 "xmlNodeDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00005061#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00005062 return;
5063 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00005064 if (cur->type == XML_XINCLUDE_START)
5065 return;
5066 if (cur->type == XML_XINCLUDE_END)
5067 return;
Daniel Veillardcf461992000-03-14 18:30:20 +00005068 if (cur->type == XML_DTD_NODE) {
5069 xmlDtdDump(buf, (xmlDtdPtr) cur);
5070 return;
5071 }
5072 if (cur->type == XML_ELEMENT_DECL) {
5073 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5074 return;
5075 }
5076 if (cur->type == XML_ATTRIBUTE_DECL) {
5077 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5078 return;
5079 }
5080 if (cur->type == XML_ENTITY_DECL) {
5081 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5082 return;
5083 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00005084 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard14fff061999-06-22 21:49:07 +00005085 if (cur->content != NULL) {
Daniel Veillardf6eea272001-01-18 12:17:12 +00005086 if ((cur->name == xmlStringText) ||
5087 (cur->name != xmlStringTextNoenc)) {
5088 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00005089
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005090#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardf6eea272001-01-18 12:17:12 +00005091 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005092#else
Daniel Veillardf6eea272001-01-18 12:17:12 +00005093 buffer = xmlEncodeEntitiesReentrant(doc,
5094 xmlBufferContent(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005095#endif
Daniel Veillardf6eea272001-01-18 12:17:12 +00005096 if (buffer != NULL) {
5097 xmlBufferWriteCHAR(buf, buffer);
5098 xmlFree(buffer);
5099 }
5100 } else {
5101 /*
5102 * Disable escaping, needed for XSLT
5103 */
5104#ifndef XML_USE_BUFFER_CONTENT
5105 xmlBufferWriteCHAR(buf, cur->content);
5106#else
5107 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5108#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00005109 }
5110 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005111 return;
5112 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00005113 if (cur->type == XML_PI_NODE) {
5114 if (cur->content != NULL) {
5115 xmlBufferWriteChar(buf, "<?");
5116 xmlBufferWriteCHAR(buf, cur->name);
5117 if (cur->content != NULL) {
5118 xmlBufferWriteChar(buf, " ");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005119#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00005120 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005121#else
5122 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5123#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00005124 }
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005125 xmlBufferWriteChar(buf, "?>");
Daniel Veillardcf461992000-03-14 18:30:20 +00005126 } else {
5127 xmlBufferWriteChar(buf, "<?");
5128 xmlBufferWriteCHAR(buf, cur->name);
5129 xmlBufferWriteChar(buf, "?>");
Daniel Veillardb96e6431999-08-29 21:02:19 +00005130 }
5131 return;
5132 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00005133 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005134 if (cur->content != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005135 xmlBufferWriteChar(buf, "<!--");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005136#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00005137 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005138#else
5139 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5140#endif
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005141 xmlBufferWriteChar(buf, "-->");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005142 }
5143 return;
5144 }
Daniel Veillardccb09631998-10-27 06:21:04 +00005145 if (cur->type == XML_ENTITY_REF_NODE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005146 xmlBufferWriteChar(buf, "&");
5147 xmlBufferWriteCHAR(buf, cur->name);
5148 xmlBufferWriteChar(buf, ";");
Daniel Veillardccb09631998-10-27 06:21:04 +00005149 return;
5150 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00005151 if (cur->type == XML_CDATA_SECTION_NODE) {
5152 xmlBufferWriteChar(buf, "<![CDATA[");
5153 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005154#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00005155 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005156#else
5157 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5158#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00005159 xmlBufferWriteChar(buf, "]]>");
5160 return;
5161 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005162
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005163 if (format == 1) {
Daniel Veillardcf461992000-03-14 18:30:20 +00005164 tmp = cur->children;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005165 while (tmp != NULL) {
5166 if ((tmp->type == XML_TEXT_NODE) ||
5167 (tmp->type == XML_ENTITY_REF_NODE)) {
5168 format = 0;
5169 break;
5170 }
5171 tmp = tmp->next;
5172 }
5173 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005174 xmlBufferWriteChar(buf, "<");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005175 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005176 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5177 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005178 }
5179
Daniel Veillard5099ae81999-04-21 20:12:07 +00005180 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005181 if (cur->nsDef)
Daniel Veillard5099ae81999-04-21 20:12:07 +00005182 xmlNsListDump(buf, cur->nsDef);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005183 if (cur->properties != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00005184 xmlAttrListDump(buf, doc, cur->properties);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005185
Daniel Veillardcf461992000-03-14 18:30:20 +00005186 if ((cur->content == NULL) && (cur->children == NULL) &&
Daniel Veillarde41f2b72000-01-30 20:00:07 +00005187 (!xmlSaveNoEmptyTags)) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005188 xmlBufferWriteChar(buf, "/>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005189 return;
5190 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005191 xmlBufferWriteChar(buf, ">");
Daniel Veillard14fff061999-06-22 21:49:07 +00005192 if (cur->content != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005193 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00005194
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005195#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +00005196 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005197#else
5198 buffer = xmlEncodeEntitiesReentrant(doc,
5199 xmlBufferContent(cur->content));
5200#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00005201 if (buffer != NULL) {
5202 xmlBufferWriteCHAR(buf, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005203 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +00005204 }
5205 }
Daniel Veillardcf461992000-03-14 18:30:20 +00005206 if (cur->children != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005207 if (format) xmlBufferWriteChar(buf, "\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00005208 xmlNodeListDump(buf, doc, cur->children,
Daniel Veillard3e6d2372000-03-04 11:39:43 +00005209 (level >= 0?level+1:-1), format);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005210 if ((xmlIndentTreeOutput) && (format))
5211 for (i = 0;i < level;i++)
5212 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005213 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005214 xmlBufferWriteChar(buf, "</");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005215 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005216 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5217 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005218 }
5219
Daniel Veillard5099ae81999-04-21 20:12:07 +00005220 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005221 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005222}
5223
Daniel Veillard97b58771998-10-20 06:14:16 +00005224/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005225 * xmlElemDump:
Daniel Veillard06047432000-04-24 11:33:38 +00005226 * @f: the FILE * for the output
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005227 * @doc: the document
5228 * @cur: the current node
5229 *
5230 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5231 */
5232void
5233xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5234 xmlBufferPtr buf;
5235
5236 if (cur == NULL) {
5237#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005238 xmlGenericError(xmlGenericErrorContext,
5239 "xmlElemDump : cur == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005240#endif
5241 return;
5242 }
5243 if (doc == NULL) {
5244#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005245 xmlGenericError(xmlGenericErrorContext,
5246 "xmlElemDump : doc == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005247#endif
5248 }
5249 buf = xmlBufferCreate();
5250 if (buf == NULL) return;
5251 if ((doc != NULL) &&
5252 (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard361d8452000-04-03 19:48:13 +00005253#ifdef LIBXML_HTML_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005254 htmlNodeDump(buf, doc, cur);
Daniel Veillard361d8452000-04-03 19:48:13 +00005255#else
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005256 xmlGenericError(xmlGenericErrorContext,
5257 "HTML support not compiled in\n");
Daniel Veillard361d8452000-04-03 19:48:13 +00005258#endif /* LIBXML_HTML_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005259 } else
5260 xmlNodeDump(buf, doc, cur, 0, 1);
5261 xmlBufferDump(f, buf);
5262 xmlBufferFree(buf);
5263}
5264
Daniel Veillardbe803962000-06-28 23:40:59 +00005265/************************************************************************
5266 * *
5267 * Dumping XML tree content to an I/O output buffer *
5268 * *
5269 ************************************************************************/
5270
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005271void
Daniel Veillardbe803962000-06-28 23:40:59 +00005272xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5273 int level, int format, const char *encoding);
5274static void
5275xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5276 int level, int format, const char *encoding);
5277/**
Daniel Veillardbe803962000-06-28 23:40:59 +00005278 * xmlNsDumpOutput:
5279 * @buf: the XML buffer output
5280 * @cur: a namespace
5281 *
5282 * Dump a local Namespace definition.
5283 * Should be called in the context of attributes dumps.
5284 */
5285static void
5286xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5287 if (cur == NULL) {
5288#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005289 xmlGenericError(xmlGenericErrorContext,
5290 "xmlNsDump : Ns == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005291#endif
5292 return;
5293 }
Daniel Veillarde0854c32000-08-27 21:12:29 +00005294 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005295 /* Within the context of an element attributes */
5296 if (cur->prefix != NULL) {
5297 xmlOutputBufferWriteString(buf, " xmlns:");
5298 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5299 } else
5300 xmlOutputBufferWriteString(buf, " xmlns");
5301 xmlOutputBufferWriteString(buf, "=");
5302 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5303 }
5304}
5305
5306/**
5307 * xmlNsListDumpOutput:
5308 * @buf: the XML buffer output
5309 * @cur: the first namespace
5310 *
5311 * Dump a list of local Namespace definitions.
5312 * Should be called in the context of attributes dumps.
5313 */
5314static void
5315xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5316 while (cur != NULL) {
5317 xmlNsDumpOutput(buf, cur);
5318 cur = cur->next;
5319 }
5320}
5321
5322/**
5323 * xmlDtdDumpOutput:
5324 * @buf: the XML buffer output
5325 * @doc: the document
5326 * @encoding: an optional encoding string
5327 *
5328 * Dump the XML document DTD, if any.
5329 */
5330static void
5331xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5332 if (dtd == NULL) {
5333#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005334 xmlGenericError(xmlGenericErrorContext,
5335 "xmlDtdDump : no internal subset\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005336#endif
5337 return;
5338 }
5339 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5340 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5341 if (dtd->ExternalID != NULL) {
5342 xmlOutputBufferWriteString(buf, " PUBLIC ");
5343 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5344 xmlOutputBufferWriteString(buf, " ");
5345 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5346 } else if (dtd->SystemID != NULL) {
5347 xmlOutputBufferWriteString(buf, " SYSTEM ");
5348 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5349 }
5350 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5351 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5352 xmlOutputBufferWriteString(buf, ">");
5353 return;
5354 }
5355 xmlOutputBufferWriteString(buf, " [\n");
5356 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
Daniel Veillardbe803962000-06-28 23:40:59 +00005357 xmlOutputBufferWriteString(buf, "]>");
5358}
5359
5360/**
5361 * xmlAttrDumpOutput:
5362 * @buf: the XML buffer output
5363 * @doc: the document
5364 * @cur: the attribute pointer
5365 * @encoding: an optional encoding string
5366 *
5367 * Dump an XML attribute
5368 */
5369static void
5370xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
5371 const char *encoding) {
5372 xmlChar *value;
5373
5374 if (cur == NULL) {
5375#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005376 xmlGenericError(xmlGenericErrorContext,
5377 "xmlAttrDump : property == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005378#endif
5379 return;
5380 }
5381 xmlOutputBufferWriteString(buf, " ");
5382 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5383 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5384 xmlOutputBufferWriteString(buf, ":");
5385 }
5386 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5387 value = xmlNodeListGetString(doc, cur->children, 0);
5388 if (value) {
5389 xmlOutputBufferWriteString(buf, "=");
5390 xmlBufferWriteQuotedString(buf->buffer, value);
5391 xmlFree(value);
5392 } else {
5393 xmlOutputBufferWriteString(buf, "=\"\"");
5394 }
5395}
5396
5397/**
5398 * xmlAttrListDumpOutput:
5399 * @buf: the XML buffer output
5400 * @doc: the document
5401 * @cur: the first attribute pointer
5402 * @encoding: an optional encoding string
5403 *
5404 * Dump a list of XML attributes
5405 */
5406static void
5407xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5408 xmlAttrPtr cur, const char *encoding) {
5409 if (cur == NULL) {
5410#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005411 xmlGenericError(xmlGenericErrorContext,
5412 "xmlAttrListDump : property == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005413#endif
5414 return;
5415 }
5416 while (cur != NULL) {
5417 xmlAttrDumpOutput(buf, doc, cur, encoding);
5418 cur = cur->next;
5419 }
5420}
5421
5422
5423
5424/**
5425 * xmlNodeListDumpOutput:
5426 * @buf: the XML buffer output
5427 * @doc: the document
5428 * @cur: the first node
5429 * @level: the imbrication level for indenting
5430 * @format: is formatting allowed
5431 * @encoding: an optional encoding string
5432 *
5433 * Dump an XML node list, recursive behaviour,children are printed too.
5434 */
5435static void
5436xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5437 xmlNodePtr cur, int level, int format, const char *encoding) {
5438 int i;
5439
5440 if (cur == NULL) {
5441#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005442 xmlGenericError(xmlGenericErrorContext,
5443 "xmlNodeListDump : node == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005444#endif
5445 return;
5446 }
5447 while (cur != NULL) {
5448 if ((format) && (xmlIndentTreeOutput) &&
5449 (cur->type == XML_ELEMENT_NODE))
5450 for (i = 0;i < level;i++)
5451 xmlOutputBufferWriteString(buf, " ");
5452 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5453 if (format) {
5454 xmlOutputBufferWriteString(buf, "\n");
5455 }
5456 cur = cur->next;
5457 }
5458}
5459
5460/**
5461 * xmlNodeDumpOutput:
5462 * @buf: the XML buffer output
5463 * @doc: the document
5464 * @cur: the current node
5465 * @level: the imbrication level for indenting
5466 * @format: is formatting allowed
5467 * @encoding: an optional encoding string
5468 *
5469 * Dump an XML node, recursive behaviour,children are printed too.
5470 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005471void
Daniel Veillardbe803962000-06-28 23:40:59 +00005472xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5473 int level, int format, const char *encoding) {
5474 int i;
5475 xmlNodePtr tmp;
5476
5477 if (cur == NULL) {
5478#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005479 xmlGenericError(xmlGenericErrorContext,
5480 "xmlNodeDump : node == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005481#endif
5482 return;
5483 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00005484 if (cur->type == XML_XINCLUDE_START)
5485 return;
5486 if (cur->type == XML_XINCLUDE_END)
5487 return;
Daniel Veillardbe803962000-06-28 23:40:59 +00005488 if (cur->type == XML_DTD_NODE) {
5489 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5490 return;
5491 }
5492 if (cur->type == XML_ELEMENT_DECL) {
5493 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5494 return;
5495 }
5496 if (cur->type == XML_ATTRIBUTE_DECL) {
5497 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5498 return;
5499 }
5500 if (cur->type == XML_ENTITY_DECL) {
5501 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5502 return;
5503 }
5504 if (cur->type == XML_TEXT_NODE) {
5505 if (cur->content != NULL) {
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005506 if ((cur->name == xmlStringText) ||
5507 (cur->name != xmlStringTextNoenc)) {
5508 xmlChar *buffer;
Daniel Veillardbe803962000-06-28 23:40:59 +00005509
5510#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005511 if (encoding == NULL)
5512 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5513 else
5514 buffer = xmlEncodeSpecialChars(doc, cur->content);
Daniel Veillardbe803962000-06-28 23:40:59 +00005515#else
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005516 if (encoding == NULL)
5517 buffer = xmlEncodeEntitiesReentrant(doc,
5518 xmlBufferContent(cur->content));
5519 else
5520 buffer = xmlEncodeSpecialChars(doc,
5521 xmlBufferContent(cur->content));
Daniel Veillardbe803962000-06-28 23:40:59 +00005522#endif
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005523 if (buffer != NULL) {
5524 xmlOutputBufferWriteString(buf, (const char *)buffer);
5525 xmlFree(buffer);
5526 }
5527 } else {
5528 /*
5529 * Disable escaping, needed for XSLT
5530 */
5531#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillarde4566462001-01-22 09:58:39 +00005532 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005533#else
5534 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
5535#endif
Daniel Veillardbe803962000-06-28 23:40:59 +00005536 }
5537 }
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005538
Daniel Veillardbe803962000-06-28 23:40:59 +00005539 return;
5540 }
5541 if (cur->type == XML_PI_NODE) {
5542 if (cur->content != NULL) {
5543 xmlOutputBufferWriteString(buf, "<?");
5544 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5545 if (cur->content != NULL) {
5546 xmlOutputBufferWriteString(buf, " ");
5547#ifndef XML_USE_BUFFER_CONTENT
5548 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5549#else
5550 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5551#endif
5552 }
5553 xmlOutputBufferWriteString(buf, "?>");
5554 } else {
5555 xmlOutputBufferWriteString(buf, "<?");
5556 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5557 xmlOutputBufferWriteString(buf, "?>");
5558 }
5559 return;
5560 }
5561 if (cur->type == XML_COMMENT_NODE) {
5562 if (cur->content != NULL) {
5563 xmlOutputBufferWriteString(buf, "<!--");
5564#ifndef XML_USE_BUFFER_CONTENT
5565 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5566#else
5567 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5568#endif
5569 xmlOutputBufferWriteString(buf, "-->");
5570 }
5571 return;
5572 }
5573 if (cur->type == XML_ENTITY_REF_NODE) {
5574 xmlOutputBufferWriteString(buf, "&");
5575 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5576 xmlOutputBufferWriteString(buf, ";");
5577 return;
5578 }
5579 if (cur->type == XML_CDATA_SECTION_NODE) {
5580 xmlOutputBufferWriteString(buf, "<![CDATA[");
5581 if (cur->content != NULL)
5582#ifndef XML_USE_BUFFER_CONTENT
5583 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5584#else
5585 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5586#endif
5587 xmlOutputBufferWriteString(buf, "]]>");
5588 return;
5589 }
5590
5591 if (format == 1) {
5592 tmp = cur->children;
5593 while (tmp != NULL) {
5594 if ((tmp->type == XML_TEXT_NODE) ||
5595 (tmp->type == XML_ENTITY_REF_NODE)) {
5596 format = 0;
5597 break;
5598 }
5599 tmp = tmp->next;
5600 }
5601 }
5602 xmlOutputBufferWriteString(buf, "<");
5603 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5604 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5605 xmlOutputBufferWriteString(buf, ":");
5606 }
5607
5608 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5609 if (cur->nsDef)
5610 xmlNsListDumpOutput(buf, cur->nsDef);
5611 if (cur->properties != NULL)
5612 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
5613
5614 if ((cur->content == NULL) && (cur->children == NULL) &&
5615 (!xmlSaveNoEmptyTags)) {
5616 xmlOutputBufferWriteString(buf, "/>");
5617 return;
5618 }
5619 xmlOutputBufferWriteString(buf, ">");
5620 if (cur->content != NULL) {
5621 xmlChar *buffer;
5622
5623#ifndef XML_USE_BUFFER_CONTENT
5624 if (encoding == NULL)
5625 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5626 else
5627 buffer = xmlEncodeSpecialChars(doc, cur->content);
5628#else
5629 if (encoding == NULL)
5630 buffer = xmlEncodeEntitiesReentrant(doc,
5631 xmlBufferContent(cur->content));
5632 else
5633 buffer = xmlEncodeSpecialChars(doc,
5634 xmlBufferContent(cur->content));
5635#endif
5636 if (buffer != NULL) {
5637 xmlOutputBufferWriteString(buf, (const char *)buffer);
5638 xmlFree(buffer);
5639 }
5640 }
5641 if (cur->children != NULL) {
5642 if (format) xmlOutputBufferWriteString(buf, "\n");
5643 xmlNodeListDumpOutput(buf, doc, cur->children,
5644 (level >= 0?level+1:-1), format, encoding);
5645 if ((xmlIndentTreeOutput) && (format))
5646 for (i = 0;i < level;i++)
5647 xmlOutputBufferWriteString(buf, " ");
5648 }
5649 xmlOutputBufferWriteString(buf, "</");
5650 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5651 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5652 xmlOutputBufferWriteString(buf, ":");
5653 }
5654
5655 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5656 xmlOutputBufferWriteString(buf, ">");
5657}
5658
5659/**
5660 * xmlDocContentDumpOutput:
5661 * @buf: the XML buffer output
5662 * @cur: the document
5663 * @encoding: an optional encoding string
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005664 * @format: should formatting spaces been added
Daniel Veillardbe803962000-06-28 23:40:59 +00005665 *
5666 * Dump an XML document.
5667 */
5668static void
5669xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005670 const char *encoding, int format) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005671 xmlOutputBufferWriteString(buf, "<?xml version=");
5672 if (cur->version != NULL)
5673 xmlBufferWriteQuotedString(buf->buffer, cur->version);
5674 else
5675 xmlOutputBufferWriteString(buf, "\"1.0\"");
5676 if (encoding == NULL) {
5677 if (cur->encoding != NULL)
5678 encoding = (const char *) cur->encoding;
5679 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005680 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
Daniel Veillardbe803962000-06-28 23:40:59 +00005681 }
5682 if (encoding != NULL) {
5683 xmlOutputBufferWriteString(buf, " encoding=");
5684 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
5685 }
5686 switch (cur->standalone) {
5687 case 0:
5688 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
5689 break;
5690 case 1:
5691 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
5692 break;
5693 }
5694 xmlOutputBufferWriteString(buf, "?>\n");
5695 if (cur->children != NULL) {
5696 xmlNodePtr child = cur->children;
5697
Daniel Veillardbe803962000-06-28 23:40:59 +00005698 while (child != NULL) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005699 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
Daniel Veillardbe803962000-06-28 23:40:59 +00005700 xmlOutputBufferWriteString(buf, "\n");
5701 child = child->next;
5702 }
5703 }
5704}
5705
5706/************************************************************************
5707 * *
5708 * Saving functions front-ends *
5709 * *
5710 ************************************************************************/
5711
Daniel Veillard97b58771998-10-20 06:14:16 +00005712/**
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005713 * xmlDocDumpMemoryEnc:
5714 * @out_doc: Document to generate XML text from
5715 * @doc_txt_ptr: Memory pointer for allocated XML text
5716 * @doc_txt_len: Length of the generated XML text
5717 * @txt_encoding: Character encoding to use when generating XML text
5718 * @format: should formatting spaces been added
5719 *
5720 * Dump the current DOM tree into memory using the character encoding specified
5721 * by the caller. Note it is up to the caller of this function to free the
5722 * allocated memory.
5723 */
5724
5725void
5726xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5727 int * doc_txt_len, const char * txt_encoding, int format) {
5728 int dummy = 0;
5729
5730 xmlCharEncoding doc_charset;
5731 xmlOutputBufferPtr out_buff = NULL;
5732 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
5733
5734 if (doc_txt_len == NULL) {
5735 doc_txt_len = &dummy; /* Continue, caller just won't get length */
5736 }
5737
5738 if (doc_txt_ptr == NULL) {
5739 *doc_txt_len = 0;
5740 xmlGenericError(xmlGenericErrorContext,
5741 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
5742 return;
5743 }
5744
5745 *doc_txt_ptr = NULL;
5746 *doc_txt_len = 0;
5747
5748 if (out_doc == NULL) {
5749 /* No document, no output */
5750 xmlGenericError(xmlGenericErrorContext,
5751 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
5752 return;
5753 }
5754
5755 /*
5756 * Validate the encoding value, if provided.
5757 * This logic is copied from xmlSaveFileEnc.
5758 */
5759
5760 if (txt_encoding == NULL)
5761 txt_encoding = (const char *) out_doc->encoding;
5762 if (txt_encoding != NULL) {
5763 doc_charset = xmlParseCharEncoding(txt_encoding);
5764
5765 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
5766 xmlGenericError(xmlGenericErrorContext,
5767 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
5768 return;
5769
5770 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
5771 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
5772 if ( conv_hdlr == NULL ) {
5773 xmlGenericError(xmlGenericErrorContext,
5774 "%s: %s %s '%s'\n",
5775 "xmlDocDumpFormatMemoryEnc",
5776 "Failed to identify encoding handler for",
5777 "character set",
5778 txt_encoding);
5779 return;
5780 }
5781 }
5782 }
5783
5784 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
5785 xmlGenericError(xmlGenericErrorContext,
5786 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
5787 return;
5788 }
5789
5790 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, 1);
5791 xmlOutputBufferFlush(out_buff);
5792 if (out_buff->conv != NULL) {
5793 *doc_txt_len = out_buff->conv->use;
5794 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
5795 } else {
5796 *doc_txt_len = out_buff->buffer->use;
5797 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
5798 }
5799 (void)xmlOutputBufferClose(out_buff);
5800
5801 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
5802 *doc_txt_len = 0;
5803 xmlGenericError(xmlGenericErrorContext,
5804 "xmlDocDumpFormatMemoryEnc: %s\n",
5805 "Failed to allocate memory for document text representation.");
5806 }
5807
5808 return;
5809}
5810
5811/**
Daniel Veillard97b58771998-10-20 06:14:16 +00005812 * xmlDocDumpMemory:
5813 * @cur: the document
5814 * @mem: OUT: the memory pointer
5815 * @size: OUT: the memory lenght
5816 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005817 * Dump an XML document in memory and return the xmlChar * and it's size.
Daniel Veillard97b58771998-10-20 06:14:16 +00005818 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005819 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005820void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005821xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005822 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
5823}
Daniel Veillard5099ae81999-04-21 20:12:07 +00005824
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005825/**
5826 * xmlDocDumpFormatMemory:
5827 * @cur: the document
5828 * @mem: OUT: the memory pointer
5829 * @size: OUT: the memory lenght
5830 * @format: should formatting spaces been added
5831 *
5832 *
5833 * Dump an XML document in memory and return the xmlChar * and it's size.
5834 * It's up to the caller to free the memory.
5835 */
5836void
5837xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
5838 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005839}
5840
Daniel Veillard97b58771998-10-20 06:14:16 +00005841/**
Daniel Veillard58770e72000-11-25 00:48:47 +00005842 * xmlDocDumpMemoryEnc:
5843 * @out_doc: Document to generate XML text from
5844 * @doc_txt_ptr: Memory pointer for allocated XML text
5845 * @doc_txt_len: Length of the generated XML text
5846 * @txt_encoding: Character encoding to use when generating XML text
5847 *
5848 * Dump the current DOM tree into memory using the character encoding specified
5849 * by the caller. Note it is up to the caller of this function to free the
5850 * allocated memory.
5851 */
5852
5853void
5854xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5855 int * doc_txt_len, const char * txt_encoding) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005856 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
5857 txt_encoding, 1);
Daniel Veillard58770e72000-11-25 00:48:47 +00005858}
5859
5860/**
Daniel Veillard97b58771998-10-20 06:14:16 +00005861 * xmlGetDocCompressMode:
5862 * @doc: the document
5863 *
5864 * get the compression ratio for a document, ZLIB based
Daniel Veillard1e346af1999-02-22 10:33:01 +00005865 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00005866 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005867int
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005868xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005869 if (doc == NULL) return(-1);
5870 return(doc->compression);
5871}
5872
Daniel Veillard97b58771998-10-20 06:14:16 +00005873/**
5874 * xmlSetDocCompressMode:
5875 * @doc: the document
5876 * @mode: the compression ratio
5877 *
5878 * set the compression ratio for a document, ZLIB based
5879 * Correct values: 0 (uncompressed) to 9 (max compression)
5880 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005881void
5882xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005883 if (doc == NULL) return;
5884 if (mode < 0) doc->compression = 0;
5885 else if (mode > 9) doc->compression = 9;
5886 else doc->compression = mode;
5887}
5888
Daniel Veillard97b58771998-10-20 06:14:16 +00005889/**
5890 * xmlGetCompressMode:
5891 *
5892 * get the default compression mode used, ZLIB based.
Daniel Veillard1e346af1999-02-22 10:33:01 +00005893 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00005894 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005895int
5896 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005897 return(xmlCompressMode);
5898}
Daniel Veillard97b58771998-10-20 06:14:16 +00005899
5900/**
5901 * xmlSetCompressMode:
5902 * @mode: the compression ratio
5903 *
5904 * set the default compression mode used, ZLIB based
5905 * Correct values: 0 (uncompressed) to 9 (max compression)
5906 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005907void
5908xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005909 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00005910 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005911 else xmlCompressMode = mode;
5912}
5913
Daniel Veillardbe803962000-06-28 23:40:59 +00005914/**
5915 * xmlDocDump:
5916 * @f: the FILE*
5917 * @cur: the document
5918 *
5919 * Dump an XML document to an open FILE.
5920 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005921 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005922 */
5923int
5924xmlDocDump(FILE *f, xmlDocPtr cur) {
5925 xmlOutputBufferPtr buf;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005926 const char * encoding;
5927 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillardbe803962000-06-28 23:40:59 +00005928 int ret;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005929
Daniel Veillardbe803962000-06-28 23:40:59 +00005930 if (cur == NULL) {
5931#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005932 xmlGenericError(xmlGenericErrorContext,
5933 "xmlDocDump : document == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005934#endif
5935 return(-1);
5936 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005937 encoding = (const char *) cur->encoding;
5938
5939 if (encoding != NULL) {
5940 xmlCharEncoding enc;
5941
5942 enc = xmlParseCharEncoding(encoding);
5943
5944 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005945 xmlGenericError(xmlGenericErrorContext,
5946 "xmlDocDump: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005947 return(-1);
5948 }
5949 if (enc != XML_CHAR_ENCODING_UTF8) {
5950 handler = xmlFindCharEncodingHandler(encoding);
5951 if (handler == NULL) {
5952 xmlFree((char *) cur->encoding);
5953 cur->encoding = NULL;
5954 }
5955 }
5956 }
5957 buf = xmlOutputBufferCreateFile(f, handler);
Daniel Veillardbe803962000-06-28 23:40:59 +00005958 if (buf == NULL) return(-1);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005959 xmlDocContentDumpOutput(buf, cur, NULL, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005960
5961 ret = xmlOutputBufferClose(buf);
5962 return(ret);
5963}
5964
5965/**
Daniel Veillardbe803962000-06-28 23:40:59 +00005966 * xmlSaveFileTo:
5967 * @buf: an output I/O buffer
5968 * @cur: the document
5969 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
5970 *
5971 * Dump an XML document to an I/O buffer.
5972 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005973 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005974 */
5975int
5976xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
5977 int ret;
5978
5979 if (buf == NULL) return(0);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005980 xmlDocContentDumpOutput(buf, cur, encoding, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005981 ret = xmlOutputBufferClose(buf);
5982 return(ret);
5983}
5984
5985/**
5986 * xmlSaveFileEnc:
5987 * @filename: the filename (or URL)
5988 * @cur: the document
5989 * @encoding: the name of an encoding (or NULL)
5990 *
5991 * Dump an XML document, converting it to the given encoding
5992 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005993 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005994 */
5995int
5996xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
5997 xmlOutputBufferPtr buf;
5998 xmlCharEncodingHandlerPtr handler = NULL;
5999 int ret;
6000
6001 if (encoding != NULL) {
6002 xmlCharEncoding enc;
6003
6004 enc = xmlParseCharEncoding(encoding);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006005 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006006 xmlGenericError(xmlGenericErrorContext,
6007 "xmlSaveFileEnc: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006008 return(-1);
6009 }
6010 if (enc != XML_CHAR_ENCODING_UTF8) {
6011 handler = xmlFindCharEncodingHandler(encoding);
6012 if (handler == NULL) {
Daniel Veillardbe803962000-06-28 23:40:59 +00006013 return(-1);
6014 }
Daniel Veillardbe803962000-06-28 23:40:59 +00006015 }
6016 }
6017
6018 /*
6019 * save the content to a temp buffer.
6020 */
6021 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
Daniel Veillardf831bfb2001-01-16 17:26:04 +00006022 if (buf == NULL) return(-1);
Daniel Veillardbe803962000-06-28 23:40:59 +00006023
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00006024 xmlDocContentDumpOutput(buf, cur, encoding, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00006025
6026 ret = xmlOutputBufferClose(buf);
6027 return(ret);
6028}
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006029
6030/**
6031 * xmlSaveFile:
6032 * @filename: the filename (or URL)
6033 * @cur: the document
6034 *
6035 * Dump an XML document to a file. Will use compression if
6036 * compiled in and enabled. If @filename is "-" the stdout file is
6037 * used.
6038 * returns: the number of byte written or -1 in case of failure.
6039 */
6040int
6041xmlSaveFile(const char *filename, xmlDocPtr cur) {
6042 xmlOutputBufferPtr buf;
6043 const char *encoding;
6044 xmlCharEncodingHandlerPtr handler = NULL;
6045 int ret;
6046
6047 if (cur == NULL)
6048 return(-1);
6049 encoding = (const char *) cur->encoding;
6050
6051 /*
6052 * save the content to a temp buffer.
6053 */
6054#ifdef HAVE_ZLIB_H
6055 if (cur->compression < 0) cur->compression = xmlCompressMode;
Daniel Veillardbe803962000-06-28 23:40:59 +00006056#endif
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006057 if (encoding != NULL) {
6058 xmlCharEncoding enc;
6059
6060 enc = xmlParseCharEncoding(encoding);
6061
6062 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006063 xmlGenericError(xmlGenericErrorContext,
6064 "xmlSaveFile: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006065 return(-1);
6066 }
6067 if (enc != XML_CHAR_ENCODING_UTF8) {
6068 handler = xmlFindCharEncodingHandler(encoding);
6069 if (handler == NULL) {
6070 xmlFree((char *) cur->encoding);
6071 cur->encoding = NULL;
6072 }
6073 }
6074 }
6075
6076 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Daniel Veillard0cede082001-01-17 08:23:04 +00006077 if (buf == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006078
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00006079 xmlDocContentDumpOutput(buf, cur, NULL, 1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006080
6081 ret = xmlOutputBufferClose(buf);
6082 return(ret);
6083}
6084