blob: 03295445f86defc62a30b5b536e6fcb9e45bf189 [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) &&
2077 (parent->last->type == XML_TEXT_NODE)) {
2078#ifndef XML_USE_BUFFER_CONTENT
2079 xmlNodeAddContent(parent->last, cur->content);
2080#else
2081 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2082#endif
2083 /*
2084 * if it's the only child, nothing more to be done.
2085 */
2086 if (cur->next == NULL) {
2087 xmlFreeNode(cur);
2088 return(parent->last);
2089 }
2090 prev = cur;
2091 cur = cur->next;
2092 xmlFreeNode(prev);
2093 }
Daniel Veillard87b95392000-08-12 21:12:04 +00002094 prev = parent->last;
2095 prev->next = cur;
2096 cur->prev = prev;
2097 }
2098 while (cur->next != NULL) {
2099 cur->parent = parent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002100 if (cur->doc != parent->doc) {
2101 xmlSetTreeDoc(cur, parent->doc);
2102 }
Daniel Veillard87b95392000-08-12 21:12:04 +00002103 cur = cur->next;
2104 }
2105 cur->parent = parent;
2106 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
2107 parent->last = cur;
2108
2109 return(cur);
2110}
2111
2112/**
Daniel Veillard97b58771998-10-20 06:14:16 +00002113 * xmlAddChild:
2114 * @parent: the parent node
2115 * @cur: the child node
2116 *
Daniel Veillard683cb022000-10-22 12:04:13 +00002117 * Add a new child element, to @parent, at the end of the child list
2118 * merging adjacent TEXT nodes (in which case @cur is freed)
Daniel Veillard1e346af1999-02-22 10:33:01 +00002119 * Returns the child or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002120 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002121xmlNodePtr
2122xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002123 xmlNodePtr prev;
2124
2125 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002126#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002127 xmlGenericError(xmlGenericErrorContext,
2128 "xmlAddChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002129#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002130 return(NULL);
2131 }
2132
2133 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002134#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002135 xmlGenericError(xmlGenericErrorContext,
2136 "xmlAddChild : child == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002137#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002138 return(NULL);
2139 }
2140
Daniel Veillard0bef1311998-10-14 02:36:47 +00002141 if ((cur->doc != NULL) && (parent->doc != NULL) &&
2142 (cur->doc != parent->doc)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002143#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002144 xmlGenericError(xmlGenericErrorContext,
2145 "Elements moved to a different document\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002146#endif
Daniel Veillard0bef1311998-10-14 02:36:47 +00002147 }
2148
Daniel Veillard260a68f1998-08-13 03:39:55 +00002149 /*
Daniel Veillard683cb022000-10-22 12:04:13 +00002150 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
2151 * or with parent->content if parent->content != NULL.
2152 * cur is then freed.
2153 */
2154 if (cur->type == XML_TEXT_NODE) {
2155 if (((parent->type == XML_ELEMENT_NODE) ||
2156 (parent->type == XML_TEXT_NODE)) &&
2157 (parent->content != NULL)) {
2158#ifndef XML_USE_BUFFER_CONTENT
2159 xmlNodeAddContent(parent, cur->content);
2160#else
2161 xmlNodeAddContent(parent, xmlBufferContent(cur->content));
2162#endif
2163 xmlFreeNode(cur);
2164 return(parent);
2165 }
2166 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE)) {
2167#ifndef XML_USE_BUFFER_CONTENT
2168 xmlNodeAddContent(parent->last, cur->content);
2169#else
2170 xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
2171#endif
2172 xmlFreeNode(cur);
2173 return(parent->last);
2174 }
2175 }
2176
2177 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00002178 * add the new element at the end of the children list.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002179 */
2180 cur->parent = parent;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002181 if (cur->doc != parent->doc) {
2182 xmlSetTreeDoc(cur, parent->doc);
2183 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002184
Daniel Veillardccb09631998-10-27 06:21:04 +00002185 /*
2186 * Handle the case where parent->content != NULL, in that case it will
2187 * create a intermediate TEXT node.
2188 */
Daniel Veillardcf461992000-03-14 18:30:20 +00002189 if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
2190 (parent->content != NULL)) {
Daniel Veillardccb09631998-10-27 06:21:04 +00002191 xmlNodePtr text;
2192
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002193#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardccb09631998-10-27 06:21:04 +00002194 text = xmlNewDocText(parent->doc, parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002195#else
2196 text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
2197#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002198 if (text != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002199 text->next = parent->children;
Daniel Veillardccb09631998-10-27 06:21:04 +00002200 if (text->next != NULL)
2201 text->next->prev = text;
Daniel Veillardcf461992000-03-14 18:30:20 +00002202 parent->children = text;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002203 UPDATE_LAST_CHILD_AND_PARENT(parent)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002204#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002205 xmlFree(parent->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002206#else
2207 xmlBufferFree(parent->content);
2208#endif
Daniel Veillardccb09631998-10-27 06:21:04 +00002209 parent->content = NULL;
2210 }
2211 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002212 if (parent->children == NULL) {
2213 parent->children = cur;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002214 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002215 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002216 prev = parent->last;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002217 prev->next = cur;
Daniel Veillard0bef1311998-10-14 02:36:47 +00002218 cur->prev = prev;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002219 parent->last = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002220 }
2221
2222 return(cur);
2223}
2224
Daniel Veillard97b58771998-10-20 06:14:16 +00002225/**
2226 * xmlGetLastChild:
2227 * @parent: the parent node
2228 *
2229 * Search the last child of a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00002230 * Returns the last child or NULL if none.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002231 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002232xmlNodePtr
2233xmlGetLastChild(xmlNodePtr parent) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002234 if (parent == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002235#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002236 xmlGenericError(xmlGenericErrorContext,
2237 "xmlGetLastChild : parent == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002238#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002239 return(NULL);
2240 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002241 return(parent->last);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002242}
2243
Daniel Veillard97b58771998-10-20 06:14:16 +00002244/**
2245 * xmlFreeNodeList:
2246 * @cur: the first node in the list
2247 *
2248 * Free a node and all its siblings, this is a recursive behaviour, all
Daniel Veillardcf461992000-03-14 18:30:20 +00002249 * the children are freed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002250 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002251void
2252xmlFreeNodeList(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002253 xmlNodePtr next;
2254 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002255#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002256 xmlGenericError(xmlGenericErrorContext,
2257 "xmlFreeNodeList : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002258#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002259 return;
2260 }
2261 while (cur != NULL) {
2262 next = cur->next;
2263 xmlFreeNode(cur);
2264 cur = next;
2265 }
2266}
2267
Daniel Veillard97b58771998-10-20 06:14:16 +00002268/**
2269 * xmlFreeNode:
2270 * @cur: the node
2271 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002272 * Free a node, this is a recursive behaviour, all the children are freed too.
2273 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002274 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00002275void
2276xmlFreeNode(xmlNodePtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002277 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002278#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002279 xmlGenericError(xmlGenericErrorContext,
2280 "xmlFreeNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002281#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00002282 return;
2283 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002284 if (cur->type == XML_DTD_NODE)
2285 return;
Daniel Veillardccb09631998-10-27 06:21:04 +00002286 cur->doc = NULL;
2287 cur->parent = NULL;
2288 cur->next = NULL;
2289 cur->prev = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002290 if ((cur->children != NULL) &&
2291 (cur->type != XML_ENTITY_REF_NODE))
2292 xmlFreeNodeList(cur->children);
Daniel Veillardccb09631998-10-27 06:21:04 +00002293 if (cur->properties != NULL) xmlFreePropList(cur->properties);
2294 if (cur->type != XML_ENTITY_REF_NODE)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002295#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00002296 if (cur->content != NULL) xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002297#else
2298 if (cur->content != NULL) xmlBufferFree(cur->content);
2299#endif
Daniel Veillardf6eea272001-01-18 12:17:12 +00002300 if ((cur->name != NULL) &&
2301 (cur->name != xmlStringText) &&
2302 (cur->name != xmlStringTextNoenc) &&
2303 (cur->name != xmlStringComment))
2304 xmlFree((char *) cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002305 if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
2306 memset(cur, -1, sizeof(xmlNode));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002307 xmlFree(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002308}
2309
Daniel Veillard16253641998-10-28 22:58:05 +00002310/**
2311 * xmlUnlinkNode:
2312 * @cur: the node
2313 *
2314 * Unlink a node from it's current context, the node is not freed
2315 */
2316void
2317xmlUnlinkNode(xmlNodePtr cur) {
2318 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002319#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002320 xmlGenericError(xmlGenericErrorContext,
2321 "xmlUnlinkNode : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002322#endif
Daniel Veillard16253641998-10-28 22:58:05 +00002323 return;
2324 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002325 if ((cur->parent != NULL) && (cur->parent->children == cur))
2326 cur->parent->children = cur->next;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002327 if ((cur->parent != NULL) && (cur->parent->last == cur))
2328 cur->parent->last = cur->prev;
Daniel Veillard16253641998-10-28 22:58:05 +00002329 if (cur->next != NULL)
2330 cur->next->prev = cur->prev;
2331 if (cur->prev != NULL)
2332 cur->prev->next = cur->next;
2333 cur->next = cur->prev = NULL;
2334 cur->parent = NULL;
2335}
2336
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002337/**
2338 * xmlReplaceNode:
2339 * @old: the old node
2340 * @cur: the node
2341 *
2342 * Unlink the old node from it's current context, prune the new one
2343 * at the same place. If cur was already inserted in a document it is
2344 * first unlinked from its existing context.
2345 *
2346 * Returns the old node
2347 */
2348xmlNodePtr
2349xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
2350 if (old == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002351#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002352 xmlGenericError(xmlGenericErrorContext,
2353 "xmlReplaceNode : old == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002354#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002355 return(NULL);
2356 }
2357 if (cur == NULL) {
2358 xmlUnlinkNode(old);
2359 return(old);
2360 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002361 if (cur == old) {
2362 return(old);
2363 }
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002364 xmlUnlinkNode(cur);
2365 cur->doc = old->doc;
2366 cur->parent = old->parent;
2367 cur->next = old->next;
2368 if (cur->next != NULL)
2369 cur->next->prev = cur;
2370 cur->prev = old->prev;
2371 if (cur->prev != NULL)
2372 cur->prev->next = cur;
2373 if (cur->parent != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002374 if (cur->parent->children == old)
2375 cur->parent->children = cur;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002376 if (cur->parent->last == old)
2377 cur->parent->last = cur;
2378 }
2379 old->next = old->prev = NULL;
2380 old->parent = NULL;
2381 return(old);
2382}
2383
Daniel Veillard260a68f1998-08-13 03:39:55 +00002384/************************************************************************
2385 * *
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002386 * Copy operations *
2387 * *
2388 ************************************************************************/
2389
2390/**
2391 * xmlCopyNamespace:
2392 * @cur: the namespace
2393 *
2394 * Do a copy of the namespace.
2395 *
2396 * Returns: a new xmlNsPtr, or NULL in case of error.
2397 */
2398xmlNsPtr
2399xmlCopyNamespace(xmlNsPtr cur) {
2400 xmlNsPtr ret;
2401
2402 if (cur == NULL) return(NULL);
2403 switch (cur->type) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002404 case XML_LOCAL_NAMESPACE:
2405 ret = xmlNewNs(NULL, cur->href, cur->prefix);
2406 break;
2407 default:
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002408#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002409 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda4964b72000-10-31 18:23:44 +00002410 "xmlCopyNamespace: invalid type %d\n", cur->type);
Daniel Veillardad8f99d2000-01-15 14:20:03 +00002411#endif
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002412 return(NULL);
2413 }
2414 return(ret);
2415}
2416
2417/**
2418 * xmlCopyNamespaceList:
2419 * @cur: the first namespace
2420 *
2421 * Do a copy of an namespace list.
2422 *
2423 * Returns: a new xmlNsPtr, or NULL in case of error.
2424 */
2425xmlNsPtr
2426xmlCopyNamespaceList(xmlNsPtr cur) {
2427 xmlNsPtr ret = NULL;
2428 xmlNsPtr p = NULL,q;
2429
2430 while (cur != NULL) {
2431 q = xmlCopyNamespace(cur);
2432 if (p == NULL) {
2433 ret = p = q;
2434 } else {
2435 p->next = q;
2436 p = q;
2437 }
2438 cur = cur->next;
2439 }
2440 return(ret);
2441}
2442
Daniel Veillard389e6b72001-01-15 19:41:13 +00002443static xmlNodePtr
2444xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002445/**
2446 * xmlCopyProp:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002447 * @target: the element where the attribute will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002448 * @cur: the attribute
2449 *
2450 * Do a copy of the attribute.
2451 *
2452 * Returns: a new xmlAttrPtr, or NULL in case of error.
2453 */
2454xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002455xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002456 xmlAttrPtr ret;
2457
2458 if (cur == NULL) return(NULL);
Daniel Veillard389e6b72001-01-15 19:41:13 +00002459 if (target != NULL)
2460 ret = xmlNewDocProp(target->doc, cur->name, NULL);
2461 else if (cur->parent != NULL)
Daniel Veillardcf461992000-03-14 18:30:20 +00002462 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
2463 else if (cur->children != NULL)
2464 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002465 else
2466 ret = xmlNewDocProp(NULL, cur->name, NULL);
2467 if (ret == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002468 ret->parent = target;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002469
2470 if ((cur->ns != NULL) && (target != NULL)) {
2471 xmlNsPtr ns;
2472
2473 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
2474 ret->ns = ns;
2475 } else
2476 ret->ns = NULL;
2477
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002478 if (cur->children != NULL) {
2479 xmlNodePtr tmp;
2480
Daniel Veillard389e6b72001-01-15 19:41:13 +00002481 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002482 ret->last = NULL;
2483 tmp = ret->children;
2484 while (tmp != NULL) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00002485 /* tmp->parent = (xmlNodePtr)ret; */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002486 if (tmp->next == NULL)
2487 ret->last = tmp;
2488 tmp = tmp->next;
2489 }
2490 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002491 return(ret);
2492}
2493
2494/**
2495 * xmlCopyPropList:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002496 * @target: the element where the attributes will be grafted
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002497 * @cur: the first attribute
2498 *
2499 * Do a copy of an attribute list.
2500 *
2501 * Returns: a new xmlAttrPtr, or NULL in case of error.
2502 */
2503xmlAttrPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +00002504xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002505 xmlAttrPtr ret = NULL;
2506 xmlAttrPtr p = NULL,q;
2507
2508 while (cur != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002509 q = xmlCopyProp(target, cur);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002510 if (p == NULL) {
2511 ret = p = q;
2512 } else {
2513 p->next = q;
Daniel Veillardcf461992000-03-14 18:30:20 +00002514 q->prev = p;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002515 p = q;
2516 }
2517 cur = cur->next;
2518 }
2519 return(ret);
2520}
2521
2522/*
Daniel Veillard11a48ec1999-11-23 10:40:46 +00002523 * NOTE abeut the CopyNode operations !
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002524 *
2525 * They are splitted into external and internal parts for one
2526 * tricky reason: namespaces. Doing a direct copy of a node
2527 * say RPM:Copyright without changing the namespace pointer to
2528 * something else can produce stale links. One way to do it is
2529 * to keep a reference counter but this doesn't work as soon
2530 * as one move the element or the subtree out of the scope of
2531 * the existing namespace. The actual solution seems to add
2532 * a copy of the namespace at the top of the copied tree if
2533 * not available in the subtree.
2534 * Hence two functions, the public front-end call the inner ones
2535 */
2536
2537static xmlNodePtr
2538xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
2539
2540static xmlNodePtr
2541xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
2542 int recursive) {
2543 xmlNodePtr ret;
2544
2545 if (node == NULL) return(NULL);
2546 /*
2547 * Allocate a new node and fill the fields.
2548 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00002549 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002550 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002551 xmlGenericError(xmlGenericErrorContext,
2552 "xmlStaticCopyNode : malloc failed\n");
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002553 return(NULL);
2554 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002555 memset(ret, 0, sizeof(xmlNode));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002556 ret->type = node->type;
Daniel Veillardcf461992000-03-14 18:30:20 +00002557
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002558 ret->doc = doc;
2559 ret->parent = parent;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002560 if (node->name != NULL)
2561 ret->name = xmlStrdup(node->name);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002562 if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
2563#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002564 ret->content = xmlStrdup(node->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00002565#else
2566 ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
2567 xmlBufferSetAllocationScheme(ret->content,
2568 xmlGetBufferAllocationScheme());
2569 xmlBufferAdd(ret->content,
2570 xmlBufferContent(node->content),
2571 xmlBufferLength(node->content));
2572#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002573 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002574 if (parent != NULL)
2575 xmlAddChild(parent, ret);
2576
2577 if (!recursive) return(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002578 if (node->nsDef != NULL)
2579 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
2580
2581 if (node->ns != NULL) {
2582 xmlNsPtr ns;
2583
2584 ns = xmlSearchNs(doc, ret, node->ns->prefix);
2585 if (ns == NULL) {
2586 /*
2587 * Humm, we are copying an element whose namespace is defined
2588 * out of the new tree scope. Search it in the original tree
2589 * and add it at the top of the new tree
2590 */
2591 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
2592 if (ns != NULL) {
2593 xmlNodePtr root = ret;
2594
2595 while (root->parent != NULL) root = root->parent;
2596 xmlNewNs(root, ns->href, ns->prefix);
2597 }
2598 } else {
2599 /*
2600 * reference the existing namespace definition in our own tree.
2601 */
2602 ret->ns = ns;
2603 }
2604 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002605 if (node->properties != NULL)
2606 ret->properties = xmlCopyPropList(ret, node->properties);
Daniel Veillardcf461992000-03-14 18:30:20 +00002607 if (node->children != NULL)
2608 ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002609 UPDATE_LAST_CHILD_AND_PARENT(ret)
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002610 return(ret);
2611}
2612
2613static xmlNodePtr
2614xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
2615 xmlNodePtr ret = NULL;
2616 xmlNodePtr p = NULL,q;
2617
2618 while (node != NULL) {
Daniel Veillardde55cf62001-01-31 15:53:13 +00002619 if( node->type == XML_DTD_NODE )
2620 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
2621 else
2622 q = xmlStaticCopyNode(node, doc, parent, 1);
Daniel Veillard06047432000-04-24 11:33:38 +00002623 if (ret == NULL) {
2624 q->prev = NULL;
2625 ret = p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002626 } else {
Daniel Veillard06047432000-04-24 11:33:38 +00002627 p->next = q;
2628 q->prev = p;
2629 p = q;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002630 }
2631 node = node->next;
2632 }
2633 return(ret);
2634}
2635
2636/**
2637 * xmlCopyNode:
2638 * @node: the node
2639 * @recursive: if 1 do a recursive copy.
2640 *
2641 * Do a copy of the node.
2642 *
2643 * Returns: a new xmlNodePtr, or NULL in case of error.
2644 */
2645xmlNodePtr
2646xmlCopyNode(xmlNodePtr node, int recursive) {
2647 xmlNodePtr ret;
2648
2649 ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
2650 return(ret);
2651}
2652
2653/**
2654 * xmlCopyNodeList:
2655 * @node: the first node in the list.
2656 *
2657 * Do a recursive copy of the node list.
2658 *
2659 * Returns: a new xmlNodePtr, or NULL in case of error.
2660 */
2661xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
2662 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
2663 return(ret);
2664}
2665
2666/**
2667 * xmlCopyElement:
2668 * @elem: the element
2669 *
2670 * Do a copy of the element definition.
2671 *
2672 * Returns: a new xmlElementPtr, or NULL in case of error.
2673xmlElementPtr
2674xmlCopyElement(xmlElementPtr elem) {
2675 xmlElementPtr ret;
2676
2677 if (elem == NULL) return(NULL);
2678 ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
2679 if (ret == NULL) return(NULL);
2680 if (!recursive) return(ret);
2681 if (elem->properties != NULL)
2682 ret->properties = xmlCopyPropList(elem->properties);
2683
2684 if (elem->nsDef != NULL)
2685 ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
Daniel Veillardcf461992000-03-14 18:30:20 +00002686 if (elem->children != NULL)
2687 ret->children = xmlCopyElementList(elem->children);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002688 return(ret);
2689}
2690 */
2691
2692/**
2693 * xmlCopyDtd:
2694 * @dtd: the dtd
2695 *
2696 * Do a copy of the dtd.
2697 *
2698 * Returns: a new xmlDtdPtr, or NULL in case of error.
2699 */
2700xmlDtdPtr
2701xmlCopyDtd(xmlDtdPtr dtd) {
2702 xmlDtdPtr ret;
2703
2704 if (dtd == NULL) return(NULL);
2705 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
2706 if (ret == NULL) return(NULL);
2707 if (dtd->entities != NULL)
2708 ret->entities = (void *) xmlCopyEntitiesTable(
2709 (xmlEntitiesTablePtr) dtd->entities);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002710 if (dtd->notations != NULL)
2711 ret->notations = (void *) xmlCopyNotationTable(
2712 (xmlNotationTablePtr) dtd->notations);
2713 if (dtd->elements != NULL)
2714 ret->elements = (void *) xmlCopyElementTable(
2715 (xmlElementTablePtr) dtd->elements);
2716 if (dtd->attributes != NULL)
2717 ret->attributes = (void *) xmlCopyAttributeTable(
2718 (xmlAttributeTablePtr) dtd->attributes);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002719 return(ret);
2720}
2721
2722/**
2723 * xmlCopyDoc:
2724 * @doc: the document
2725 * @recursive: if 1 do a recursive copy.
2726 *
2727 * Do a copy of the document info. If recursive, the content tree will
2728 * be copied too as well as Dtd, namespaces and entities.
2729 *
2730 * Returns: a new xmlDocPtr, or NULL in case of error.
2731 */
2732xmlDocPtr
2733xmlCopyDoc(xmlDocPtr doc, int recursive) {
2734 xmlDocPtr ret;
2735
2736 if (doc == NULL) return(NULL);
2737 ret = xmlNewDoc(doc->version);
2738 if (ret == NULL) return(NULL);
2739 if (doc->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002740 ret->name = xmlMemStrdup(doc->name);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002741 if (doc->encoding != NULL)
2742 ret->encoding = xmlStrdup(doc->encoding);
Daniel Veillardde55cf62001-01-31 15:53:13 +00002743 ret->charset = doc->charset;
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002744 ret->compression = doc->compression;
2745 ret->standalone = doc->standalone;
2746 if (!recursive) return(ret);
2747
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002748 if (doc->intSubset != NULL)
2749 ret->intSubset = xmlCopyDtd(doc->intSubset);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002750 if (doc->oldNs != NULL)
2751 ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002752 if (doc->children != NULL) {
2753 xmlNodePtr tmp;
Daniel Veillard06047432000-04-24 11:33:38 +00002754 ret->children = xmlStaticCopyNodeList(doc->children, ret,
2755 (xmlNodePtr)ret);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002756 ret->last = NULL;
2757 tmp = ret->children;
2758 while (tmp != NULL) {
2759 if (tmp->next == NULL)
2760 ret->last = tmp;
2761 tmp = tmp->next;
2762 }
2763 }
Daniel Veillardbe36afe1998-11-27 06:39:50 +00002764 return(ret);
2765}
2766
2767/************************************************************************
2768 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002769 * Content access functions *
2770 * *
2771 ************************************************************************/
2772
Daniel Veillard97b58771998-10-20 06:14:16 +00002773/**
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002774 * xmlDocGetRootElement:
2775 * @doc: the document
2776 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002777 * Get the root element of the document (doc->children is a list
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002778 * containing possibly comments, PIs, etc ...).
2779 *
2780 * Returns the xmlNodePtr for the root or NULL
2781 */
2782xmlNodePtr
2783xmlDocGetRootElement(xmlDocPtr doc) {
2784 xmlNodePtr ret;
2785
2786 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002787 ret = doc->children;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002788 while (ret != NULL) {
2789 if (ret->type == XML_ELEMENT_NODE)
2790 return(ret);
2791 ret = ret->next;
2792 }
2793 return(ret);
2794}
2795
2796/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002797 * xmlDocSetRootElement:
2798 * @doc: the document
2799 * @root: the new document root element
2800 *
Daniel Veillardcf461992000-03-14 18:30:20 +00002801 * Set the root element of the document (doc->children is a list
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002802 * containing possibly comments, PIs, etc ...).
2803 *
2804 * Returns the old root element if any was found
2805 */
2806xmlNodePtr
2807xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
2808 xmlNodePtr old = NULL;
2809
2810 if (doc == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00002811 old = doc->children;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002812 while (old != NULL) {
2813 if (old->type == XML_ELEMENT_NODE)
2814 break;
2815 old = old->next;
2816 }
2817 if (old == NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002818 if (doc->children == NULL) {
2819 doc->children = root;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002820 doc->last = root;
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002821 } else {
Daniel Veillardcf461992000-03-14 18:30:20 +00002822 xmlAddSibling(doc->children, root);
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002823 }
2824 } else {
2825 xmlReplaceNode(old, root);
2826 }
2827 return(old);
2828}
2829
2830/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002831 * xmlNodeSetLang:
2832 * @cur: the node being changed
2833 * @lang: the langage description
2834 *
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002835 * Set the language of a node, i.e. the values of the xml:lang
2836 * attribute.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002837 */
2838void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002839xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002840 if (cur == NULL) return;
2841 switch(cur->type) {
2842 case XML_TEXT_NODE:
2843 case XML_CDATA_SECTION_NODE:
2844 case XML_COMMENT_NODE:
2845 case XML_DOCUMENT_NODE:
2846 case XML_DOCUMENT_TYPE_NODE:
2847 case XML_DOCUMENT_FRAG_NODE:
2848 case XML_NOTATION_NODE:
2849 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002850 case XML_DTD_NODE:
2851 case XML_ELEMENT_DECL:
2852 case XML_ATTRIBUTE_DECL:
2853 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002854 case XML_PI_NODE:
2855 case XML_ENTITY_REF_NODE:
2856 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002857 case XML_NAMESPACE_DECL:
Daniel Veillard04698d92000-09-17 16:00:22 +00002858#ifdef LIBXML_SGML_ENABLED
2859 case XML_SGML_DOCUMENT_NODE:
2860#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002861 case XML_XINCLUDE_START:
2862 case XML_XINCLUDE_END:
Daniel Veillard39c7d712000-09-10 16:14:55 +00002863 return;
2864 case XML_ELEMENT_NODE:
2865 case XML_ATTRIBUTE_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002866 break;
2867 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002868 xmlSetProp(cur, BAD_CAST "xml:lang", lang);
2869}
2870
2871/**
2872 * xmlNodeGetLang:
2873 * @cur: the node being checked
2874 *
2875 * Searches the language of a node, i.e. the values of the xml:lang
2876 * attribute or the one carried by the nearest ancestor.
2877 *
2878 * Returns a pointer to the lang value, or NULL if not found
Daniel Veillarda819dac1999-11-24 18:04:22 +00002879 * It's up to the caller to free the memory.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002880 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00002881xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00002882xmlNodeGetLang(xmlNodePtr cur) {
Daniel Veillarda819dac1999-11-24 18:04:22 +00002883 xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002884
2885 while (cur != NULL) {
2886 lang = xmlGetProp(cur, BAD_CAST "xml:lang");
2887 if (lang != NULL)
2888 return(lang);
2889 cur = cur->parent;
2890 }
2891 return(NULL);
2892}
2893
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002894
2895/**
2896 * xmlNodeSetSpacePreserve:
2897 * @cur: the node being changed
2898 * @val: the xml:space value ("0": default, 1: "preserve")
2899 *
2900 * Set (or reset) the space preserving behaviour of a node, i.e. the
2901 * value of the xml:space attribute.
2902 */
2903void
2904xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
2905 if (cur == NULL) return;
2906 switch(cur->type) {
2907 case XML_TEXT_NODE:
2908 case XML_CDATA_SECTION_NODE:
2909 case XML_COMMENT_NODE:
2910 case XML_DOCUMENT_NODE:
2911 case XML_DOCUMENT_TYPE_NODE:
2912 case XML_DOCUMENT_FRAG_NODE:
2913 case XML_NOTATION_NODE:
2914 case XML_HTML_DOCUMENT_NODE:
2915 case XML_DTD_NODE:
2916 case XML_ELEMENT_DECL:
2917 case XML_ATTRIBUTE_DECL:
2918 case XML_ENTITY_DECL:
2919 case XML_PI_NODE:
2920 case XML_ENTITY_REF_NODE:
2921 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002922 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002923 case XML_XINCLUDE_START:
2924 case XML_XINCLUDE_END:
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002925#ifdef LIBXML_SGML_ENABLED
2926 case XML_SGML_DOCUMENT_NODE:
2927#endif
2928 return;
2929 case XML_ELEMENT_NODE:
2930 case XML_ATTRIBUTE_NODE:
2931 break;
2932 }
2933 switch (val) {
2934 case 0:
2935 xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
2936 break;
2937 case 1:
2938 xmlSetProp(cur, BAD_CAST "xml:space",
2939 BAD_CAST "preserve");
2940 break;
2941 }
2942}
2943
Daniel Veillardb96e6431999-08-29 21:02:19 +00002944/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002945 * xmlNodeGetSpacePreserve:
2946 * @cur: the node being checked
2947 *
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002948 * Searches the space preserving behaviour of a node, i.e. the values
2949 * of the xml:space attribute or the one carried by the nearest
2950 * ancestor.
Daniel Veillardcf461992000-03-14 18:30:20 +00002951 *
2952 * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
2953 */
2954int
2955xmlNodeGetSpacePreserve(xmlNodePtr cur) {
2956 xmlChar *space;
2957
2958 while (cur != NULL) {
2959 space = xmlGetProp(cur, BAD_CAST "xml:space");
2960 if (space != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002961 if (xmlStrEqual(space, BAD_CAST "preserve")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002962 xmlFree(space);
2963 return(1);
2964 }
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002965 if (xmlStrEqual(space, BAD_CAST "default")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002966 xmlFree(space);
2967 return(0);
2968 }
2969 xmlFree(space);
2970 }
2971 cur = cur->parent;
2972 }
2973 return(-1);
2974}
2975
2976/**
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002977 * xmlNodeSetName:
2978 * @cur: the node being changed
2979 * @name: the new tag name
2980 *
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00002981 * Set (or reset) the name of a node.
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002982 */
2983void
2984xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
2985 if (cur == NULL) return;
2986 if (name == NULL) return;
2987 switch(cur->type) {
2988 case XML_TEXT_NODE:
2989 case XML_CDATA_SECTION_NODE:
2990 case XML_COMMENT_NODE:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00002991 case XML_DOCUMENT_TYPE_NODE:
2992 case XML_DOCUMENT_FRAG_NODE:
2993 case XML_NOTATION_NODE:
2994 case XML_HTML_DOCUMENT_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002995 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002996 case XML_XINCLUDE_START:
2997 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00002998#ifdef LIBXML_SGML_ENABLED
2999 case XML_SGML_DOCUMENT_NODE:
3000#endif
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00003001 return;
3002 case XML_ELEMENT_NODE:
3003 case XML_ATTRIBUTE_NODE:
3004 case XML_PI_NODE:
3005 case XML_ENTITY_REF_NODE:
3006 case XML_ENTITY_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003007 case XML_DTD_NODE:
3008 case XML_DOCUMENT_NODE:
3009 case XML_ELEMENT_DECL:
3010 case XML_ATTRIBUTE_DECL:
3011 case XML_ENTITY_DECL:
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00003012 break;
3013 }
3014 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
3015 cur->name = xmlStrdup(name);
3016}
3017
3018/**
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00003019 * xmlNodeSetBase:
3020 * @cur: the node being changed
3021 * @uri: the new base URI
3022 *
3023 * Set (or reset) the base URI of a node, i.e. the value of the
3024 * xml:base attribute.
3025 */
3026void
3027xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
3028 if (cur == NULL) return;
3029 switch(cur->type) {
3030 case XML_TEXT_NODE:
3031 case XML_CDATA_SECTION_NODE:
3032 case XML_COMMENT_NODE:
3033 case XML_DOCUMENT_NODE:
3034 case XML_DOCUMENT_TYPE_NODE:
3035 case XML_DOCUMENT_FRAG_NODE:
3036 case XML_NOTATION_NODE:
3037 case XML_HTML_DOCUMENT_NODE:
3038 case XML_DTD_NODE:
3039 case XML_ELEMENT_DECL:
3040 case XML_ATTRIBUTE_DECL:
3041 case XML_ENTITY_DECL:
3042 case XML_PI_NODE:
3043 case XML_ENTITY_REF_NODE:
3044 case XML_ENTITY_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003045 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003046 case XML_XINCLUDE_START:
3047 case XML_XINCLUDE_END:
Daniel Veillardbe9ec4b2000-10-25 11:01:53 +00003048#ifdef LIBXML_SGML_ENABLED
3049 case XML_SGML_DOCUMENT_NODE:
3050#endif
3051 return;
3052 case XML_ELEMENT_NODE:
3053 case XML_ATTRIBUTE_NODE:
3054 break;
3055 }
3056 xmlSetProp(cur, BAD_CAST "xml:base", uri);
3057}
3058
3059/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003060 * xmlDocumentGetBase:
3061 * @doc: the document
3062 *
3063 * Searches for the Document BASE URL. The code should work on both XML
3064 * and HTML document.
3065 * It returns the base as defined in RFC 2396 section
3066 * 5.1.3. Base URI from the Retrieval URI
3067 * However it does not return the computed base (5.1.1 and 5.1.2), use
3068 * xmlNodeGetBase() for this
3069 *
3070 * Returns a pointer to the base URL, or NULL if not found
3071 * It's up to the caller to free the memory.
3072 */
3073xmlChar *
3074xmlDocumentGetBase(xmlDocPtr doc) {
3075 if (doc == NULL)
3076 return(NULL);
3077 if (doc->type == XML_HTML_DOCUMENT_NODE) {
3078 if (doc->URL != NULL)
3079 return(xmlStrdup(doc->URL));
3080 return(NULL);
3081 }
3082 if (doc->URL != NULL)
3083 return(xmlStrdup(doc->URL));
3084 return(NULL);
3085}
3086
3087/**
Daniel Veillard10a2c651999-12-12 13:03:50 +00003088 * xmlNodeGetBase:
3089 * @doc: the document the node pertains to
3090 * @cur: the node being checked
3091 *
3092 * Searches for the BASE URL. The code should work on both XML
3093 * and HTML document even if base mechanisms are completely different.
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003094 * It returns the base as defined in RFC 2396 sections
3095 * 5.1.1. Base URI within Document Content
3096 * and
3097 * 5.1.2. Base URI from the Encapsulating Entity
3098 * However it does not return the document base (5.1.3), use
3099 * xmlDocumentGetBase() for this
Daniel Veillard10a2c651999-12-12 13:03:50 +00003100 *
3101 * Returns a pointer to the base URL, or NULL if not found
3102 * It's up to the caller to free the memory.
3103 */
3104xmlChar *
3105xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
3106 xmlChar *base;
3107
3108 if ((cur == NULL) && (doc == NULL))
3109 return(NULL);
3110 if (doc == NULL) doc = cur->doc;
3111 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003112 cur = doc->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003113 while ((cur != NULL) && (cur->name != NULL)) {
3114 if (cur->type != XML_ELEMENT_NODE) {
3115 cur = cur->next;
3116 continue;
3117 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003118 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003119 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003120 continue;
3121 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003122 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003123 cur = cur->children;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003124 continue;
3125 }
Daniel Veillardb656ebe2000-09-22 13:51:48 +00003126 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
3127 return(xmlGetProp(cur, BAD_CAST "href"));
Daniel Veillard10a2c651999-12-12 13:03:50 +00003128 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003129 cur = cur->next;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003130 }
3131 return(NULL);
3132 }
3133 while (cur != NULL) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003134 if (cur->type == XML_ENTITY_DECL) {
3135 xmlEntityPtr ent = (xmlEntityPtr) cur;
3136 return(xmlStrdup(ent->URI));
3137 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003138 base = xmlGetProp(cur, BAD_CAST "xml:base");
3139 if (base != NULL)
3140 return(base);
3141 cur = cur->parent;
3142 }
3143 return(NULL);
3144}
3145
3146/**
Daniel Veillard16253641998-10-28 22:58:05 +00003147 * xmlNodeGetContent:
3148 * @cur: the node being read
3149 *
3150 * Read the value of a node, this can be either the text carried
3151 * directly by this node if it's a TEXT node or the aggregate string
3152 * of the values carried by this node child's (TEXT and ENTITY_REF).
3153 * Entity references are substitued.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003154 * Returns a new xmlChar * or NULL if no content is available.
Daniel Veillard5099ae81999-04-21 20:12:07 +00003155 * It's up to the caller to free the memory.
Daniel Veillard16253641998-10-28 22:58:05 +00003156 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003157xmlChar *
Daniel Veillard16253641998-10-28 22:58:05 +00003158xmlNodeGetContent(xmlNodePtr cur) {
3159 if (cur == NULL) return(NULL);
3160 switch (cur->type) {
3161 case XML_DOCUMENT_FRAG_NODE:
3162 case XML_ELEMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003163 return(xmlNodeListGetString(cur->doc, cur->children, 1));
Daniel Veillard16253641998-10-28 22:58:05 +00003164 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003165 case XML_ATTRIBUTE_NODE: {
3166 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00003167 if (attr->parent != NULL)
3168 return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003169 else
Daniel Veillardcf461992000-03-14 18:30:20 +00003170 return(xmlNodeListGetString(NULL, attr->children, 1));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003171 break;
3172 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003173 case XML_COMMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003174 case XML_PI_NODE:
3175 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003176#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00003177 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003178#else
3179 return(xmlStrdup(xmlBufferContent(cur->content)));
3180#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00003181 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00003182 case XML_ENTITY_REF_NODE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003183 /*
3184 * Locate the entity, and get it's content
3185 * @@@
3186 */
3187 return(NULL);
Daniel Veillard16253641998-10-28 22:58:05 +00003188 case XML_ENTITY_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003189 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003190 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003191 case XML_DOCUMENT_TYPE_NODE:
3192 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003193 case XML_DTD_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003194 case XML_XINCLUDE_START:
3195 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003196#ifdef LIBXML_SGML_ENABLED
3197 case XML_SGML_DOCUMENT_NODE:
3198#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00003199 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00003200 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003201 return(xmlStrdup(((xmlNsPtr)cur)->href));
Daniel Veillardcf461992000-03-14 18:30:20 +00003202 case XML_ELEMENT_DECL:
3203 /* TODO !!! */
3204 return(NULL);
3205 case XML_ATTRIBUTE_DECL:
3206 /* TODO !!! */
3207 return(NULL);
3208 case XML_ENTITY_DECL:
3209 /* TODO !!! */
Daniel Veillard16253641998-10-28 22:58:05 +00003210 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003211 case XML_CDATA_SECTION_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003212 case XML_TEXT_NODE:
3213 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003214#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003215 return(xmlStrdup(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003216#else
3217 return(xmlStrdup(xmlBufferContent(cur->content)));
3218#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003219 return(NULL);
3220 }
3221 return(NULL);
3222}
3223
3224/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003225 * xmlNodeSetContent:
3226 * @cur: the node being modified
3227 * @content: the new value of the content
3228 *
3229 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003230 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003231void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003232xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003233 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003234#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003235 xmlGenericError(xmlGenericErrorContext,
3236 "xmlNodeSetContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003237#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003238 return;
3239 }
Daniel Veillard16253641998-10-28 22:58:05 +00003240 switch (cur->type) {
3241 case XML_DOCUMENT_FRAG_NODE:
3242 case XML_ELEMENT_NODE:
3243 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003244#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003245 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003246#else
3247 xmlBufferFree(cur->content);
3248#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003249 cur->content = NULL;
3250 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003251 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3252 cur->children = xmlStringGetNodeList(cur->doc, content);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003253 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00003254 break;
3255 case XML_ATTRIBUTE_NODE:
3256 break;
3257 case XML_TEXT_NODE:
3258 case XML_CDATA_SECTION_NODE:
3259 case XML_ENTITY_REF_NODE:
3260 case XML_ENTITY_NODE:
3261 case XML_PI_NODE:
3262 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003263 if (cur->content != NULL) {
3264#ifndef XML_USE_BUFFER_CONTENT
3265 xmlFree(cur->content);
3266#else
3267 xmlBufferFree(cur->content);
3268#endif
3269 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003270 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3271 cur->last = cur->children = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003272 if (content != NULL) {
3273#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003274 cur->content = xmlStrdup(content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003275#else
3276 cur->content = xmlBufferCreateSize(0);
3277 xmlBufferSetAllocationScheme(cur->content,
3278 xmlGetBufferAllocationScheme());
3279 xmlBufferAdd(cur->content, content, -1);
3280#endif
3281 } else
Daniel Veillard16253641998-10-28 22:58:05 +00003282 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003283 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003284 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003285 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003286 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003287 case XML_XINCLUDE_START:
3288 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003289#ifdef LIBXML_SGML_ENABLED
3290 case XML_SGML_DOCUMENT_NODE:
3291#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003292 break;
3293 case XML_NOTATION_NODE:
3294 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003295 case XML_DTD_NODE:
3296 break;
Daniel Veillarda4964b72000-10-31 18:23:44 +00003297 case XML_NAMESPACE_DECL:
3298 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003299 case XML_ELEMENT_DECL:
3300 /* TODO !!! */
3301 break;
3302 case XML_ATTRIBUTE_DECL:
3303 /* TODO !!! */
3304 break;
3305 case XML_ENTITY_DECL:
3306 /* TODO !!! */
3307 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003308 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003309}
3310
Daniel Veillard97b58771998-10-20 06:14:16 +00003311/**
3312 * xmlNodeSetContentLen:
3313 * @cur: the node being modified
3314 * @content: the new value of the content
3315 * @len: the size of @content
3316 *
3317 * Replace the content of a node.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003318 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003319void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003320xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003321 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003322#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003323 xmlGenericError(xmlGenericErrorContext,
3324 "xmlNodeSetContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003325#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003326 return;
3327 }
Daniel Veillard16253641998-10-28 22:58:05 +00003328 switch (cur->type) {
3329 case XML_DOCUMENT_FRAG_NODE:
3330 case XML_ELEMENT_NODE:
3331 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003332#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003333 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003334#else
3335 xmlBufferFree(cur->content);
3336#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003337 cur->content = NULL;
3338 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003339 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3340 cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003341 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillard16253641998-10-28 22:58:05 +00003342 break;
3343 case XML_ATTRIBUTE_NODE:
3344 break;
3345 case XML_TEXT_NODE:
3346 case XML_CDATA_SECTION_NODE:
3347 case XML_ENTITY_REF_NODE:
3348 case XML_ENTITY_NODE:
3349 case XML_PI_NODE:
3350 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003351 case XML_NOTATION_NODE:
3352 if (cur->content != NULL) {
3353#ifndef XML_USE_BUFFER_CONTENT
3354 xmlFree(cur->content);
3355#else
3356 xmlBufferFree(cur->content);
3357#endif
3358 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003359 if (cur->children != NULL) xmlFreeNodeList(cur->children);
3360 cur->children = cur->last = NULL;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003361 if (content != NULL) {
3362#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003363 cur->content = xmlStrndup(content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003364#else
3365 cur->content = xmlBufferCreateSize(len);
3366 xmlBufferSetAllocationScheme(cur->content,
3367 xmlGetBufferAllocationScheme());
3368 xmlBufferAdd(cur->content, content, len);
3369#endif
3370 } else
Daniel Veillard16253641998-10-28 22:58:05 +00003371 cur->content = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003372 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003373 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003374 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003375 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003376 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003377 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003378 case XML_XINCLUDE_START:
3379 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003380#ifdef LIBXML_SGML_ENABLED
3381 case XML_SGML_DOCUMENT_NODE:
3382#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003383 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003384 case XML_ELEMENT_DECL:
3385 /* TODO !!! */
3386 break;
3387 case XML_ATTRIBUTE_DECL:
3388 /* TODO !!! */
3389 break;
3390 case XML_ENTITY_DECL:
3391 /* TODO !!! */
3392 break;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003393 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003394}
3395
Daniel Veillard97b58771998-10-20 06:14:16 +00003396/**
3397 * xmlNodeAddContentLen:
3398 * @cur: the node being modified
3399 * @content: extra content
3400 * @len: the size of @content
3401 *
3402 * Append the extra substring to the node content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003403 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003404void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003405xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003406 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003407#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003408 xmlGenericError(xmlGenericErrorContext,
3409 "xmlNodeAddContentLen : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003410#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003411 return;
3412 }
3413 if (len <= 0) return;
3414 switch (cur->type) {
3415 case XML_DOCUMENT_FRAG_NODE:
3416 case XML_ELEMENT_NODE: {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003417 xmlNodePtr last = NULL, newNode;
Daniel Veillard16253641998-10-28 22:58:05 +00003418
Daniel Veillardcf461992000-03-14 18:30:20 +00003419 if (cur->children != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003420 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003421 } else {
3422 if (cur->content != NULL) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003423#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardcf461992000-03-14 18:30:20 +00003424 cur->children = xmlStringGetNodeList(cur->doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003425#else
Daniel Veillardcf461992000-03-14 18:30:20 +00003426 cur->children = xmlStringGetNodeList(cur->doc,
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003427 xmlBufferContent(cur->content));
3428#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003429 UPDATE_LAST_CHILD_AND_PARENT(cur)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003430#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard6454aec1999-09-02 22:04:43 +00003431 xmlFree(cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003432#else
3433 xmlBufferFree(cur->content);
3434#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003435 cur->content = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003436 last = cur->last;
Daniel Veillard16253641998-10-28 22:58:05 +00003437 }
3438 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003439 newNode = xmlNewTextLen(content, len);
3440 if (newNode != NULL) {
3441 xmlAddChild(cur, newNode);
3442 if ((last != NULL) && (last->next == newNode)) {
3443 xmlTextMerge(last, newNode);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003444 }
Daniel Veillard16253641998-10-28 22:58:05 +00003445 }
3446 break;
3447 }
3448 case XML_ATTRIBUTE_NODE:
3449 break;
3450 case XML_TEXT_NODE:
3451 case XML_CDATA_SECTION_NODE:
3452 case XML_ENTITY_REF_NODE:
3453 case XML_ENTITY_NODE:
3454 case XML_PI_NODE:
3455 case XML_COMMENT_NODE:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003456 case XML_NOTATION_NODE:
3457 if (content != NULL) {
3458#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003459 cur->content = xmlStrncat(cur->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003460#else
3461 xmlBufferAdd(cur->content, content, len);
3462#endif
3463 }
Daniel Veillard16253641998-10-28 22:58:05 +00003464 case XML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003465 case XML_DTD_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003466 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard16253641998-10-28 22:58:05 +00003467 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00003468 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003469 case XML_XINCLUDE_START:
3470 case XML_XINCLUDE_END:
Daniel Veillard04698d92000-09-17 16:00:22 +00003471#ifdef LIBXML_SGML_ENABLED
3472 case XML_SGML_DOCUMENT_NODE:
3473#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003474 break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003475 case XML_ELEMENT_DECL:
3476 case XML_ATTRIBUTE_DECL:
3477 case XML_ENTITY_DECL:
3478 break;
Daniel Veillard16253641998-10-28 22:58:05 +00003479 }
3480}
3481
3482/**
3483 * xmlNodeAddContent:
3484 * @cur: the node being modified
3485 * @content: extra content
3486 *
3487 * Append the extra substring to the node content.
3488 */
3489void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003490xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
Daniel Veillard16253641998-10-28 22:58:05 +00003491 int len;
3492
3493 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003494#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003495 xmlGenericError(xmlGenericErrorContext,
3496 "xmlNodeAddContent : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00003497#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00003498 return;
3499 }
Daniel Veillard16253641998-10-28 22:58:05 +00003500 if (content == NULL) return;
3501 len = xmlStrlen(content);
3502 xmlNodeAddContentLen(cur, content, len);
3503}
3504
3505/**
3506 * xmlTextMerge:
3507 * @first: the first text node
3508 * @second: the second text node being merged
3509 *
3510 * Merge two text nodes into one
Daniel Veillard1e346af1999-02-22 10:33:01 +00003511 * Returns the first text node augmented
Daniel Veillard16253641998-10-28 22:58:05 +00003512 */
3513xmlNodePtr
3514xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
3515 if (first == NULL) return(second);
3516 if (second == NULL) return(first);
3517 if (first->type != XML_TEXT_NODE) return(first);
3518 if (second->type != XML_TEXT_NODE) return(first);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003519#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard16253641998-10-28 22:58:05 +00003520 xmlNodeAddContent(first, second->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00003521#else
3522 xmlNodeAddContent(first, xmlBufferContent(second->content));
3523#endif
Daniel Veillard16253641998-10-28 22:58:05 +00003524 xmlUnlinkNode(second);
3525 xmlFreeNode(second);
3526 return(first);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003527}
3528
Daniel Veillard97b58771998-10-20 06:14:16 +00003529/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003530 * xmlGetNsList:
3531 * @doc: the document
3532 * @node: the current node
3533 *
3534 * Search all the namespace applying to a given element.
3535 * Returns an NULL terminated array of all the xmlNsPtr found
3536 * that need to be freed by the caller or NULL if no
3537 * namespace if defined
3538 */
3539xmlNsPtr *
3540xmlGetNsList(xmlDocPtr doc, xmlNodePtr node) {
3541 xmlNsPtr cur;
3542 xmlNsPtr *ret = NULL;
3543 int nbns = 0;
3544 int maxns = 10;
3545 int i;
3546
3547 while (node != NULL) {
3548 cur = node->nsDef;
3549 while (cur != NULL) {
3550 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003551 ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
Daniel Veillardb96e6431999-08-29 21:02:19 +00003552 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003553 xmlGenericError(xmlGenericErrorContext,
3554 "xmlGetNsList : out of memory!\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00003555 return(NULL);
3556 }
3557 ret[nbns] = NULL;
3558 }
3559 for (i = 0;i < nbns;i++) {
3560 if ((cur->prefix == ret[i]->prefix) ||
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003561 (xmlStrEqual(cur->prefix, ret[i]->prefix))) break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003562 }
3563 if (i >= nbns) {
3564 if (nbns >= maxns) {
3565 maxns *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003566 ret = (xmlNsPtr *) xmlRealloc(ret,
Daniel Veillardb96e6431999-08-29 21:02:19 +00003567 (maxns + 1) * sizeof(xmlNsPtr));
3568 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003569 xmlGenericError(xmlGenericErrorContext,
3570 "xmlGetNsList : realloc failed!\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00003571 return(NULL);
3572 }
3573 }
3574 ret[nbns++] = cur;
3575 ret[nbns] = NULL;
3576 }
3577
3578 cur = cur->next;
3579 }
3580 node = node->parent;
3581 }
3582 return(ret);
3583}
3584
3585/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003586 * xmlSearchNs:
3587 * @doc: the document
3588 * @node: the current node
3589 * @nameSpace: the namespace string
Daniel Veillard260a68f1998-08-13 03:39:55 +00003590 *
Daniel Veillard97b58771998-10-20 06:14:16 +00003591 * Search a Ns registered under a given name space for a document.
3592 * recurse on the parents until it finds the defined namespace
3593 * or return NULL otherwise.
3594 * @nameSpace can be NULL, this is a search for the default namespace.
Daniel Veillarde0854c32000-08-27 21:12:29 +00003595 * We don't allow to cross entities boundaries. If you don't declare
3596 * the namespace within those you will be in troubles !!! A warning
3597 * is generated to cover this case.
3598 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003599 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003600 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003601xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003602xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003603 xmlNsPtr cur;
3604
Daniel Veillard62ba71e1999-12-16 17:52:19 +00003605 if (node == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003606 while (node != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003607 if ((node->type == XML_ENTITY_REF_NODE) ||
3608 (node->type == XML_ENTITY_NODE) ||
3609 (node->type == XML_ENTITY_DECL))
3610 return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00003611 if (node->type == XML_ELEMENT_NODE) {
3612 cur = node->nsDef;
3613 while (cur != NULL) {
Daniel Veillarde0854c32000-08-27 21:12:29 +00003614 if ((cur->prefix == NULL) && (nameSpace == NULL) &&
3615 (cur->href != NULL))
Daniel Veillardcf461992000-03-14 18:30:20 +00003616 return(cur);
3617 if ((cur->prefix != NULL) && (nameSpace != NULL) &&
Daniel Veillarde0854c32000-08-27 21:12:29 +00003618 (cur->href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003619 (xmlStrEqual(cur->prefix, nameSpace)))
Daniel Veillardcf461992000-03-14 18:30:20 +00003620 return(cur);
3621 cur = cur->next;
3622 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003623 }
3624 node = node->parent;
3625 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003626 return(NULL);
3627}
3628
Daniel Veillard97b58771998-10-20 06:14:16 +00003629/**
3630 * xmlSearchNsByHref:
3631 * @doc: the document
3632 * @node: the current node
3633 * @href: the namespace value
3634 *
3635 * Search a Ns aliasing a given URI. Recurse on the parents until it finds
3636 * the defined namespace or return NULL otherwise.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003637 * Returns the namespace pointer or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003638 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00003639xmlNsPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003640xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003641 xmlNsPtr cur;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003642 xmlNodePtr orig = node;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003643
Daniel Veillard10a2c651999-12-12 13:03:50 +00003644 if ((node == NULL) || (href == NULL)) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003645 while (node != NULL) {
3646 cur = node->nsDef;
3647 while (cur != NULL) {
3648 if ((cur->href != NULL) && (href != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003649 (xmlStrEqual(cur->href, href))) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003650 /*
3651 * Check that the prefix is not shadowed between orig and node
3652 */
3653 xmlNodePtr check = orig;
3654 xmlNsPtr tst;
3655
3656 while (check != node) {
3657 tst = check->nsDef;
3658 while (tst != NULL) {
3659 if ((tst->prefix == NULL) && (cur->prefix == NULL))
3660 goto shadowed;
3661 if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003662 (xmlStrEqual(tst->prefix, cur->prefix)))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003663 goto shadowed;
3664 tst = tst->next;
3665 }
Daniel Veillardc4f4f0b2000-10-29 17:46:30 +00003666 check = check->parent;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003667 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003668 return(cur);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003669 }
3670shadowed:
Daniel Veillard260a68f1998-08-13 03:39:55 +00003671 cur = cur->next;
3672 }
3673 node = node->parent;
3674 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003675 return(NULL);
3676}
3677
3678/**
3679 * xmlNewReconciliedNs
3680 * @doc: the document
3681 * @tree: a node expected to hold the new namespace
3682 * @ns: the original namespace
3683 *
3684 * This function tries to locate a namespace definition in a tree
3685 * ancestors, or create a new namespace definition node similar to
3686 * @ns trying to reuse the same prefix. However if the given prefix is
3687 * null (default namespace) or reused within the subtree defined by
3688 * @tree or on one of its ancestors then a new prefix is generated.
3689 * Returns the (new) namespace definition or NULL in case of error
3690 */
3691xmlNsPtr
3692xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
3693 xmlNsPtr def;
3694 xmlChar prefix[50];
3695 int counter = 1;
3696
3697 if (tree == NULL) {
3698#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003699 xmlGenericError(xmlGenericErrorContext,
3700 "xmlNewReconciliedNs : tree == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003701#endif
3702 return(NULL);
3703 }
3704 if (ns == NULL) {
3705#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003706 xmlGenericError(xmlGenericErrorContext,
3707 "xmlNewReconciliedNs : ns == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003708#endif
3709 return(NULL);
3710 }
3711 /*
3712 * Search an existing namespace definition inherited.
3713 */
3714 def = xmlSearchNsByHref(doc, tree, ns->href);
3715 if (def != NULL)
3716 return(def);
3717
3718 /*
3719 * Find a close prefix which is not already in use.
3720 * Let's strip namespace prefixes longer than 20 chars !
3721 */
3722 sprintf((char *) prefix, "%.20s", ns->prefix);
3723 def = xmlSearchNs(doc, tree, prefix);
3724 while (def != NULL) {
3725 if (counter > 1000) return(NULL);
3726 sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
3727 def = xmlSearchNs(doc, tree, prefix);
3728 }
3729
3730 /*
3731 * Ok, now we are ready to create a new one.
3732 */
3733 def = xmlNewNs(tree, ns->href, prefix);
3734 return(def);
3735}
3736
3737/**
3738 * xmlReconciliateNs
3739 * @doc: the document
3740 * @tree: a node defining the subtree to reconciliate
3741 *
3742 * This function checks that all the namespaces declared within the given
3743 * tree are properly declared. This is needed for example after Copy or Cut
3744 * and then paste operations. The subtree may still hold pointers to
3745 * namespace declarations outside the subtree or invalid/masked. As much
3746 * as possible the function try tu reuse the existing namespaces found in
3747 * the new environment. If not possible the new namespaces are redeclared
3748 * on @tree at the top of the given subtree.
3749 * Returns the number of namespace declarations created or -1 in case of error.
3750 */
3751int
3752xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
3753 xmlNsPtr *oldNs = NULL;
3754 xmlNsPtr *newNs = NULL;
3755 int sizeCache = 0;
3756 int nbCache = 0;
3757
3758 xmlNsPtr n;
3759 xmlNodePtr node = tree;
3760 xmlAttrPtr attr;
3761 int ret = 0, i;
3762
3763 while (node != NULL) {
3764 /*
3765 * Reconciliate the node namespace
3766 */
3767 if (node->ns != NULL) {
3768 /*
3769 * initialize the cache if needed
3770 */
3771 if (sizeCache == 0) {
3772 sizeCache = 10;
3773 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3774 sizeof(xmlNsPtr));
3775 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003776 xmlGenericError(xmlGenericErrorContext,
3777 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003778 return(-1);
3779 }
3780 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3781 sizeof(xmlNsPtr));
3782 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003783 xmlGenericError(xmlGenericErrorContext,
3784 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003785 xmlFree(oldNs);
3786 return(-1);
3787 }
3788 }
3789 for (i = 0;i < nbCache;i++) {
3790 if (oldNs[i] == node->ns) {
3791 node->ns = newNs[i];
3792 break;
3793 }
3794 }
3795 if (i == nbCache) {
3796 /*
3797 * Ok we need to recreate a new namespace definition
3798 */
3799 n = xmlNewReconciliedNs(doc, tree, node->ns);
3800 if (n != NULL) { /* :-( what if else ??? */
3801 /*
3802 * check if we need to grow the cache buffers.
3803 */
3804 if (sizeCache <= nbCache) {
3805 sizeCache *= 2;
3806 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3807 sizeof(xmlNsPtr));
3808 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003809 xmlGenericError(xmlGenericErrorContext,
3810 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003811 xmlFree(newNs);
3812 return(-1);
3813 }
3814 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3815 sizeof(xmlNsPtr));
3816 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003817 xmlGenericError(xmlGenericErrorContext,
3818 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003819 xmlFree(oldNs);
3820 return(-1);
3821 }
3822 }
3823 newNs[nbCache] = n;
3824 oldNs[nbCache++] = node->ns;
3825 node->ns = n;
3826 }
3827 }
3828 }
3829 /*
3830 * now check for namespace hold by attributes on the node.
3831 */
3832 attr = node->properties;
3833 while (attr != NULL) {
3834 if (attr->ns != NULL) {
3835 /*
3836 * initialize the cache if needed
3837 */
3838 if (sizeCache == 0) {
3839 sizeCache = 10;
3840 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3841 sizeof(xmlNsPtr));
3842 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003843 xmlGenericError(xmlGenericErrorContext,
3844 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003845 return(-1);
3846 }
3847 newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
3848 sizeof(xmlNsPtr));
3849 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003850 xmlGenericError(xmlGenericErrorContext,
3851 "xmlReconciliateNs : memory pbm\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003852 xmlFree(oldNs);
3853 return(-1);
3854 }
3855 }
3856 for (i = 0;i < nbCache;i++) {
3857 if (oldNs[i] == attr->ns) {
3858 node->ns = newNs[i];
3859 break;
3860 }
3861 }
3862 if (i == nbCache) {
3863 /*
3864 * Ok we need to recreate a new namespace definition
3865 */
3866 n = xmlNewReconciliedNs(doc, tree, attr->ns);
3867 if (n != NULL) { /* :-( what if else ??? */
3868 /*
3869 * check if we need to grow the cache buffers.
3870 */
3871 if (sizeCache <= nbCache) {
3872 sizeCache *= 2;
3873 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
3874 sizeof(xmlNsPtr));
3875 if (oldNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003876 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003877 "xmlReconciliateNs : memory pbm\n");
3878 xmlFree(newNs);
3879 return(-1);
3880 }
3881 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
3882 sizeof(xmlNsPtr));
3883 if (newNs == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003884 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003885 "xmlReconciliateNs : memory pbm\n");
3886 xmlFree(oldNs);
3887 return(-1);
3888 }
3889 }
3890 newNs[nbCache] = n;
3891 oldNs[nbCache++] = attr->ns;
3892 attr->ns = n;
3893 }
3894 }
3895 }
3896 attr = attr->next;
3897 }
3898
3899 /*
3900 * Browse the full subtree, deep first
3901 */
Daniel Veillardcf461992000-03-14 18:30:20 +00003902 if (node->children != NULL) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003903 /* deep first */
Daniel Veillardcf461992000-03-14 18:30:20 +00003904 node = node->children;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003905 } else if ((node != tree) && (node->next != NULL)) {
3906 /* then siblings */
3907 node = node->next;
3908 } else if (node != tree) {
3909 /* go up to parents->next if needed */
3910 while (node != tree) {
3911 if (node->parent != NULL)
3912 node = node->parent;
3913 if ((node != tree) && (node->next != NULL)) {
3914 node = node->next;
3915 break;
3916 }
3917 if (node->parent == NULL) {
3918 node = NULL;
3919 break;
3920 }
3921 }
3922 /* exit condition */
3923 if (node == tree)
3924 node = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003925 }
3926 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003927 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003928}
3929
Daniel Veillard97b58771998-10-20 06:14:16 +00003930/**
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003931 * xmlHasProp:
3932 * @node: the node
3933 * @name: the attribute name
3934 *
3935 * Search an attribute associated to a node
3936 * This function also looks in DTD attribute declaration for #FIXED or
3937 * default declaration values unless DTD use has been turned off.
3938 *
3939 * Returns the attribute or the attribute declaration or NULL if
3940 * neither was found.
3941 */
3942xmlAttrPtr
3943xmlHasProp(xmlNodePtr node, const xmlChar *name) {
3944 xmlAttrPtr prop;
3945 xmlDocPtr doc;
3946
3947 if ((node == NULL) || (name == NULL)) return(NULL);
3948 /*
3949 * Check on the properties attached to the node
3950 */
3951 prop = node->properties;
3952 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003953 if (xmlStrEqual(prop->name, name)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003954 return(prop);
3955 }
3956 prop = prop->next;
3957 }
3958 if (!xmlCheckDTD) return(NULL);
3959
3960 /*
3961 * Check if there is a default declaration in the internal
3962 * or external subsets
3963 */
3964 doc = node->doc;
3965 if (doc != NULL) {
3966 xmlAttributePtr attrDecl;
3967 if (doc->intSubset != NULL) {
3968 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
3969 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3970 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
3971 if (attrDecl != NULL)
3972 return((xmlAttrPtr) attrDecl);
3973 }
3974 }
3975 return(NULL);
3976}
3977
3978/**
Daniel Veillard97b58771998-10-20 06:14:16 +00003979 * xmlGetProp:
3980 * @node: the node
3981 * @name: the attribute name
3982 *
3983 * Search and get the value of an attribute associated to a node
Daniel Veillardccb09631998-10-27 06:21:04 +00003984 * This does the entity substitution.
Daniel Veillard10a2c651999-12-12 13:03:50 +00003985 * This function looks in DTD attribute declaration for #FIXED or
3986 * default declaration values unless DTD use has been turned off.
3987 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003988 * Returns the attribute value or NULL if not found.
Daniel Veillarda819dac1999-11-24 18:04:22 +00003989 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003990 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003991xmlChar *
3992xmlGetProp(xmlNodePtr node, const xmlChar *name) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003993 xmlAttrPtr prop;
3994 xmlDocPtr doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003995
Daniel Veillard10a2c651999-12-12 13:03:50 +00003996 if ((node == NULL) || (name == NULL)) return(NULL);
3997 /*
3998 * Check on the properties attached to the node
3999 */
4000 prop = node->properties;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004001 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004002 if (xmlStrEqual(prop->name, name)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004003 xmlChar *ret;
Daniel Veillard6800ef31999-02-08 18:33:22 +00004004
Daniel Veillardcf461992000-03-14 18:30:20 +00004005 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004006 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
Daniel Veillard6800ef31999-02-08 18:33:22 +00004007 return(ret);
Daniel Veillard68178931999-02-08 18:34:36 +00004008 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004009 prop = prop->next;
4010 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00004011 if (!xmlCheckDTD) return(NULL);
4012
4013 /*
4014 * Check if there is a default declaration in the internal
4015 * or external subsets
4016 */
4017 doc = node->doc;
4018 if (doc != NULL) {
4019 xmlAttributePtr attrDecl;
4020 if (doc->intSubset != NULL) {
4021 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4022 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4023 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
Daniel Veillardf967b902000-01-17 16:06:10 +00004024 if (attrDecl != NULL)
4025 return(xmlStrdup(attrDecl->defaultValue));
Daniel Veillard10a2c651999-12-12 13:03:50 +00004026 }
4027 }
4028 return(NULL);
4029}
4030
4031/**
4032 * xmlGetNsProp:
4033 * @node: the node
4034 * @name: the attribute name
4035 * @namespace: the URI of the namespace
4036 *
4037 * Search and get the value of an attribute associated to a node
4038 * This attribute has to be anchored in the namespace specified.
4039 * This does the entity substitution.
4040 * This function looks in DTD attribute declaration for #FIXED or
4041 * default declaration values unless DTD use has been turned off.
4042 *
4043 * Returns the attribute value or NULL if not found.
4044 * It's up to the caller to free the memory.
4045 */
4046xmlChar *
4047xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00004048 xmlAttrPtr prop;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004049 xmlDocPtr doc;
4050 xmlNsPtr ns;
4051
Daniel Veillard389e6b72001-01-15 19:41:13 +00004052 if (node == NULL)
4053 return(NULL);
4054
4055 prop = node->properties;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004056 if (namespace == NULL)
4057 return(xmlGetProp(node, name));
4058 while (prop != NULL) {
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00004059 /*
4060 * One need to have
4061 * - same attribute names
4062 * - and the attribute carrying that namespace
4063 * or
4064 * no namespace on the attribute and the element carrying it
4065 */
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004066 if ((xmlStrEqual(prop->name, name)) &&
Daniel Veillard5cb5ab81999-12-21 15:35:29 +00004067 (((prop->ns == NULL) && (node->ns != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004068 (xmlStrEqual(node->ns->href, namespace))) ||
4069 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, namespace))))) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00004070 xmlChar *ret;
4071
Daniel Veillardcf461992000-03-14 18:30:20 +00004072 ret = xmlNodeListGetString(node->doc, prop->children, 1);
Daniel Veillard10a2c651999-12-12 13:03:50 +00004073 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
4074 return(ret);
4075 }
4076 prop = prop->next;
4077 }
4078 if (!xmlCheckDTD) return(NULL);
4079
4080 /*
4081 * Check if there is a default declaration in the internal
4082 * or external subsets
4083 */
4084 doc = node->doc;
4085 if (doc != NULL) {
4086 xmlAttributePtr attrDecl;
4087 if (doc->intSubset != NULL) {
4088 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
4089 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4090 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
4091
Daniel Veillardc2f4df22001-01-04 14:06:39 +00004092 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00004093 /*
4094 * The DTD declaration only allows a prefix search
4095 */
4096 ns = xmlSearchNs(doc, node, attrDecl->prefix);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004097 if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
Daniel Veillard10a2c651999-12-12 13:03:50 +00004098 return(xmlStrdup(attrDecl->defaultValue));
4099 }
4100 }
4101 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004102 return(NULL);
4103}
4104
Daniel Veillard97b58771998-10-20 06:14:16 +00004105/**
Daniel Veillardccb09631998-10-27 06:21:04 +00004106 * xmlSetProp:
Daniel Veillard97b58771998-10-20 06:14:16 +00004107 * @node: the node
4108 * @name: the attribute name
4109 * @value: the attribute value
4110 *
4111 * Set (or reset) an attribute carried by a node.
Daniel Veillard1e346af1999-02-22 10:33:01 +00004112 * Returns the attribute pointer.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004113 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004114xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004115xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004116 xmlAttrPtr prop = node->properties;
Daniel Veillarde4566462001-01-22 09:58:39 +00004117 xmlDocPtr doc = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004118
Daniel Veillarde4566462001-01-22 09:58:39 +00004119 if ((node == NULL) || (name == NULL))
4120 return(NULL);
4121 doc = node->doc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004122 while (prop != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004123 if (xmlStrEqual(prop->name, name)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00004124 if (prop->children != NULL)
4125 xmlFreeNodeList(prop->children);
4126 prop->children = NULL;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004127 prop->last = NULL;
Daniel Veillard51e3b151999-11-12 17:02:31 +00004128 if (value != NULL) {
4129 xmlChar *buffer;
Daniel Veillardcf461992000-03-14 18:30:20 +00004130 xmlNodePtr tmp;
4131
Daniel Veillard51e3b151999-11-12 17:02:31 +00004132 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
Daniel Veillardcf461992000-03-14 18:30:20 +00004133 prop->children = xmlStringGetNodeList(node->doc, buffer);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004134 prop->last = NULL;
Daniel Veillarde4566462001-01-22 09:58:39 +00004135 prop->doc = doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00004136 tmp = prop->children;
4137 while (tmp != NULL) {
4138 tmp->parent = (xmlNodePtr) prop;
Daniel Veillarde4566462001-01-22 09:58:39 +00004139 tmp->doc = doc;
Daniel Veillardcf461992000-03-14 18:30:20 +00004140 if (tmp->next == NULL)
4141 prop->last = tmp;
4142 tmp = tmp->next;
4143 }
Daniel Veillard51e3b151999-11-12 17:02:31 +00004144 xmlFree(buffer);
4145 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004146 return(prop);
4147 }
4148 prop = prop->next;
4149 }
4150 prop = xmlNewProp(node, name, value);
4151 return(prop);
4152}
4153
Daniel Veillard97b58771998-10-20 06:14:16 +00004154/**
Daniel Veillard389e6b72001-01-15 19:41:13 +00004155 * xmlSetNsProp:
4156 * @node: the node
4157 * @ns: the namespace definition
4158 * @name: the attribute name
4159 * @value: the attribute value
4160 *
4161 * Set (or reset) an attribute carried by a node.
4162 * The ns structure must be in scope, this is not checked.
4163 *
4164 * Returns the attribute pointer.
4165 */
4166xmlAttrPtr
4167xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
4168 const xmlChar *value) {
4169 xmlAttrPtr prop;
4170
4171 if ((node == NULL) || (name == NULL))
4172 return(NULL);
4173
4174 if (ns == NULL)
4175 return(xmlSetProp(node, name, value));
4176 if (ns->href == NULL)
4177 return(NULL);
4178 prop = node->properties;
4179
4180 while (prop != NULL) {
4181 /*
4182 * One need to have
4183 * - same attribute names
4184 * - and the attribute carrying that namespace
4185 * or
4186 * no namespace on the attribute and the element carrying it
4187 */
4188 if ((xmlStrEqual(prop->name, name)) &&
4189 (((prop->ns == NULL) && (node->ns != NULL) &&
4190 (xmlStrEqual(node->ns->href, ns->href))) ||
4191 ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
4192 if (prop->children != NULL)
4193 xmlFreeNodeList(prop->children);
4194 prop->children = NULL;
4195 prop->last = NULL;
4196 prop->ns = ns;
4197 if (value != NULL) {
4198 xmlChar *buffer;
4199 xmlNodePtr tmp;
4200
4201 buffer = xmlEncodeEntitiesReentrant(node->doc, value);
4202 prop->children = xmlStringGetNodeList(node->doc, buffer);
4203 prop->last = NULL;
4204 tmp = prop->children;
4205 while (tmp != NULL) {
4206 tmp->parent = (xmlNodePtr) prop;
4207 if (tmp->next == NULL)
4208 prop->last = tmp;
4209 tmp = tmp->next;
4210 }
4211 xmlFree(buffer);
4212 }
4213 return(prop);
4214 }
4215 prop = prop->next;
4216 }
4217 prop = xmlNewNsProp(node, ns, name, value);
4218 return(prop);
4219}
4220
4221/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004222 * xmlNodeIsText:
4223 * @node: the node
4224 *
4225 * Is this node a Text node ?
Daniel Veillard1e346af1999-02-22 10:33:01 +00004226 * Returns 1 yes, 0 no
Daniel Veillard260a68f1998-08-13 03:39:55 +00004227 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004228int
4229xmlNodeIsText(xmlNodePtr node) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004230 if (node == NULL) return(0);
4231
Daniel Veillard0bef1311998-10-14 02:36:47 +00004232 if (node->type == XML_TEXT_NODE) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004233 return(0);
4234}
4235
Daniel Veillard97b58771998-10-20 06:14:16 +00004236/**
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004237 * xmlIsBlankNode:
4238 * @node: the node
4239 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004240 * Checks whether this node is an empty or whitespace only
4241 * (and possibly ignorable) text-node.
4242 *
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004243 * Returns 1 yes, 0 no
4244 */
4245int
4246xmlIsBlankNode(xmlNodePtr node) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004247 const xmlChar *cur;
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004248 if (node == NULL) return(0);
4249
4250 if (node->type != XML_TEXT_NODE) return(0);
Daniel Veillardcd429612000-10-11 15:57:05 +00004251 if (node->content == NULL) return(1);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004252#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004253 cur = node->content;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004254#else
4255 cur = xmlBufferContent(node->content);
4256#endif
Daniel Veillard3e6d2372000-03-04 11:39:43 +00004257 while (*cur != 0) {
4258 if (!IS_BLANK(*cur)) return(0);
4259 cur++;
4260 }
4261
4262 return(1);
4263}
4264
4265/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00004266 * xmlTextConcat:
Daniel Veillard97b58771998-10-20 06:14:16 +00004267 * @node: the node
4268 * @content: the content
4269 * @len: @content lenght
4270 *
4271 * Concat the given string at the end of the existing node content
Daniel Veillard260a68f1998-08-13 03:39:55 +00004272 */
Daniel Veillard97b58771998-10-20 06:14:16 +00004273
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004274void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004275xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004276 if (node == NULL) return;
4277
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004278 if ((node->type != XML_TEXT_NODE) &&
4279 (node->type != XML_CDATA_SECTION_NODE)) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004280#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004281 xmlGenericError(xmlGenericErrorContext,
4282 "xmlTextConcat: node is not text nor cdata\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004283#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004284 return;
4285 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004286#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard260a68f1998-08-13 03:39:55 +00004287 node->content = xmlStrncat(node->content, content, len);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004288#else
4289 xmlBufferAdd(node->content, content, len);
4290#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004291}
4292
4293/************************************************************************
4294 * *
4295 * Output : to a FILE or in memory *
4296 * *
4297 ************************************************************************/
4298
Daniel Veillard5099ae81999-04-21 20:12:07 +00004299#define BASE_BUFFER_SIZE 4000
4300
4301/**
4302 * xmlBufferCreate:
4303 *
4304 * routine to create an XML buffer.
4305 * returns the new structure.
4306 */
4307xmlBufferPtr
4308xmlBufferCreate(void) {
4309 xmlBufferPtr ret;
4310
Daniel Veillard6454aec1999-09-02 22:04:43 +00004311 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
Daniel Veillard5099ae81999-04-21 20:12:07 +00004312 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004313 xmlGenericError(xmlGenericErrorContext,
4314 "xmlBufferCreate : out of memory!\n");
Daniel Veillard5099ae81999-04-21 20:12:07 +00004315 return(NULL);
4316 }
4317 ret->use = 0;
4318 ret->size = BASE_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004319 ret->alloc = xmlBufferAllocScheme;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004320 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
Daniel Veillard5099ae81999-04-21 20:12:07 +00004321 if (ret->content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004322 xmlGenericError(xmlGenericErrorContext,
4323 "xmlBufferCreate : out of memory!\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00004324 xmlFree(ret);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004325 return(NULL);
4326 }
4327 ret->content[0] = 0;
4328 return(ret);
4329}
4330
4331/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004332 * xmlBufferCreateSize:
4333 * @size: initial size of buffer
4334 *
4335 * routine to create an XML buffer.
4336 * returns the new structure.
4337 */
4338xmlBufferPtr
4339xmlBufferCreateSize(size_t size) {
4340 xmlBufferPtr ret;
4341
4342 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
4343 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004344 xmlGenericError(xmlGenericErrorContext,
4345 "xmlBufferCreate : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004346 return(NULL);
4347 }
4348 ret->use = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +00004349 ret->alloc = xmlBufferAllocScheme;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004350 ret->size = (size ? size+2 : 0); /* +1 for ending null */
Daniel Veillard10a2c651999-12-12 13:03:50 +00004351 if (ret->size){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004352 ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
4353 if (ret->content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004354 xmlGenericError(xmlGenericErrorContext,
4355 "xmlBufferCreate : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004356 xmlFree(ret);
4357 return(NULL);
4358 }
4359 ret->content[0] = 0;
4360 } else
4361 ret->content = NULL;
4362 return(ret);
4363}
4364
4365/**
Daniel Veillard06047432000-04-24 11:33:38 +00004366 * xmlBufferSetAllocationScheme:
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004367 * @buf: the buffer to free
4368 * @scheme: allocation scheme to use
4369 *
4370 * Sets the allocation scheme for this buffer
4371 */
4372void
4373xmlBufferSetAllocationScheme(xmlBufferPtr buf,
4374 xmlBufferAllocationScheme scheme) {
4375 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004376#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004377 xmlGenericError(xmlGenericErrorContext,
4378 "xmlBufferSetAllocationScheme: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004379#endif
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004380 return;
4381 }
4382
4383 buf->alloc = scheme;
4384}
4385
4386/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004387 * xmlBufferFree:
4388 * @buf: the buffer to free
4389 *
4390 * Frees an XML buffer.
4391 */
4392void
4393xmlBufferFree(xmlBufferPtr buf) {
4394 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004395#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004396 xmlGenericError(xmlGenericErrorContext,
4397 "xmlBufferFree: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004398#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004399 return;
4400 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004401 if (buf->content != NULL) {
4402#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00004403 memset(buf->content, -1, BASE_BUFFER_SIZE);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004404#else
4405 memset(buf->content, -1, buf->size);
4406#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004407 xmlFree(buf->content);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004408 }
4409 memset(buf, -1, sizeof(xmlBuffer));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004410 xmlFree(buf);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004411}
4412
4413/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004414 * xmlBufferEmpty:
4415 * @buf: the buffer
4416 *
4417 * empty a buffer.
4418 */
4419void
4420xmlBufferEmpty(xmlBufferPtr buf) {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +00004421 if (buf->content == NULL) return;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004422 buf->use = 0;
4423 memset(buf->content, -1, buf->size);/* just for debug */
4424}
4425
4426/**
4427 * xmlBufferShrink:
4428 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004429 * @len: the number of xmlChar to remove
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004430 *
4431 * Remove the beginning of an XML buffer.
4432 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004433 * Returns the number of xmlChar removed, or -1 in case of failure.
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004434 */
4435int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004436xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004437 if (len == 0) return(0);
4438 if (len > buf->use) return(-1);
4439
4440 buf->use -= len;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004441 memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004442
4443 buf->content[buf->use] = 0;
4444 return(len);
4445}
4446
4447/**
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004448 * xmlBufferGrow:
4449 * @buf: the buffer
Daniel Veillard4a6845d2001-01-03 13:32:39 +00004450 * @len: the minimum free size to allocate
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004451 *
4452 * Grow the available space of an XML buffer.
4453 *
4454 * Returns the new available space or -1 in case of error
4455 */
4456int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004457xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004458 int size;
4459 xmlChar *newbuf;
4460
Daniel Veillard4a6845d2001-01-03 13:32:39 +00004461 if (len + buf->use < buf->size) return(0);
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004462
Daniel Veillardbe803962000-06-28 23:40:59 +00004463 size = buf->use + len + 100;
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004464
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004465 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
Daniel Veillard496a1cf2000-05-03 14:20:55 +00004466 if (newbuf == NULL) return(-1);
4467 buf->content = newbuf;
4468 buf->size = size;
4469 return(buf->size - buf->use);
4470}
4471
4472/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004473 * xmlBufferDump:
4474 * @file: the file output
4475 * @buf: the buffer to dump
4476 *
4477 * Dumps an XML buffer to a FILE *.
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004478 * Returns the number of xmlChar written
Daniel Veillard5099ae81999-04-21 20:12:07 +00004479 */
4480int
4481xmlBufferDump(FILE *file, xmlBufferPtr buf) {
4482 int ret;
4483
4484 if (buf == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004485#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004486 xmlGenericError(xmlGenericErrorContext,
4487 "xmlBufferDump: buf == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004488#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004489 return(0);
4490 }
4491 if (buf->content == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004492#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004493 xmlGenericError(xmlGenericErrorContext,
4494 "xmlBufferDump: buf->content == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004495#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004496 return(0);
4497 }
4498 if (file == NULL) file = stdout;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004499 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004500 return(ret);
4501}
4502
4503/**
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004504 * xmlBufferContent:
4505 * @buf: the buffer to resize
4506 *
4507 * Returns the internal content
4508 */
4509
4510const xmlChar*
4511xmlBufferContent(const xmlBufferPtr buf)
4512{
4513 if(!buf)
4514 return NULL;
4515
4516 return buf->content;
4517}
4518
4519/**
4520 * xmlBufferLength:
4521 * @buf: the buffer
4522 *
4523 * Returns the length of data in the internal content
4524 */
4525
4526int
4527xmlBufferLength(const xmlBufferPtr buf)
4528{
4529 if(!buf)
4530 return 0;
4531
4532 return buf->use;
4533}
4534
4535/**
4536 * xmlBufferResize:
4537 * @buf: the buffer to resize
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004538 * @size: the desired size
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004539 *
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004540 * Resize a buffer to accomodate minimum size of @size.
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004541 *
4542 * Returns 0 in case of problems, 1 otherwise
4543 */
4544int
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004545xmlBufferResize(xmlBufferPtr buf, unsigned int size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004546{
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004547 unsigned int newSize;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004548 xmlChar* rebuf = NULL;
4549
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004550 /*take care of empty case*/
4551 newSize = (buf->size ? buf->size*2 : size);
4552
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004553 /* Don't resize if we don't have to */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004554 if (size < buf->size)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004555 return 1;
4556
4557 /* figure out new size */
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004558 switch (buf->alloc){
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004559 case XML_BUFFER_ALLOC_DOUBLEIT:
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004560 while (size > newSize) newSize *= 2;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004561 break;
4562 case XML_BUFFER_ALLOC_EXACT:
4563 newSize = size+10;
4564 break;
4565 default:
4566 newSize = size+10;
4567 break;
4568 }
4569
4570 if (buf->content == NULL)
4571 rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
4572 else
4573 rebuf = (xmlChar *) xmlRealloc(buf->content,
4574 newSize * sizeof(xmlChar));
4575 if (rebuf == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004576 xmlGenericError(xmlGenericErrorContext,
4577 "xmlBufferAdd : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004578 return 0;
4579 }
4580 buf->content = rebuf;
4581 buf->size = newSize;
4582
4583 return 1;
4584}
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004585
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004586/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004587 * xmlBufferAdd:
4588 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004589 * @str: the xmlChar string
4590 * @len: the number of xmlChar to add
Daniel Veillard5099ae81999-04-21 20:12:07 +00004591 *
Daniel Veillard10a2c651999-12-12 13:03:50 +00004592 * Add a string range to an XML buffer. if len == -1, the lenght of
4593 * str is recomputed.
Daniel Veillard5099ae81999-04-21 20:12:07 +00004594 */
4595void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004596xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004597 unsigned int needSize;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004598
4599 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004600#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004601 xmlGenericError(xmlGenericErrorContext,
4602 "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004603#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004604 return;
4605 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00004606 if (len < -1) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004607#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004608 xmlGenericError(xmlGenericErrorContext,
4609 "xmlBufferAdd: len < 0\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004610#endif
Daniel Veillard10a2c651999-12-12 13:03:50 +00004611 return;
4612 }
4613 if (len == 0) return;
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004614
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004615 if (len < 0)
Daniel Veillardcf461992000-03-14 18:30:20 +00004616 len = xmlStrlen(str);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004617
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004618 if (len <= 0) return;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004619
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004620 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004621 if (needSize > buf->size){
4622 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004623 xmlGenericError(xmlGenericErrorContext,
4624 "xmlBufferAdd : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004625 return;
4626 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004627 }
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004628
4629 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004630 buf->use += len;
4631 buf->content[buf->use] = 0;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004632}
4633
4634/**
Daniel Veillardbe803962000-06-28 23:40:59 +00004635 * xmlBufferAddHead:
4636 * @buf: the buffer
4637 * @str: the xmlChar string
4638 * @len: the number of xmlChar to add
4639 *
4640 * Add a string range to the beginning of an XML buffer.
4641 * if len == -1, the lenght of @str is recomputed.
4642 */
4643void
4644xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004645 unsigned int needSize;
Daniel Veillardbe803962000-06-28 23:40:59 +00004646
4647 if (str == NULL) {
4648#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004649 xmlGenericError(xmlGenericErrorContext,
4650 "xmlBufferAdd: str == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004651#endif
4652 return;
4653 }
4654 if (len < -1) {
4655#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004656 xmlGenericError(xmlGenericErrorContext,
4657 "xmlBufferAdd: len < 0\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004658#endif
4659 return;
4660 }
4661 if (len == 0) return;
4662
4663 if (len < 0)
4664 len = xmlStrlen(str);
4665
4666 if (len <= 0) return;
4667
4668 needSize = buf->use + len + 2;
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004669 if (needSize > buf->size){
4670 if (!xmlBufferResize(buf, needSize)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004671 xmlGenericError(xmlGenericErrorContext,
4672 "xmlBufferAddHead : out of memory!\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00004673 return;
4674 }
4675 }
4676
4677 memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
4678 memmove(&buf->content[0], str, len * sizeof(xmlChar));
4679 buf->use += len;
4680 buf->content[buf->use] = 0;
4681}
4682
4683/**
Daniel Veillard5099ae81999-04-21 20:12:07 +00004684 * xmlBufferCat:
4685 * @buf: the buffer to dump
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004686 * @str: the xmlChar string
Daniel Veillard5099ae81999-04-21 20:12:07 +00004687 *
4688 * Append a zero terminated string to an XML buffer.
4689 */
4690void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004691xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004692 if (str != NULL)
4693 xmlBufferAdd(buf, str, -1);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004694}
4695
4696/**
4697 * xmlBufferCCat:
4698 * @buf: the buffer to dump
4699 * @str: the C char string
4700 *
4701 * Append a zero terminated C string to an XML buffer.
4702 */
4703void
4704xmlBufferCCat(xmlBufferPtr buf, const char *str) {
4705 const char *cur;
4706
4707 if (str == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004708#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004709 xmlGenericError(xmlGenericErrorContext,
4710 "xmlBufferAdd: str == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004711#endif
Daniel Veillard5099ae81999-04-21 20:12:07 +00004712 return;
4713 }
4714 for (cur = str;*cur != 0;cur++) {
4715 if (buf->use + 10 >= buf->size) {
Daniel Veillard4b0755c2000-09-25 14:26:28 +00004716 if (!xmlBufferResize(buf, buf->use+10)){
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004717 xmlGenericError(xmlGenericErrorContext,
4718 "xmlBufferCCat : out of memory!\n");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00004719 return;
4720 }
4721 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004722 buf->content[buf->use++] = *cur;
4723 }
Daniel Veillard65c295d2001-01-26 09:32:39 +00004724 buf->content[buf->use] = 0;
Daniel Veillard5099ae81999-04-21 20:12:07 +00004725}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004726
Daniel Veillard97b58771998-10-20 06:14:16 +00004727/**
4728 * xmlBufferWriteCHAR:
Daniel Veillard5099ae81999-04-21 20:12:07 +00004729 * @buf: the XML buffer
Daniel Veillard97b58771998-10-20 06:14:16 +00004730 * @string: the string to add
4731 *
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004732 * routine which manages and grows an output buffer. This one adds
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004733 * xmlChars at the end of the buffer.
Daniel Veillard97b58771998-10-20 06:14:16 +00004734 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004735void
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004736#ifdef VMS
4737xmlBufferWriteXmlCHAR
4738#else
4739xmlBufferWriteCHAR
4740#endif
4741(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004742 xmlBufferCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004743}
4744
Daniel Veillard97b58771998-10-20 06:14:16 +00004745/**
4746 * xmlBufferWriteChar:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004747 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004748 * @string: the string to add
4749 *
4750 * routine which manage and grows an output buffer. This one add
4751 * C chars at the end of the array.
4752 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004753void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004754xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
4755 xmlBufferCCat(buf, string);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004756}
4757
Daniel Veillard5099ae81999-04-21 20:12:07 +00004758
Daniel Veillard97b58771998-10-20 06:14:16 +00004759/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004760 * xmlBufferWriteQuotedString:
4761 * @buf: the XML buffer output
4762 * @string: the string to add
4763 *
4764 * routine which manage and grows an output buffer. This one writes
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004765 * a quoted or double quoted xmlChar string, checking first if it holds
Daniel Veillard011b63c1999-06-02 17:44:04 +00004766 * quote or double-quotes internally
4767 */
4768void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004769xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004770 if (xmlStrchr(string, '"')) {
4771 if (xmlStrchr(string, '\'')) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004772#ifdef DEBUG_BUFFER
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004773 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard011b63c1999-06-02 17:44:04 +00004774 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004775#endif
Daniel Veillard011b63c1999-06-02 17:44:04 +00004776 }
4777 xmlBufferCCat(buf, "'");
4778 xmlBufferCat(buf, string);
4779 xmlBufferCCat(buf, "'");
4780 } else {
4781 xmlBufferCCat(buf, "\"");
4782 xmlBufferCat(buf, string);
4783 xmlBufferCCat(buf, "\"");
4784 }
4785}
4786
4787
Daniel Veillardbe803962000-06-28 23:40:59 +00004788/************************************************************************
4789 * *
4790 * Dumping XML tree content to a simple buffer *
4791 * *
4792 ************************************************************************/
4793
Daniel Veillardb656ebe2000-09-22 13:51:48 +00004794void
Daniel Veillardcf461992000-03-14 18:30:20 +00004795xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4796 int format);
4797static void
4798xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4799 int format);
4800void
4801htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
4802
Daniel Veillard011b63c1999-06-02 17:44:04 +00004803/**
Daniel Veillard97b58771998-10-20 06:14:16 +00004804 * xmlNsDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004805 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004806 * @cur: a namespace
4807 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004808 * Dump a local Namespace definition.
Daniel Veillard97b58771998-10-20 06:14:16 +00004809 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004810 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004811static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004812xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004813 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004814#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004815 xmlGenericError(xmlGenericErrorContext,
4816 "xmlNsDump : Ns == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004817#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004818 return;
4819 }
4820 if (cur->type == XML_LOCAL_NAMESPACE) {
4821 /* Within the context of an element attributes */
4822 if (cur->prefix != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004823 xmlBufferWriteChar(buf, " xmlns:");
4824 xmlBufferWriteCHAR(buf, cur->prefix);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004825 } else
Daniel Veillard5099ae81999-04-21 20:12:07 +00004826 xmlBufferWriteChar(buf, " xmlns");
Daniel Veillard011b63c1999-06-02 17:44:04 +00004827 xmlBufferWriteChar(buf, "=");
4828 xmlBufferWriteQuotedString(buf, cur->href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004829 }
4830}
4831
Daniel Veillard97b58771998-10-20 06:14:16 +00004832/**
4833 * xmlNsListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004834 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004835 * @cur: the first namespace
4836 *
4837 * Dump a list of local Namespace definitions.
4838 * Should be called in the context of attributes dumps.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004839 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004840static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004841xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004842 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004843 xmlNsDump(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004844 cur = cur->next;
4845 }
4846}
4847
Daniel Veillard97b58771998-10-20 06:14:16 +00004848/**
4849 * xmlDtdDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004850 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004851 * @doc: the document
4852 *
4853 * Dump the XML document DTD, if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004854 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004855static void
Daniel Veillardcf461992000-03-14 18:30:20 +00004856xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
4857 if (dtd == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004858#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004859 xmlGenericError(xmlGenericErrorContext,
4860 "xmlDtdDump : no internal subset\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004861#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004862 return;
4863 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004864 xmlBufferWriteChar(buf, "<!DOCTYPE ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004865 xmlBufferWriteCHAR(buf, dtd->name);
4866 if (dtd->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004867 xmlBufferWriteChar(buf, " PUBLIC ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004868 xmlBufferWriteQuotedString(buf, dtd->ExternalID);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004869 xmlBufferWriteChar(buf, " ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004870 xmlBufferWriteQuotedString(buf, dtd->SystemID);
4871 } else if (dtd->SystemID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004872 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillardcf461992000-03-14 18:30:20 +00004873 xmlBufferWriteQuotedString(buf, dtd->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004874 }
Daniel Veillardcf461992000-03-14 18:30:20 +00004875 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
4876 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
4877 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004878 return;
4879 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004880 xmlBufferWriteChar(buf, " [\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00004881 xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
4882#if 0
4883 if (dtd->entities != NULL)
4884 xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
4885 if (dtd->notations != NULL)
4886 xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
4887 if (dtd->elements != NULL)
4888 xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
4889 if (dtd->attributes != NULL)
4890 xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
4891#endif
4892 xmlBufferWriteChar(buf, "]>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004893}
4894
Daniel Veillard97b58771998-10-20 06:14:16 +00004895/**
4896 * xmlAttrDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004897 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004898 * @doc: the document
4899 * @cur: the attribute pointer
4900 *
4901 * Dump an XML attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00004902 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004903static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004904xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004905 xmlChar *value;
Daniel Veillardccb09631998-10-27 06:21:04 +00004906
Daniel Veillard260a68f1998-08-13 03:39:55 +00004907 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004908#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004909 xmlGenericError(xmlGenericErrorContext,
4910 "xmlAttrDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004911#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004912 return;
4913 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004914 xmlBufferWriteChar(buf, " ");
Daniel Veillardb96e6431999-08-29 21:02:19 +00004915 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4916 xmlBufferWriteCHAR(buf, cur->ns->prefix);
4917 xmlBufferWriteChar(buf, ":");
4918 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00004919 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +00004920 value = xmlNodeListGetString(doc, cur->children, 0);
Daniel Veillardf060a412001-01-03 20:52:44 +00004921 if (value != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004922 xmlBufferWriteChar(buf, "=");
4923 xmlBufferWriteQuotedString(buf, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004924 xmlFree(value);
Daniel Veillard726c7e31999-02-08 15:13:10 +00004925 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004926 xmlBufferWriteChar(buf, "=\"\"");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004927 }
4928}
4929
Daniel Veillard97b58771998-10-20 06:14:16 +00004930/**
4931 * xmlAttrListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004932 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004933 * @doc: the document
4934 * @cur: the first attribute pointer
4935 *
4936 * Dump a list of XML attributes
Daniel Veillard260a68f1998-08-13 03:39:55 +00004937 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004938static void
Daniel Veillard5099ae81999-04-21 20:12:07 +00004939xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004940 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004941#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004942 xmlGenericError(xmlGenericErrorContext,
4943 "xmlAttrListDump : property == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004944#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004945 return;
4946 }
4947 while (cur != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00004948 xmlAttrDump(buf, doc, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004949 cur = cur->next;
4950 }
4951}
4952
Daniel Veillard260a68f1998-08-13 03:39:55 +00004953
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004954
Daniel Veillard97b58771998-10-20 06:14:16 +00004955/**
4956 * xmlNodeListDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004957 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004958 * @doc: the document
4959 * @cur: the first node
Daniel Veillardcf461992000-03-14 18:30:20 +00004960 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004961 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004962 *
4963 * Dump an XML node list, recursive behaviour,children are printed too.
4964 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00004965static void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004966xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
4967 int format) {
4968 int i;
Daniel Veillardccb09631998-10-27 06:21:04 +00004969
Daniel Veillard260a68f1998-08-13 03:39:55 +00004970 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004971#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004972 xmlGenericError(xmlGenericErrorContext,
4973 "xmlNodeListDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00004974#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004975 return;
4976 }
4977 while (cur != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004978 if ((format) && (xmlIndentTreeOutput) &&
4979 (cur->type == XML_ELEMENT_NODE))
4980 for (i = 0;i < level;i++)
4981 xmlBufferWriteChar(buf, " ");
4982 xmlNodeDump(buf, doc, cur, level, format);
4983 if (format) {
4984 xmlBufferWriteChar(buf, "\n");
Daniel Veillardccb09631998-10-27 06:21:04 +00004985 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004986 cur = cur->next;
4987 }
4988}
4989
Daniel Veillard97b58771998-10-20 06:14:16 +00004990/**
Daniel Veillardccb09631998-10-27 06:21:04 +00004991 * xmlNodeDump:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004992 * @buf: the XML buffer output
Daniel Veillard97b58771998-10-20 06:14:16 +00004993 * @doc: the document
4994 * @cur: the current node
Daniel Veillardcf461992000-03-14 18:30:20 +00004995 * @level: the imbrication level for indenting
Daniel Veillard7d2c2761999-10-11 15:09:51 +00004996 * @format: is formatting allowed
Daniel Veillard97b58771998-10-20 06:14:16 +00004997 *
4998 * Dump an XML node, recursive behaviour,children are printed too.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004999 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005000void
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005001xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
5002 int format) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005003 int i;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005004 xmlNodePtr tmp;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005005
5006 if (cur == NULL) {
Daniel Veillardad8f99d2000-01-15 14:20:03 +00005007#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005008 xmlGenericError(xmlGenericErrorContext,
5009 "xmlNodeDump : node == NULL\n");
Daniel Veillardad8f99d2000-01-15 14:20:03 +00005010#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00005011 return;
5012 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00005013 if (cur->type == XML_XINCLUDE_START)
5014 return;
5015 if (cur->type == XML_XINCLUDE_END)
5016 return;
Daniel Veillardcf461992000-03-14 18:30:20 +00005017 if (cur->type == XML_DTD_NODE) {
5018 xmlDtdDump(buf, (xmlDtdPtr) cur);
5019 return;
5020 }
5021 if (cur->type == XML_ELEMENT_DECL) {
5022 xmlDumpElementDecl(buf, (xmlElementPtr) cur);
5023 return;
5024 }
5025 if (cur->type == XML_ATTRIBUTE_DECL) {
5026 xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
5027 return;
5028 }
5029 if (cur->type == XML_ENTITY_DECL) {
5030 xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
5031 return;
5032 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00005033 if (cur->type == XML_TEXT_NODE) {
Daniel Veillard14fff061999-06-22 21:49:07 +00005034 if (cur->content != NULL) {
Daniel Veillardf6eea272001-01-18 12:17:12 +00005035 if ((cur->name == xmlStringText) ||
5036 (cur->name != xmlStringTextNoenc)) {
5037 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00005038
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005039#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardf6eea272001-01-18 12:17:12 +00005040 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005041#else
Daniel Veillardf6eea272001-01-18 12:17:12 +00005042 buffer = xmlEncodeEntitiesReentrant(doc,
5043 xmlBufferContent(cur->content));
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005044#endif
Daniel Veillardf6eea272001-01-18 12:17:12 +00005045 if (buffer != NULL) {
5046 xmlBufferWriteCHAR(buf, buffer);
5047 xmlFree(buffer);
5048 }
5049 } else {
5050 /*
5051 * Disable escaping, needed for XSLT
5052 */
5053#ifndef XML_USE_BUFFER_CONTENT
5054 xmlBufferWriteCHAR(buf, cur->content);
5055#else
5056 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5057#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00005058 }
5059 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005060 return;
5061 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00005062 if (cur->type == XML_PI_NODE) {
5063 if (cur->content != NULL) {
5064 xmlBufferWriteChar(buf, "<?");
5065 xmlBufferWriteCHAR(buf, cur->name);
5066 if (cur->content != NULL) {
5067 xmlBufferWriteChar(buf, " ");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005068#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb96e6431999-08-29 21:02:19 +00005069 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005070#else
5071 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5072#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00005073 }
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005074 xmlBufferWriteChar(buf, "?>");
Daniel Veillardcf461992000-03-14 18:30:20 +00005075 } else {
5076 xmlBufferWriteChar(buf, "<?");
5077 xmlBufferWriteCHAR(buf, cur->name);
5078 xmlBufferWriteChar(buf, "?>");
Daniel Veillardb96e6431999-08-29 21:02:19 +00005079 }
5080 return;
5081 }
Daniel Veillard0bef1311998-10-14 02:36:47 +00005082 if (cur->type == XML_COMMENT_NODE) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005083 if (cur->content != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005084 xmlBufferWriteChar(buf, "<!--");
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005085#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard5099ae81999-04-21 20:12:07 +00005086 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005087#else
5088 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5089#endif
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005090 xmlBufferWriteChar(buf, "-->");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005091 }
5092 return;
5093 }
Daniel Veillardccb09631998-10-27 06:21:04 +00005094 if (cur->type == XML_ENTITY_REF_NODE) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005095 xmlBufferWriteChar(buf, "&");
5096 xmlBufferWriteCHAR(buf, cur->name);
5097 xmlBufferWriteChar(buf, ";");
Daniel Veillardccb09631998-10-27 06:21:04 +00005098 return;
5099 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00005100 if (cur->type == XML_CDATA_SECTION_NODE) {
5101 xmlBufferWriteChar(buf, "<![CDATA[");
5102 if (cur->content != NULL)
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005103#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardb05deb71999-08-10 19:04:08 +00005104 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005105#else
5106 xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
5107#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00005108 xmlBufferWriteChar(buf, "]]>");
5109 return;
5110 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005111
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005112 if (format == 1) {
Daniel Veillardcf461992000-03-14 18:30:20 +00005113 tmp = cur->children;
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005114 while (tmp != NULL) {
5115 if ((tmp->type == XML_TEXT_NODE) ||
5116 (tmp->type == XML_ENTITY_REF_NODE)) {
5117 format = 0;
5118 break;
5119 }
5120 tmp = tmp->next;
5121 }
5122 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005123 xmlBufferWriteChar(buf, "<");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005124 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005125 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5126 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005127 }
5128
Daniel Veillard5099ae81999-04-21 20:12:07 +00005129 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005130 if (cur->nsDef)
Daniel Veillard5099ae81999-04-21 20:12:07 +00005131 xmlNsListDump(buf, cur->nsDef);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005132 if (cur->properties != NULL)
Daniel Veillard5099ae81999-04-21 20:12:07 +00005133 xmlAttrListDump(buf, doc, cur->properties);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005134
Daniel Veillardcf461992000-03-14 18:30:20 +00005135 if ((cur->content == NULL) && (cur->children == NULL) &&
Daniel Veillarde41f2b72000-01-30 20:00:07 +00005136 (!xmlSaveNoEmptyTags)) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005137 xmlBufferWriteChar(buf, "/>");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005138 return;
5139 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005140 xmlBufferWriteChar(buf, ">");
Daniel Veillard14fff061999-06-22 21:49:07 +00005141 if (cur->content != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005142 xmlChar *buffer;
Daniel Veillard14fff061999-06-22 21:49:07 +00005143
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005144#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillard14fff061999-06-22 21:49:07 +00005145 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
Daniel Veillardf5c2c871999-12-01 09:51:45 +00005146#else
5147 buffer = xmlEncodeEntitiesReentrant(doc,
5148 xmlBufferContent(cur->content));
5149#endif
Daniel Veillard14fff061999-06-22 21:49:07 +00005150 if (buffer != NULL) {
5151 xmlBufferWriteCHAR(buf, buffer);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005152 xmlFree(buffer);
Daniel Veillard14fff061999-06-22 21:49:07 +00005153 }
5154 }
Daniel Veillardcf461992000-03-14 18:30:20 +00005155 if (cur->children != NULL) {
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005156 if (format) xmlBufferWriteChar(buf, "\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00005157 xmlNodeListDump(buf, doc, cur->children,
Daniel Veillard3e6d2372000-03-04 11:39:43 +00005158 (level >= 0?level+1:-1), format);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005159 if ((xmlIndentTreeOutput) && (format))
5160 for (i = 0;i < level;i++)
5161 xmlBufferWriteChar(buf, " ");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005162 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00005163 xmlBufferWriteChar(buf, "</");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005164 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00005165 xmlBufferWriteCHAR(buf, cur->ns->prefix);
5166 xmlBufferWriteChar(buf, ":");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005167 }
5168
Daniel Veillard5099ae81999-04-21 20:12:07 +00005169 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard7d2c2761999-10-11 15:09:51 +00005170 xmlBufferWriteChar(buf, ">");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005171}
5172
Daniel Veillard97b58771998-10-20 06:14:16 +00005173/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005174 * xmlElemDump:
Daniel Veillard06047432000-04-24 11:33:38 +00005175 * @f: the FILE * for the output
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005176 * @doc: the document
5177 * @cur: the current node
5178 *
5179 * Dump an XML/HTML node, recursive behaviour,children are printed too.
5180 */
5181void
5182xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
5183 xmlBufferPtr buf;
5184
5185 if (cur == NULL) {
5186#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005187 xmlGenericError(xmlGenericErrorContext,
5188 "xmlElemDump : cur == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005189#endif
5190 return;
5191 }
5192 if (doc == NULL) {
5193#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005194 xmlGenericError(xmlGenericErrorContext,
5195 "xmlElemDump : doc == NULL\n");
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005196#endif
5197 }
5198 buf = xmlBufferCreate();
5199 if (buf == NULL) return;
5200 if ((doc != NULL) &&
5201 (doc->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard361d8452000-04-03 19:48:13 +00005202#ifdef LIBXML_HTML_ENABLED
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005203 htmlNodeDump(buf, doc, cur);
Daniel Veillard361d8452000-04-03 19:48:13 +00005204#else
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005205 xmlGenericError(xmlGenericErrorContext,
5206 "HTML support not compiled in\n");
Daniel Veillard361d8452000-04-03 19:48:13 +00005207#endif /* LIBXML_HTML_ENABLED */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005208 } else
5209 xmlNodeDump(buf, doc, cur, 0, 1);
5210 xmlBufferDump(f, buf);
5211 xmlBufferFree(buf);
5212}
5213
Daniel Veillardbe803962000-06-28 23:40:59 +00005214/************************************************************************
5215 * *
5216 * Dumping XML tree content to an I/O output buffer *
5217 * *
5218 ************************************************************************/
5219
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005220void
Daniel Veillardbe803962000-06-28 23:40:59 +00005221xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5222 int level, int format, const char *encoding);
5223static void
5224xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5225 int level, int format, const char *encoding);
5226/**
Daniel Veillardbe803962000-06-28 23:40:59 +00005227 * xmlNsDumpOutput:
5228 * @buf: the XML buffer output
5229 * @cur: a namespace
5230 *
5231 * Dump a local Namespace definition.
5232 * Should be called in the context of attributes dumps.
5233 */
5234static void
5235xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5236 if (cur == NULL) {
5237#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005238 xmlGenericError(xmlGenericErrorContext,
5239 "xmlNsDump : Ns == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005240#endif
5241 return;
5242 }
Daniel Veillarde0854c32000-08-27 21:12:29 +00005243 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005244 /* Within the context of an element attributes */
5245 if (cur->prefix != NULL) {
5246 xmlOutputBufferWriteString(buf, " xmlns:");
5247 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
5248 } else
5249 xmlOutputBufferWriteString(buf, " xmlns");
5250 xmlOutputBufferWriteString(buf, "=");
5251 xmlBufferWriteQuotedString(buf->buffer, cur->href);
5252 }
5253}
5254
5255/**
5256 * xmlNsListDumpOutput:
5257 * @buf: the XML buffer output
5258 * @cur: the first namespace
5259 *
5260 * Dump a list of local Namespace definitions.
5261 * Should be called in the context of attributes dumps.
5262 */
5263static void
5264xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
5265 while (cur != NULL) {
5266 xmlNsDumpOutput(buf, cur);
5267 cur = cur->next;
5268 }
5269}
5270
5271/**
5272 * xmlDtdDumpOutput:
5273 * @buf: the XML buffer output
5274 * @doc: the document
5275 * @encoding: an optional encoding string
5276 *
5277 * Dump the XML document DTD, if any.
5278 */
5279static void
5280xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
5281 if (dtd == NULL) {
5282#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005283 xmlGenericError(xmlGenericErrorContext,
5284 "xmlDtdDump : no internal subset\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005285#endif
5286 return;
5287 }
5288 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
5289 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
5290 if (dtd->ExternalID != NULL) {
5291 xmlOutputBufferWriteString(buf, " PUBLIC ");
5292 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
5293 xmlOutputBufferWriteString(buf, " ");
5294 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5295 } else if (dtd->SystemID != NULL) {
5296 xmlOutputBufferWriteString(buf, " SYSTEM ");
5297 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
5298 }
5299 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
5300 (dtd->attributes == NULL) && (dtd->notations == NULL)) {
5301 xmlOutputBufferWriteString(buf, ">");
5302 return;
5303 }
5304 xmlOutputBufferWriteString(buf, " [\n");
5305 xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
Daniel Veillardbe803962000-06-28 23:40:59 +00005306 xmlOutputBufferWriteString(buf, "]>");
5307}
5308
5309/**
5310 * xmlAttrDumpOutput:
5311 * @buf: the XML buffer output
5312 * @doc: the document
5313 * @cur: the attribute pointer
5314 * @encoding: an optional encoding string
5315 *
5316 * Dump an XML attribute
5317 */
5318static void
5319xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
5320 const char *encoding) {
5321 xmlChar *value;
5322
5323 if (cur == NULL) {
5324#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005325 xmlGenericError(xmlGenericErrorContext,
5326 "xmlAttrDump : property == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005327#endif
5328 return;
5329 }
5330 xmlOutputBufferWriteString(buf, " ");
5331 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5332 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5333 xmlOutputBufferWriteString(buf, ":");
5334 }
5335 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5336 value = xmlNodeListGetString(doc, cur->children, 0);
5337 if (value) {
5338 xmlOutputBufferWriteString(buf, "=");
5339 xmlBufferWriteQuotedString(buf->buffer, value);
5340 xmlFree(value);
5341 } else {
5342 xmlOutputBufferWriteString(buf, "=\"\"");
5343 }
5344}
5345
5346/**
5347 * xmlAttrListDumpOutput:
5348 * @buf: the XML buffer output
5349 * @doc: the document
5350 * @cur: the first attribute pointer
5351 * @encoding: an optional encoding string
5352 *
5353 * Dump a list of XML attributes
5354 */
5355static void
5356xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5357 xmlAttrPtr cur, const char *encoding) {
5358 if (cur == NULL) {
5359#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005360 xmlGenericError(xmlGenericErrorContext,
5361 "xmlAttrListDump : property == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005362#endif
5363 return;
5364 }
5365 while (cur != NULL) {
5366 xmlAttrDumpOutput(buf, doc, cur, encoding);
5367 cur = cur->next;
5368 }
5369}
5370
5371
5372
5373/**
5374 * xmlNodeListDumpOutput:
5375 * @buf: the XML buffer output
5376 * @doc: the document
5377 * @cur: the first node
5378 * @level: the imbrication level for indenting
5379 * @format: is formatting allowed
5380 * @encoding: an optional encoding string
5381 *
5382 * Dump an XML node list, recursive behaviour,children are printed too.
5383 */
5384static void
5385xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
5386 xmlNodePtr cur, int level, int format, const char *encoding) {
5387 int i;
5388
5389 if (cur == NULL) {
5390#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005391 xmlGenericError(xmlGenericErrorContext,
5392 "xmlNodeListDump : node == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005393#endif
5394 return;
5395 }
5396 while (cur != NULL) {
5397 if ((format) && (xmlIndentTreeOutput) &&
5398 (cur->type == XML_ELEMENT_NODE))
5399 for (i = 0;i < level;i++)
5400 xmlOutputBufferWriteString(buf, " ");
5401 xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
5402 if (format) {
5403 xmlOutputBufferWriteString(buf, "\n");
5404 }
5405 cur = cur->next;
5406 }
5407}
5408
5409/**
5410 * xmlNodeDumpOutput:
5411 * @buf: the XML buffer output
5412 * @doc: the document
5413 * @cur: the current node
5414 * @level: the imbrication level for indenting
5415 * @format: is formatting allowed
5416 * @encoding: an optional encoding string
5417 *
5418 * Dump an XML node, recursive behaviour,children are printed too.
5419 */
Daniel Veillardb656ebe2000-09-22 13:51:48 +00005420void
Daniel Veillardbe803962000-06-28 23:40:59 +00005421xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
5422 int level, int format, const char *encoding) {
5423 int i;
5424 xmlNodePtr tmp;
5425
5426 if (cur == NULL) {
5427#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005428 xmlGenericError(xmlGenericErrorContext,
5429 "xmlNodeDump : node == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005430#endif
5431 return;
5432 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00005433 if (cur->type == XML_XINCLUDE_START)
5434 return;
5435 if (cur->type == XML_XINCLUDE_END)
5436 return;
Daniel Veillardbe803962000-06-28 23:40:59 +00005437 if (cur->type == XML_DTD_NODE) {
5438 xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
5439 return;
5440 }
5441 if (cur->type == XML_ELEMENT_DECL) {
5442 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
5443 return;
5444 }
5445 if (cur->type == XML_ATTRIBUTE_DECL) {
5446 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
5447 return;
5448 }
5449 if (cur->type == XML_ENTITY_DECL) {
5450 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
5451 return;
5452 }
5453 if (cur->type == XML_TEXT_NODE) {
5454 if (cur->content != NULL) {
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005455 if ((cur->name == xmlStringText) ||
5456 (cur->name != xmlStringTextNoenc)) {
5457 xmlChar *buffer;
Daniel Veillardbe803962000-06-28 23:40:59 +00005458
5459#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005460 if (encoding == NULL)
5461 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5462 else
5463 buffer = xmlEncodeSpecialChars(doc, cur->content);
Daniel Veillardbe803962000-06-28 23:40:59 +00005464#else
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005465 if (encoding == NULL)
5466 buffer = xmlEncodeEntitiesReentrant(doc,
5467 xmlBufferContent(cur->content));
5468 else
5469 buffer = xmlEncodeSpecialChars(doc,
5470 xmlBufferContent(cur->content));
Daniel Veillardbe803962000-06-28 23:40:59 +00005471#endif
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005472 if (buffer != NULL) {
5473 xmlOutputBufferWriteString(buf, (const char *)buffer);
5474 xmlFree(buffer);
5475 }
5476 } else {
5477 /*
5478 * Disable escaping, needed for XSLT
5479 */
5480#ifndef XML_USE_BUFFER_CONTENT
Daniel Veillarde4566462001-01-22 09:58:39 +00005481 xmlOutputBufferWriteString(buf, (const char *) cur->content);
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005482#else
5483 xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
5484#endif
Daniel Veillardbe803962000-06-28 23:40:59 +00005485 }
5486 }
Daniel Veillardcb126ac2001-01-18 12:50:20 +00005487
Daniel Veillardbe803962000-06-28 23:40:59 +00005488 return;
5489 }
5490 if (cur->type == XML_PI_NODE) {
5491 if (cur->content != NULL) {
5492 xmlOutputBufferWriteString(buf, "<?");
5493 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5494 if (cur->content != NULL) {
5495 xmlOutputBufferWriteString(buf, " ");
5496#ifndef XML_USE_BUFFER_CONTENT
5497 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5498#else
5499 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5500#endif
5501 }
5502 xmlOutputBufferWriteString(buf, "?>");
5503 } else {
5504 xmlOutputBufferWriteString(buf, "<?");
5505 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5506 xmlOutputBufferWriteString(buf, "?>");
5507 }
5508 return;
5509 }
5510 if (cur->type == XML_COMMENT_NODE) {
5511 if (cur->content != NULL) {
5512 xmlOutputBufferWriteString(buf, "<!--");
5513#ifndef XML_USE_BUFFER_CONTENT
5514 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5515#else
5516 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5517#endif
5518 xmlOutputBufferWriteString(buf, "-->");
5519 }
5520 return;
5521 }
5522 if (cur->type == XML_ENTITY_REF_NODE) {
5523 xmlOutputBufferWriteString(buf, "&");
5524 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5525 xmlOutputBufferWriteString(buf, ";");
5526 return;
5527 }
5528 if (cur->type == XML_CDATA_SECTION_NODE) {
5529 xmlOutputBufferWriteString(buf, "<![CDATA[");
5530 if (cur->content != NULL)
5531#ifndef XML_USE_BUFFER_CONTENT
5532 xmlOutputBufferWriteString(buf, (const char *)cur->content);
5533#else
5534 xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
5535#endif
5536 xmlOutputBufferWriteString(buf, "]]>");
5537 return;
5538 }
5539
5540 if (format == 1) {
5541 tmp = cur->children;
5542 while (tmp != NULL) {
5543 if ((tmp->type == XML_TEXT_NODE) ||
5544 (tmp->type == XML_ENTITY_REF_NODE)) {
5545 format = 0;
5546 break;
5547 }
5548 tmp = tmp->next;
5549 }
5550 }
5551 xmlOutputBufferWriteString(buf, "<");
5552 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5553 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5554 xmlOutputBufferWriteString(buf, ":");
5555 }
5556
5557 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5558 if (cur->nsDef)
5559 xmlNsListDumpOutput(buf, cur->nsDef);
5560 if (cur->properties != NULL)
5561 xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
5562
5563 if ((cur->content == NULL) && (cur->children == NULL) &&
5564 (!xmlSaveNoEmptyTags)) {
5565 xmlOutputBufferWriteString(buf, "/>");
5566 return;
5567 }
5568 xmlOutputBufferWriteString(buf, ">");
5569 if (cur->content != NULL) {
5570 xmlChar *buffer;
5571
5572#ifndef XML_USE_BUFFER_CONTENT
5573 if (encoding == NULL)
5574 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
5575 else
5576 buffer = xmlEncodeSpecialChars(doc, cur->content);
5577#else
5578 if (encoding == NULL)
5579 buffer = xmlEncodeEntitiesReentrant(doc,
5580 xmlBufferContent(cur->content));
5581 else
5582 buffer = xmlEncodeSpecialChars(doc,
5583 xmlBufferContent(cur->content));
5584#endif
5585 if (buffer != NULL) {
5586 xmlOutputBufferWriteString(buf, (const char *)buffer);
5587 xmlFree(buffer);
5588 }
5589 }
5590 if (cur->children != NULL) {
5591 if (format) xmlOutputBufferWriteString(buf, "\n");
5592 xmlNodeListDumpOutput(buf, doc, cur->children,
5593 (level >= 0?level+1:-1), format, encoding);
5594 if ((xmlIndentTreeOutput) && (format))
5595 for (i = 0;i < level;i++)
5596 xmlOutputBufferWriteString(buf, " ");
5597 }
5598 xmlOutputBufferWriteString(buf, "</");
5599 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5600 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
5601 xmlOutputBufferWriteString(buf, ":");
5602 }
5603
5604 xmlOutputBufferWriteString(buf, (const char *)cur->name);
5605 xmlOutputBufferWriteString(buf, ">");
5606}
5607
5608/**
5609 * xmlDocContentDumpOutput:
5610 * @buf: the XML buffer output
5611 * @cur: the document
5612 * @encoding: an optional encoding string
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005613 * @format: should formatting spaces been added
Daniel Veillardbe803962000-06-28 23:40:59 +00005614 *
5615 * Dump an XML document.
5616 */
5617static void
5618xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005619 const char *encoding, int format) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005620 xmlOutputBufferWriteString(buf, "<?xml version=");
5621 if (cur->version != NULL)
5622 xmlBufferWriteQuotedString(buf->buffer, cur->version);
5623 else
5624 xmlOutputBufferWriteString(buf, "\"1.0\"");
5625 if (encoding == NULL) {
5626 if (cur->encoding != NULL)
5627 encoding = (const char *) cur->encoding;
5628 else if (cur->charset != XML_CHAR_ENCODING_UTF8)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005629 encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
Daniel Veillardbe803962000-06-28 23:40:59 +00005630 }
5631 if (encoding != NULL) {
5632 xmlOutputBufferWriteString(buf, " encoding=");
5633 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
5634 }
5635 switch (cur->standalone) {
5636 case 0:
5637 xmlOutputBufferWriteString(buf, " standalone=\"no\"");
5638 break;
5639 case 1:
5640 xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
5641 break;
5642 }
5643 xmlOutputBufferWriteString(buf, "?>\n");
5644 if (cur->children != NULL) {
5645 xmlNodePtr child = cur->children;
5646
Daniel Veillardbe803962000-06-28 23:40:59 +00005647 while (child != NULL) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005648 xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
Daniel Veillardbe803962000-06-28 23:40:59 +00005649 xmlOutputBufferWriteString(buf, "\n");
5650 child = child->next;
5651 }
5652 }
5653}
5654
5655/************************************************************************
5656 * *
5657 * Saving functions front-ends *
5658 * *
5659 ************************************************************************/
5660
Daniel Veillard97b58771998-10-20 06:14:16 +00005661/**
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005662 * xmlDocDumpMemoryEnc:
5663 * @out_doc: Document to generate XML text from
5664 * @doc_txt_ptr: Memory pointer for allocated XML text
5665 * @doc_txt_len: Length of the generated XML text
5666 * @txt_encoding: Character encoding to use when generating XML text
5667 * @format: should formatting spaces been added
5668 *
5669 * Dump the current DOM tree into memory using the character encoding specified
5670 * by the caller. Note it is up to the caller of this function to free the
5671 * allocated memory.
5672 */
5673
5674void
5675xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5676 int * doc_txt_len, const char * txt_encoding, int format) {
5677 int dummy = 0;
5678
5679 xmlCharEncoding doc_charset;
5680 xmlOutputBufferPtr out_buff = NULL;
5681 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
5682
5683 if (doc_txt_len == NULL) {
5684 doc_txt_len = &dummy; /* Continue, caller just won't get length */
5685 }
5686
5687 if (doc_txt_ptr == NULL) {
5688 *doc_txt_len = 0;
5689 xmlGenericError(xmlGenericErrorContext,
5690 "xmlDocDumpFormatMemoryEnc: Null return buffer pointer.");
5691 return;
5692 }
5693
5694 *doc_txt_ptr = NULL;
5695 *doc_txt_len = 0;
5696
5697 if (out_doc == NULL) {
5698 /* No document, no output */
5699 xmlGenericError(xmlGenericErrorContext,
5700 "xmlDocDumpFormatMemoryEnc: Null DOM tree document pointer.\n");
5701 return;
5702 }
5703
5704 /*
5705 * Validate the encoding value, if provided.
5706 * This logic is copied from xmlSaveFileEnc.
5707 */
5708
5709 if (txt_encoding == NULL)
5710 txt_encoding = (const char *) out_doc->encoding;
5711 if (txt_encoding != NULL) {
5712 doc_charset = xmlParseCharEncoding(txt_encoding);
5713
5714 if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
5715 xmlGenericError(xmlGenericErrorContext,
5716 "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
5717 return;
5718
5719 } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
5720 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
5721 if ( conv_hdlr == NULL ) {
5722 xmlGenericError(xmlGenericErrorContext,
5723 "%s: %s %s '%s'\n",
5724 "xmlDocDumpFormatMemoryEnc",
5725 "Failed to identify encoding handler for",
5726 "character set",
5727 txt_encoding);
5728 return;
5729 }
5730 }
5731 }
5732
5733 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
5734 xmlGenericError(xmlGenericErrorContext,
5735 "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
5736 return;
5737 }
5738
5739 xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, 1);
5740 xmlOutputBufferFlush(out_buff);
5741 if (out_buff->conv != NULL) {
5742 *doc_txt_len = out_buff->conv->use;
5743 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
5744 } else {
5745 *doc_txt_len = out_buff->buffer->use;
5746 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
5747 }
5748 (void)xmlOutputBufferClose(out_buff);
5749
5750 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
5751 *doc_txt_len = 0;
5752 xmlGenericError(xmlGenericErrorContext,
5753 "xmlDocDumpFormatMemoryEnc: %s\n",
5754 "Failed to allocate memory for document text representation.");
5755 }
5756
5757 return;
5758}
5759
5760/**
Daniel Veillard97b58771998-10-20 06:14:16 +00005761 * xmlDocDumpMemory:
5762 * @cur: the document
5763 * @mem: OUT: the memory pointer
5764 * @size: OUT: the memory lenght
5765 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005766 * Dump an XML document in memory and return the xmlChar * and it's size.
Daniel Veillard97b58771998-10-20 06:14:16 +00005767 * It's up to the caller to free the memory.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005768 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005769void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005770xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005771 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
5772}
Daniel Veillard5099ae81999-04-21 20:12:07 +00005773
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005774/**
5775 * xmlDocDumpFormatMemory:
5776 * @cur: the document
5777 * @mem: OUT: the memory pointer
5778 * @size: OUT: the memory lenght
5779 * @format: should formatting spaces been added
5780 *
5781 *
5782 * Dump an XML document in memory and return the xmlChar * and it's size.
5783 * It's up to the caller to free the memory.
5784 */
5785void
5786xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
5787 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005788}
5789
Daniel Veillard97b58771998-10-20 06:14:16 +00005790/**
Daniel Veillard58770e72000-11-25 00:48:47 +00005791 * xmlDocDumpMemoryEnc:
5792 * @out_doc: Document to generate XML text from
5793 * @doc_txt_ptr: Memory pointer for allocated XML text
5794 * @doc_txt_len: Length of the generated XML text
5795 * @txt_encoding: Character encoding to use when generating XML text
5796 *
5797 * Dump the current DOM tree into memory using the character encoding specified
5798 * by the caller. Note it is up to the caller of this function to free the
5799 * allocated memory.
5800 */
5801
5802void
5803xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
5804 int * doc_txt_len, const char * txt_encoding) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005805 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
5806 txt_encoding, 1);
Daniel Veillard58770e72000-11-25 00:48:47 +00005807}
5808
5809/**
Daniel Veillard97b58771998-10-20 06:14:16 +00005810 * xmlGetDocCompressMode:
5811 * @doc: the document
5812 *
5813 * get the compression ratio for a document, ZLIB based
Daniel Veillard1e346af1999-02-22 10:33:01 +00005814 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard151b1b01998-09-23 00:49:46 +00005815 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005816int
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005817xmlGetDocCompressMode (xmlDocPtr doc) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005818 if (doc == NULL) return(-1);
5819 return(doc->compression);
5820}
5821
Daniel Veillard97b58771998-10-20 06:14:16 +00005822/**
5823 * xmlSetDocCompressMode:
5824 * @doc: the document
5825 * @mode: the compression ratio
5826 *
5827 * set the compression ratio for a document, ZLIB based
5828 * Correct values: 0 (uncompressed) to 9 (max compression)
5829 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005830void
5831xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
Daniel Veillard15a8df41998-09-24 19:15:06 +00005832 if (doc == NULL) return;
5833 if (mode < 0) doc->compression = 0;
5834 else if (mode > 9) doc->compression = 9;
5835 else doc->compression = mode;
5836}
5837
Daniel Veillard97b58771998-10-20 06:14:16 +00005838/**
5839 * xmlGetCompressMode:
5840 *
5841 * get the default compression mode used, ZLIB based.
Daniel Veillard1e346af1999-02-22 10:33:01 +00005842 * Returns 0 (uncompressed) to 9 (max compression)
Daniel Veillard15a8df41998-09-24 19:15:06 +00005843 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005844int
5845 xmlGetCompressMode(void) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005846 return(xmlCompressMode);
5847}
Daniel Veillard97b58771998-10-20 06:14:16 +00005848
5849/**
5850 * xmlSetCompressMode:
5851 * @mode: the compression ratio
5852 *
5853 * set the default compression mode used, ZLIB based
5854 * Correct values: 0 (uncompressed) to 9 (max compression)
5855 */
Daniel Veillardbaf4cd51998-10-27 22:56:57 +00005856void
5857xmlSetCompressMode(int mode) {
Daniel Veillard151b1b01998-09-23 00:49:46 +00005858 if (mode < 0) xmlCompressMode = 0;
Daniel Veillard15a8df41998-09-24 19:15:06 +00005859 else if (mode > 9) xmlCompressMode = 9;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005860 else xmlCompressMode = mode;
5861}
5862
Daniel Veillardbe803962000-06-28 23:40:59 +00005863/**
5864 * xmlDocDump:
5865 * @f: the FILE*
5866 * @cur: the document
5867 *
5868 * Dump an XML document to an open FILE.
5869 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005870 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005871 */
5872int
5873xmlDocDump(FILE *f, xmlDocPtr cur) {
5874 xmlOutputBufferPtr buf;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005875 const char * encoding;
5876 xmlCharEncodingHandlerPtr handler = NULL;
Daniel Veillardbe803962000-06-28 23:40:59 +00005877 int ret;
Daniel Veillard151b1b01998-09-23 00:49:46 +00005878
Daniel Veillardbe803962000-06-28 23:40:59 +00005879 if (cur == NULL) {
5880#ifdef DEBUG_TREE
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005881 xmlGenericError(xmlGenericErrorContext,
5882 "xmlDocDump : document == NULL\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00005883#endif
5884 return(-1);
5885 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005886 encoding = (const char *) cur->encoding;
5887
5888 if (encoding != NULL) {
5889 xmlCharEncoding enc;
5890
5891 enc = xmlParseCharEncoding(encoding);
5892
5893 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005894 xmlGenericError(xmlGenericErrorContext,
5895 "xmlDocDump: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005896 return(-1);
5897 }
5898 if (enc != XML_CHAR_ENCODING_UTF8) {
5899 handler = xmlFindCharEncodingHandler(encoding);
5900 if (handler == NULL) {
5901 xmlFree((char *) cur->encoding);
5902 cur->encoding = NULL;
5903 }
5904 }
5905 }
5906 buf = xmlOutputBufferCreateFile(f, handler);
Daniel Veillardbe803962000-06-28 23:40:59 +00005907 if (buf == NULL) return(-1);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005908 xmlDocContentDumpOutput(buf, cur, NULL, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005909
5910 ret = xmlOutputBufferClose(buf);
5911 return(ret);
5912}
5913
5914/**
Daniel Veillardbe803962000-06-28 23:40:59 +00005915 * xmlSaveFileTo:
5916 * @buf: an output I/O buffer
5917 * @cur: the document
5918 * @encoding: the encoding if any assuming the i/O layer handles the trancoding
5919 *
5920 * Dump an XML document to an I/O buffer.
5921 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005922 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005923 */
5924int
5925xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
5926 int ret;
5927
5928 if (buf == NULL) return(0);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005929 xmlDocContentDumpOutput(buf, cur, encoding, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005930 ret = xmlOutputBufferClose(buf);
5931 return(ret);
5932}
5933
5934/**
5935 * xmlSaveFileEnc:
5936 * @filename: the filename (or URL)
5937 * @cur: the document
5938 * @encoding: the name of an encoding (or NULL)
5939 *
5940 * Dump an XML document, converting it to the given encoding
5941 *
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005942 * returns: the number of byte written or -1 in case of failure.
Daniel Veillardbe803962000-06-28 23:40:59 +00005943 */
5944int
5945xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
5946 xmlOutputBufferPtr buf;
5947 xmlCharEncodingHandlerPtr handler = NULL;
5948 int ret;
5949
5950 if (encoding != NULL) {
5951 xmlCharEncoding enc;
5952
5953 enc = xmlParseCharEncoding(encoding);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005954 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005955 xmlGenericError(xmlGenericErrorContext,
5956 "xmlSaveFileEnc: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005957 return(-1);
5958 }
5959 if (enc != XML_CHAR_ENCODING_UTF8) {
5960 handler = xmlFindCharEncodingHandler(encoding);
5961 if (handler == NULL) {
Daniel Veillardbe803962000-06-28 23:40:59 +00005962 return(-1);
5963 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005964 }
5965 }
5966
5967 /*
5968 * save the content to a temp buffer.
5969 */
5970 buf = xmlOutputBufferCreateFilename(filename, handler, 0);
Daniel Veillardf831bfb2001-01-16 17:26:04 +00005971 if (buf == NULL) return(-1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005972
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005973 xmlDocContentDumpOutput(buf, cur, encoding, 1);
Daniel Veillardbe803962000-06-28 23:40:59 +00005974
5975 ret = xmlOutputBufferClose(buf);
5976 return(ret);
5977}
Daniel Veillard32bc74e2000-07-14 14:49:25 +00005978
5979/**
5980 * xmlSaveFile:
5981 * @filename: the filename (or URL)
5982 * @cur: the document
5983 *
5984 * Dump an XML document to a file. Will use compression if
5985 * compiled in and enabled. If @filename is "-" the stdout file is
5986 * used.
5987 * returns: the number of byte written or -1 in case of failure.
5988 */
5989int
5990xmlSaveFile(const char *filename, xmlDocPtr cur) {
5991 xmlOutputBufferPtr buf;
5992 const char *encoding;
5993 xmlCharEncodingHandlerPtr handler = NULL;
5994 int ret;
5995
5996 if (cur == NULL)
5997 return(-1);
5998 encoding = (const char *) cur->encoding;
5999
6000 /*
6001 * save the content to a temp buffer.
6002 */
6003#ifdef HAVE_ZLIB_H
6004 if (cur->compression < 0) cur->compression = xmlCompressMode;
Daniel Veillardbe803962000-06-28 23:40:59 +00006005#endif
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006006 if (encoding != NULL) {
6007 xmlCharEncoding enc;
6008
6009 enc = xmlParseCharEncoding(encoding);
6010
6011 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006012 xmlGenericError(xmlGenericErrorContext,
6013 "xmlSaveFile: document not in UTF8\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006014 return(-1);
6015 }
6016 if (enc != XML_CHAR_ENCODING_UTF8) {
6017 handler = xmlFindCharEncodingHandler(encoding);
6018 if (handler == NULL) {
6019 xmlFree((char *) cur->encoding);
6020 cur->encoding = NULL;
6021 }
6022 }
6023 }
6024
6025 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
Daniel Veillard0cede082001-01-17 08:23:04 +00006026 if (buf == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006027
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00006028 xmlDocContentDumpOutput(buf, cur, NULL, 1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00006029
6030 ret = xmlOutputBufferClose(buf);
6031 return(ret);
6032}
6033